]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/javascript/util/RemoteRequest.js
added some permission exception handling..
[Evergreen.git] / Open-ILS / src / javascript / util / RemoteRequest.js
1
2 var XML_HTTP_GATEWAY = "gateway";
3 var XML_HTTP_SERVER = "gapines.org";
4 var XML_HTTP_MAX_TRIES = 3;
5
6
7
8 /* true if we've been absorbed by a XUL app */
9 function isXUL() {
10         try {
11                 if(IAMXUL)
12                         return true;
13         } catch(E) {
14                 return false;
15         }
16 }
17
18
19 /* ----------------------------------------------------------------------- */
20 /* class methods */
21
22 /* keeping all requests in a global cache allows us to manage request
23         resends effectively */
24
25 /* Array of globally pending requests */
26 RemoteRequest.pending = new Array();
27
28 /* cleans requests (and null entries) from the pending array */
29 RemoteRequest.prunePending = function(id) {
30         var tmpArray = new Array();
31         for( var x in RemoteRequest.pending ) {
32                 if( RemoteRequest.pending[x] != null ) {
33                         if( RemoteRequest.pending[x].id != id )
34                                 tmpArray.push(RemoteRequest.pending[x]);
35                 }
36         }
37         RemoteRequest.pending = tmpArray;
38 }
39
40 /* returns the number of pending requests */
41 RemoteRequest.numPending = function() {
42         return RemoteRequest.pending.length;
43 }
44
45 RemoteRequest.cancelAll = function() {
46         for( var x in RemoteRequest.pending ) {
47                 if( RemoteRequest.pending[x] != null ) {
48                         debug("Cancelling request...");
49                         RemoteRequest.pending[x].cancelled = true;
50                 }
51         }
52 }
53
54
55 /* ----------------------------------------------------------------------- */
56 /* Generic request manager */
57 function RequestBatch() {
58         this.requests = new Array();
59 }
60 RequestBatch.prototype.add = function(request) {
61         this.requests.push(request);
62 }
63
64 RequestBatch.prototype.remove = function(request) {
65         var newArray = new Array();
66         for( var i in this.requests ) {
67                 if( this.requests[i] != null &&
68                         this.requests[i].id != request.id )
69                         newArray.push(this.requests[i]);
70         }
71         this.requests = newArray;
72 }
73
74 RequestBatch.prototype.pending = function() {
75         return this.requests.length;
76 }
77
78 /* cancels all requests in this batch that have not already been sent */
79 RequestBatch.prototype.cancel = function() {
80         for(var i in this.requests) {
81                 if(this.requests[i] != null)
82                         this.requests.cancelled = true;
83         }
84 }
85
86 /* ----------------------------------------------------------------------- */
87 /* Request object */
88 function RemoteRequest( service, method ) {
89
90         this.service    = service;
91         this.method             = method;
92         this.xmlhttp    = false;
93         this.name               = null;
94         this.sendCount = 0;
95
96         this.type               = "POST"; /* default */
97         this.id                 = service + method + Math.random();
98         this.cancelled = false;
99
100         var i = 2;
101         this.params = ""; 
102
103         while(i < arguments.length) {
104                 var object = js2JSON(arguments[i++]);
105                 this.params += "&__param=" + encodeURIComponent(object);
106         }
107
108         if(!this.params) { this.params = ""; }
109         this.param_string = "service=" + service + "&method=" + method + this.params;
110
111         if( ! this.type || ! this.service || ! this.method ) {
112                 alert( "ERROR IN REQUEST PARAMS");
113                 return null;
114         }
115
116         if( this.buildXMLRequest() == null )
117                 alert("NEWER BROWSER");
118 }
119
120 /* constructs our XMLHTTPRequest object */
121 RemoteRequest.prototype.buildXMLRequest = function() {
122
123         try { 
124                 this.xmlhttp = new ActiveXObject("Msxml2.XMLHTTP"); 
125         } catch (e) {
126                 try { 
127                         this.xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); 
128                 } catch (E) {
129                         this.xmlhttp = false;
130                 }
131         }
132
133         if (!this.xmlhttp && typeof XMLHttpRequest!='undefined') {
134                 this.xmlhttp = new XMLHttpRequest();
135         }
136
137         if(!this.xmlhttp) {
138                 alert("NEEDS NEWER JAVASCRIPT for XMLHTTPRequest()");
139                 return null;
140         }
141
142         if( this.callback )
143                 this.setCompleteCallback( this.callback );
144
145         return true;
146 }
147
148
149 /* define the callback we use when this request has received
150         all of its data */
151 RemoteRequest.prototype.setCompleteCallback = function(callback) {
152
153         if(this.cancelled) return;
154
155         var object = this;
156         var obj = this.xmlhttp;
157         this.callback = callback;
158
159         this.xmlhttp.onreadystatechange = function() {
160                 if( obj.readyState == 4 ) {
161
162                         try {
163                                 if(object.cancelled) return;
164                                 callback(object);
165
166                         } catch(E) {
167
168                                 debug("Processing Error in complete callback: [" + E + "]");
169
170                                 /* if we receive a communication error, retry the request up
171                                         to XML_HTTP_MAX_TRIES attempts */
172                                 if( instanceOf(E, EXCommunication) ) {
173
174                                         debug("Communication Error: [" + E + "]");
175                                         if(object.sendCount >= XML_HTTP_MAX_TRIES ) {
176                                                 if(isXUL()) {
177                                                         throw object;
178                                                 } else {
179                                                         alert("Arrrgghh, Matey! Error communicating:\n" +
180                                                                  E  + "\n" + object.param_string);
181                                                 }
182                                         } else {
183                                                 object.buildXMLRequest();
184                                                 object.send();
185                                                 return;
186                                         }
187                                 } else {
188                                         /* any other exception is alerted for now */
189                                         RemoteRequest.prunePending(object.id);
190                                         //alert("Exception: " + E);
191                                         throw E;
192                                 }
193                         }
194
195                         /* on success, remove the request from the pending cache */
196                         RemoteRequest.prunePending(object.id);
197                 }
198         }
199 }
200
201
202 /* http by default.  This makes it https. *ONLY works when
203         embedded in a XUL app. */
204 RemoteRequest.prototype.setSecure = function(bool) {
205         this.secure = bool; 
206 }
207
208 /** Send the request 
209   * By default, all calls are asynchronous.  if 'blocking' is
210   * set to true, then the call will block until a response
211   * is received.  If blocking, callbacks will not be called.
212   * In other words, you can assume the data is avaiable 
213   * (getResponseObject()) as soon as the send call returns. 
214   */
215 RemoteRequest.prototype.send = function(blocking) {
216
217         if(this.cancelled) return;
218
219         if( this.sendCount == 0)
220                 RemoteRequest.pending.push(this);
221         else 
222                 debug("Resending request with id " + this.id 
223                                 + " and send count " + this.sendCount);
224         
225         /* determine the xmlhttp server dynamically */
226         var url = location.protocol + "//" + location.host + "/" + XML_HTTP_GATEWAY;
227
228         if(isXUL()) {
229                 if(this.secure)
230                         url =   "https://" + XML_HTTP_SERVER + "/" + XML_HTTP_GATEWAY;
231                 else
232                         //url = "http://" + XML_HTTP_SERVER + ":8080/" + XML_HTTP_GATEWAY;
233                         url =   "http://" + XML_HTTP_SERVER + "/" + XML_HTTP_GATEWAY;
234         }
235
236         var data = null;
237
238         if( this.type == 'GET' ) { 
239                 url +=  "?" + this.param_string; 
240         }
241
242         if(blocking) {
243                 this.xmlhttp.open(this.type, url, false);
244         } else {
245                 this.xmlhttp.open(this.type, url, true);
246         }
247
248
249         if( this.type == 'POST' ) {
250                 data = this.param_string;
251                 this.xmlhttp.setRequestHeader('Content-Type',
252                                 'application/x-www-form-urlencoded');
253         }
254
255         debug("Remote Request sending..." + data);
256         this.xmlhttp.send( data );
257         this.sendCount += 1;
258         debug("Remote Request done sending");
259         return this;
260 }
261
262 /* returns the actual response text from the request */
263 RemoteRequest.prototype.getText = function() {
264         return this.xmlhttp.responseText;
265 }
266
267 RemoteRequest.prototype.isReady = function() {
268         return this.xmlhttp.readyState == 4;
269 }
270
271
272 /* returns the JSON->js result object  */
273 RemoteRequest.prototype.getResultObject = function() {
274         if(this.cancelled) return null;
275
276         var text = this.xmlhttp.responseText;
277         var obj = JSON2js(text);
278
279         if(obj == null) {
280                 debug("received null response");
281                 return null;
282         }
283
284         if(obj.is_err) { 
285                 debug("Something's Wrong: " + js2JSON(obj));
286                 throw new EXCommunication(obj.err_msg); 
287         }
288
289         if( obj[0] != null && obj[1] == null ) 
290                 obj = obj[0];
291
292         /* these are user level exceptions from the server code */
293         if(instanceOf(obj, ex)) {
294                 debug("Received user level exception: " + obj.err_msg());
295                 /* the opac will go ahead and spit out the error msg */
296                 if(!isXUL()) alert(obj.err_msg());
297                 throw obj;
298         }
299
300         if(instanceOf(obj, perm_ex)) {
301                 debug("Received permission error: " + obj.err_msg());
302                 /* the opac will go ahead and spit out the error msg */
303                 if(!isXUL()) alert(obj.err_msg());
304                 throw obj;
305         }
306
307         return obj;
308 }
309
310 /* adds a new parameter to the request */
311 RemoteRequest.prototype.addParam = function(param) {
312         var string = encodeURIComponent(js2JSON(param));
313         this.param_string += "&__param=" + string;
314 }
315