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