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