1
/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
2
* license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
3
* full text of the license. */
6
* @requires OpenLayers/Protocol.js
7
* @requires OpenLayers/Feature/Vector.js
11
* Class: OpenLayers.Protocol.HTTP
12
* A basic HTTP protocol for vector layers. Create a new instance with the
13
* <OpenLayers.Protocol.HTTP> constructor.
16
* - <OpenLayers.Protocol>
18
OpenLayers.Protocol.HTTP = OpenLayers.Class(OpenLayers.Protocol, {
22
* {String} Service URL, read-only, set through the options
23
* passed to constructor.
29
* {Object} HTTP request headers, read-only, set through the options
30
* passed to the constructor,
31
* Example: {'Content-Type': 'plain/text'}
37
* {Object} Parameters of GET requests, read-only, set through the options
38
* passed to the constructor,
39
* Example: {'bbox': '5,5,5,5'}
45
* {Object} Function to be called when the <read>, <create>,
46
* <update>, <delete> or <commit> operation completes, read-only,
47
* set through the options passed to the constructor.
53
* {Object} Callback execution scope, read-only, set through the
54
* options passed to the constructor.
59
* Constructor: OpenLayers.Protocol.HTTP
60
* A class for giving layers generic HTTP protocol.
63
* options - {Object} Optional object whose properties will be set on the
66
* Valid options include:
70
* format - {<OpenLayers.Format>}
71
* callback - {Function}
74
initialize: function(options) {
77
OpenLayers.Protocol.prototype.initialize.apply(this, arguments);
82
* Clean up the protocol.
87
OpenLayers.Protocol.prototype.destroy.apply(this);
91
* Method: createCallback
92
* Returns a function that applies the given public method with resp and
96
* method - {Function} The method to be applied by the callback.
97
* response - {<OpenLayers.Protocol.Response>} The protocol response object.
98
* options - {Object} Options sent to the protocol method (read, create,
101
createCallback: function(method, response, options) {
102
return OpenLayers.Function.bind(function() {
103
method.apply(this, [response, options]);
109
* Construct a request for reading new features.
112
* options - {Object} Optional object for configuring the request.
113
* This object is modified and should not be reused.
116
* url - {String} Url for the request.
117
* params - {Object} Parameters to get serialized as a query string.
118
* headers - {Object} Headers to be set on the request.
119
* filter - {<OpenLayers.Filter.BBOX>} If a bbox filter is sent, it will be
120
* serialized according to the OpenSearch Geo extension
121
* (bbox=minx,miny,maxx,maxy). Note that a BBOX filter as the child
122
* of a logical filter will not be serialized.
125
* {<OpenLayers.Protocol.Response>} A response object, whose "priv" property
126
* references the HTTP request, this object is also passed to the
127
* callback function when the request completes, its "features" property
128
* is then populated with the the features received from the server.
130
read: function(options) {
131
options = OpenLayers.Util.applyDefaults(options, this.options);
132
var resp = new OpenLayers.Protocol.Response({requestType: "read"});
134
if(options.filter && options.filter instanceof OpenLayers.Filter.Spatial) {
135
if(options.filter.type == OpenLayers.Filter.Spatial.BBOX) {
136
options.params = OpenLayers.Util.extend(options.params, {
137
bbox: options.filter.value.toArray()
142
resp.priv = OpenLayers.Request.GET({
144
callback: this.createCallback(this.handleRead, resp, options),
145
params: options.params,
146
headers: options.headers
154
* Individual callbacks are created for read, create and update, should
155
* a subclass need to override each one separately.
158
* resp - {<OpenLayers.Protocol.Response>} The response object to pass to
160
* options - {Object} The user options passed to the read call.
162
handleRead: function(resp, options) {
163
this.handleResponse(resp, options);
168
* Construct a request for writing newly created features.
171
* features - {Array({<OpenLayers.Feature.Vector>})} or
172
* {<OpenLayers.Feature.Vector>}
173
* options - {Object} Optional object for configuring the request.
174
* This object is modified and should not be reused.
177
* {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
178
* object, whose "priv" property references the HTTP request, this
179
* object is also passed to the callback function when the request
180
* completes, its "features" property is then populated with the
181
* the features received from the server.
183
create: function(features, options) {
184
options = OpenLayers.Util.applyDefaults(options, this.options);
186
var resp = new OpenLayers.Protocol.Response({
187
reqFeatures: features,
188
requestType: "create"
191
resp.priv = OpenLayers.Request.POST({
193
callback: this.createCallback(this.handleCreate, resp, options),
194
headers: options.headers,
195
data: this.format.write(features)
202
* Method: handleCreate
203
* Called the the request issued by <create> is complete. May be overridden
207
* resp - {<OpenLayers.Protocol.Response>} The response object to pass to
209
* options - {Object} The user options passed to the create call.
211
handleCreate: function(resp, options) {
212
this.handleResponse(resp, options);
217
* Construct a request updating modified feature.
220
* feature - {<OpenLayers.Feature.Vector>}
221
* options - {Object} Optional object for configuring the request.
222
* This object is modified and should not be reused.
225
* {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
226
* object, whose "priv" property references the HTTP request, this
227
* object is also passed to the callback function when the request
228
* completes, its "features" property is then populated with the
229
* the feature received from the server.
231
update: function(feature, options) {
232
var url = options.url || feature.url || this.options.url;
233
options = OpenLayers.Util.applyDefaults(options, this.options);
235
var resp = new OpenLayers.Protocol.Response({
236
reqFeatures: feature,
237
requestType: "update"
240
resp.priv = OpenLayers.Request.PUT({
242
callback: this.createCallback(this.handleUpdate, resp, options),
243
headers: options.headers,
244
data: this.format.write(feature)
251
* Method: handleUpdate
252
* Called the the request issued by <update> is complete. May be overridden
256
* resp - {<OpenLayers.Protocol.Response>} The response object to pass to
258
* options - {Object} The user options passed to the update call.
260
handleUpdate: function(resp, options) {
261
this.handleResponse(resp, options);
266
* Construct a request deleting a removed feature.
269
* feature - {<OpenLayers.Feature.Vector>}
270
* options - {Object} Optional object for configuring the request.
271
* This object is modified and should not be reused.
274
* {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
275
* object, whose "priv" property references the HTTP request, this
276
* object is also passed to the callback function when the request
279
"delete": function(feature, options) {
280
var url = options.url || feature.url || this.options.url;
281
options = OpenLayers.Util.applyDefaults(options, this.options);
283
var resp = new OpenLayers.Protocol.Response({
284
reqFeatures: feature,
285
requestType: "delete"
288
resp.priv = OpenLayers.Request.DELETE({
290
callback: this.createCallback(this.handleDelete, resp, options),
291
headers: options.headers
298
* Method: handleDelete
299
* Called the the request issued by <delete> is complete. May be overridden
303
* resp - {<OpenLayers.Protocol.Response>} The response object to pass to
305
* options - {Object} The user options passed to the delete call.
307
handleDelete: function(resp, options) {
308
this.handleResponse(resp, options);
312
* Method: handleResponse
313
* Called by CRUD specific handlers.
316
* resp - {<OpenLayers.Protocol.Response>} The response object to pass to
318
* options - {Object} The user options passed to the create, read, update,
321
handleResponse: function(resp, options) {
322
var request = resp.priv;
323
if(options.callback) {
324
if(request.status >= 200 && request.status < 300) {
326
if(resp.requestType != "delete") {
327
resp.features = this.parseFeatures(request);
329
resp.code = OpenLayers.Protocol.Response.SUCCESS;
332
resp.code = OpenLayers.Protocol.Response.FAILURE;
334
options.callback.call(options.scope, resp);
339
* Method: parseFeatures
340
* Read HTTP response body and return features.
343
* request - {XMLHttpRequest} The request object
346
* {Array({<OpenLayers.Feature.Vector>})} or
347
* {<OpenLayers.Feature.Vector>} Array of features or a single feature.
349
parseFeatures: function(request) {
350
var doc = request.responseXML;
351
if (!doc || !doc.documentElement) {
352
doc = request.responseText;
354
if (!doc || doc.length <= 0) {
357
return this.format.read(doc);
362
* Iterate over each feature and take action based on the feature state.
363
* Possible actions are create, update and delete.
366
* features - {Array({<OpenLayers.Feature.Vector>})}
367
* options - {Object} Optional object for setting up intermediate commit
371
* create - {Object} Optional object to be passed to the <create> method.
372
* update - {Object} Optional object to be passed to the <update> method.
373
* delete - {Object} Optional object to be passed to the <delete> method.
374
* callback - {Function} Optional function to be called when the commit
376
* scope - {Object} Optional object to be set as the scope of the callback.
379
* {Array(<OpenLayers.Protocol.Response>)} An array of response objects,
380
* one per request made to the server, each object's "priv" property
381
* references the corresponding HTTP request.
383
commit: function(features, options) {
384
options = OpenLayers.Util.applyDefaults(options, this.options);
385
var resp = [], nResponses = 0;
387
// Divide up features before issuing any requests. This properly
388
// counts requests in the event that any responses come in before
389
// all requests have been issued.
391
types[OpenLayers.State.INSERT] = [];
392
types[OpenLayers.State.UPDATE] = [];
393
types[OpenLayers.State.DELETE] = [];
395
for(var i=0, len=features.length; i<len; ++i) {
396
feature = features[i];
397
list = types[feature.state];
402
// tally up number of requests
403
var nRequests = (types[OpenLayers.State.INSERT].length > 0 ? 1 : 0) +
404
types[OpenLayers.State.UPDATE].length +
405
types[OpenLayers.State.DELETE].length;
407
function callback(response) {
409
response.last = (nResponses >= nRequests);
410
this.callUserCallback(response, options);
413
// start issuing requests
414
var queue = types[OpenLayers.State.INSERT];
415
if(queue.length > 0) {
416
resp.push(this.create(
417
queue, OpenLayers.Util.applyDefaults(
418
{callback: callback, scope: this},
419
options.create || {} // remove || when #1716 is resolved
423
queue = types[OpenLayers.State.UPDATE];
424
for(var i=queue.length-1; i>=0; --i) {
425
resp.push(this.update(
426
queue[i], OpenLayers.Util.applyDefaults(
427
{callback: callback, scope: this},
428
options.update || {} // remove || when #1716 is resolved
432
queue = types[OpenLayers.State.DELETE];
433
for(var i=queue.length-1; i>=0; --i) {
434
resp.push(this["delete"](
435
queue[i], OpenLayers.Util.applyDefaults(
436
{callback: callback, scope: this},
437
options["delete"] || {} // remove || when #1716 is resolved
445
* Method: callUserCallback
446
* This method is used from within the commit method each time an
447
* an HTTP response is received from the server, it is responsible
448
* for calling the user-supplied callbacks.
451
* resp - {<OpenLayers.Protocol.Response>}
452
* options - {Object} The map of options passed to the commit call.
454
callUserCallback: function(resp, options) {
455
var opt = options[resp.requestType];
456
if(opt && opt.callback) {
457
opt.callback.call(opt.scope, resp);
459
if(resp.last && options.callback) {
460
options.callback.call(options.scope);
464
CLASS_NAME: "OpenLayers.Protocol.HTTP"