+ Vector layer with a Fixed strategy, HTTP protocol, and GML format.
+
+
+
+ The vector layer shown uses the Fixed strategy, the HTTP protocol,
+ and the GML format.
+ The Fixed strategy is a simple strategy that fetches features once
+ and never re-requests new data.
+ The HTTP protocol makes requests using HTTP verbs. It should be
+ constructed with a url that corresponds to a collection of features
+ (a resource on some server).
+ The GML format is used to serialize features.
+
+
+
diff --git a/lib/OpenLayers.js b/lib/OpenLayers.js
index 5b890ab7f0..70e91bc64d 100644
--- a/lib/OpenLayers.js
+++ b/lib/OpenLayers.js
@@ -184,6 +184,7 @@
"OpenLayers/Strategy.js",
"OpenLayers/Strategy/Fixed.js",
"OpenLayers/Protocol.js",
+ "OpenLayers/Protocol/HTTP.js",
"OpenLayers/Layer/PointTrack.js",
"OpenLayers/Layer/GML.js",
"OpenLayers/Style.js",
diff --git a/lib/OpenLayers/Protocol/HTTP.js b/lib/OpenLayers/Protocol/HTTP.js
new file mode 100644
index 0000000000..76efb06486
--- /dev/null
+++ b/lib/OpenLayers/Protocol/HTTP.js
@@ -0,0 +1,454 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Protocol.js
+ * @requires OpenLayers/Feature/Vector.js
+ */
+
+/**
+ * Class: OpenLayers.Protocol.HTTP
+ * A basic HTTP protocol for vector layers. Create a new instance with the
+ * constructor.
+ *
+ * Inherits from:
+ * -
+ */
+OpenLayers.Protocol.HTTP = OpenLayers.Class(OpenLayers.Protocol, {
+
+ /**
+ * Property: url
+ * {String} - Service URL, read-only, set through the options
+ * passed to constructor.
+ */
+ url: null,
+
+ /**
+ * Property: headers
+ * {Object} - HTTP request headers, read-only, set through the options
+ * passed to the constructor,
+ * Example: {'Content-Type': 'plain/text'}
+ */
+ headers: null,
+
+ /**
+ * Property: params
+ * {Object} - Parameters of GET requests, read-only, set through the options
+ * passed to the constructor,
+ * Example: {'bbox': '5,5,5,5'}
+ */
+ params: null,
+
+ /**
+ * Property: format
+ * {} Parser for reading and writing features.
+ */
+ format: null,
+
+ /**
+ * Property: callback
+ * {Object} - Function to be called when the , ,
+ * , or operation completes, read-only,
+ * set through the options passed to the constructor.
+ */
+ callback: null,
+
+ /**
+ * Property: scope
+ * {Object} - Callback execution scope, read-only, set through the
+ * options passed to the constructor.
+ */
+ scope: null,
+
+ /**
+ * Constructor: OpenLayers.Protocol.HTTP
+ * A class for giving layers generic HTTP protocol.
+ *
+ * Parameters:
+ * options - {Object} Optional object whose properties will be set on the
+ * instance.
+ *
+ * Valid options include:
+ * url - {String}
+ * headers - {Object}
+ * params - {Object}
+ * format - {}
+ * callback - {Function}
+ * scope - {Object}
+ */
+ initialize: function(options) {
+ this.params = {};
+ this.headers = {};
+ OpenLayers.Protocol.prototype.initialize.apply(this, arguments);
+ },
+
+ /**
+ * APIMethod: destroy
+ * Clean up the protocol.
+ */
+ destroy: function() {
+ this.params = null;
+ this.headers = null;
+ OpenLayers.Protocol.prototype.destroy.apply(this);
+ },
+
+ /**
+ * Method: createCallback
+ * Returns a function that applies the given public method with resp and
+ * options arguments.
+ *
+ * Parameters:
+ * method - {Function} The method to be applied by the callback.
+ * response - {} The protocol response object.
+ * options - {Object} Options sent to the protocol method (read, create,
+ * update, or delete).
+ */
+ createCallback: function(method, response, options) {
+ return OpenLayers.Function.bind(function() {
+ method.apply(this, [response, options]);
+ }, this);
+ },
+
+ /**
+ * Method: read
+ * Construct a request for reading new features.
+ *
+ * Parameters:
+ * options - {Object} Optional object for configuring the request.
+ * This object is modified and should not be reused.
+ *
+ * Returns:
+ * {} A response object, whose "priv" property
+ * references the HTTP request, this object is also passed to the
+ * callback function when the request completes, its "features" property
+ * is then populated with the the features received from the server.
+ */
+ read: function(options) {
+ options = OpenLayers.Util.applyDefaults(options, this.options);
+ var resp = new OpenLayers.Protocol.Response({requestType: "read"});
+
+ resp.priv = OpenLayers.Request.GET({
+ url: options.url,
+ callback: this.createCallback(this.handleRead, resp, options),
+ params: options.params,
+ headers: options.headers
+ });
+
+ return resp;
+ },
+
+ /**
+ * Method: handleRead
+ * Individual callbacks are created for read, create and update, should
+ * a subclass need to override each one separately.
+ *
+ * Parameters:
+ * resp - {} The response object to pass to
+ * the user callback.
+ * options - {Object} The user options passed to the read call.
+ */
+ handleRead: function(resp, options) {
+ this.handleResponse(resp, options);
+ },
+
+ /**
+ * Method: create
+ * Construct a request for writing newly created features.
+ *
+ * Parameters:
+ * features - {Array({})} or
+ * {}
+ * options - {Object} Optional object for configuring the request.
+ * This object is modified and should not be reused.
+ *
+ * Returns:
+ * {} An
+ * object, whose "priv" property references the HTTP request, this
+ * object is also passed to the callback function when the request
+ * completes, its "features" property is then populated with the
+ * the features received from the server.
+ */
+ create: function(features, options) {
+ options = OpenLayers.Util.applyDefaults(options, this.options);
+
+ var resp = new OpenLayers.Protocol.Response({
+ reqFeatures: features,
+ requestType: "create"
+ });
+
+ resp.priv = OpenLayers.Request.POST({
+ url: options.url,
+ callback: this.createCallback(this.handleCreate, resp, options),
+ headers: options.headers,
+ data: this.format.write(features)
+ });
+
+ return resp;
+ },
+
+ /**
+ * Method: handleCreate
+ * Called the the request issued by is complete. May be overridden
+ * by subclasses.
+ *
+ * Parameters:
+ * resp - {} The response object to pass to
+ * any user callback.
+ * options - {Object} The user options passed to the create call.
+ */
+ handleCreate: function(resp, options) {
+ this.handleResponse(resp, options);
+ },
+
+ /**
+ * Method: update
+ * Construct a request updating modified feature.
+ *
+ * Parameters:
+ * feature - {}
+ * options - {Object} Optional object for configuring the request.
+ * This object is modified and should not be reused.
+ *
+ * Returns:
+ * {} An
+ * object, whose "priv" property references the HTTP request, this
+ * object is also passed to the callback function when the request
+ * completes, its "features" property is then populated with the
+ * the feature received from the server.
+ */
+ update: function(feature, options) {
+ var url = options.url || feature.url || this.options.url;
+ options = OpenLayers.Util.applyDefaults(options, this.options);
+
+ var resp = new OpenLayers.Protocol.Response({
+ reqFeatures: feature,
+ requestType: "update"
+ });
+
+ resp.priv = OpenLayers.Request.PUT({
+ url: url,
+ callback: this.createCallback(this.handleUpdate, resp, options),
+ headers: options.headers,
+ data: this.format.write(feature)
+ });
+
+ return resp;
+ },
+
+ /**
+ * Method: handleUpdate
+ * Called the the request issued by is complete. May be overridden
+ * by subclasses.
+ *
+ * Parameters:
+ * resp - {} The response object to pass to
+ * any user callback.
+ * options - {Object} The user options passed to the update call.
+ */
+ handleUpdate: function(resp, options) {
+ this.handleResponse(resp, options);
+ },
+
+ /**
+ * Method: delete
+ * Construct a request deleting a removed feature.
+ *
+ * Parameters:
+ * feature - {}
+ * options - {Object} Optional object for configuring the request.
+ * This object is modified and should not be reused.
+ *
+ * Returns:
+ * {} An
+ * object, whose "priv" property references the HTTP request, this
+ * object is also passed to the callback function when the request
+ * completes.
+ */
+ "delete": function(feature, options) {
+ var url = options.url || feature.url || this.options.url;
+ options = OpenLayers.Util.applyDefaults(options, this.options);
+
+ var resp = new OpenLayers.Protocol.Response({
+ reqFeatures: feature,
+ requestType: "delete"
+ });
+
+ resp.priv = OpenLayers.Request.DELETE({
+ url: url,
+ callback: this.createCallback(this.handleDelete, resp, options),
+ headers: options.headers
+ });
+
+ return resp;
+ },
+
+ /**
+ * Method: handleDelete
+ * Called the the request issued by is complete. May be overridden
+ * by subclasses.
+ *
+ * Parameters:
+ * resp - {} The response object to pass to
+ * any user callback.
+ * options - {Object} The user options passed to the delete call.
+ */
+ handleDelete: function(resp, options) {
+ this.handleResponse(resp, options);
+ },
+
+ /**
+ * Method: handleResponse
+ * Called by CRUD specific handlers.
+ *
+ * Parameters:
+ * resp - {} The response object to pass to
+ * any user callback.
+ * options - {Object} The user options passed to the create, read, update,
+ * or delete call.
+ */
+ handleResponse: function(resp, options) {
+ var request = resp.priv;
+ if(options.callback) {
+ if(request.status >= 200 && request.status < 300) {
+ // success
+ if(resp.requestType != "delete") {
+ resp.features = this.parseFeatures(request);
+ }
+ resp.code = OpenLayers.Protocol.Response.SUCCESS;
+ } else {
+ // failure
+ resp.code = OpenLayers.Protocol.Response.FAILURE;
+ }
+ options.callback.call(options.scope, resp);
+ }
+ },
+
+ /**
+ * Method: parseFeatures
+ * Read HTTP response body and return features.
+ *
+ * Parameters:
+ * request - {XMLHttpRequest} The request object
+ *
+ * Returns:
+ * {Array({})} or
+ * {} Array of features or a single feature.
+ */
+ parseFeatures: function(request) {
+ var doc = request.responseXML;
+ if (!doc || !doc.documentElement) {
+ doc = request.responseText;
+ }
+ if (!doc || doc.length <= 0) {
+ return null;
+ }
+ return this.format.read(doc);
+ },
+
+ /**
+ * Method: commit
+ * Iterate over each feature and take action based on the feature state.
+ * Possible actions are create, update and delete.
+ *
+ * Parameters:
+ * features - {Array({})}
+ * options - {Object} Optional object for setting up intermediate commit
+ * callbacks.
+ *
+ * Valid options:
+ * create - {Object} Optional object to be passed to the method.
+ * update - {Object} Optional object to be passed to the method.
+ * delete - {Object} Optional object to be passed to the method.
+ * callback - {Function} Optional function to be called when the commit
+ * is complete.
+ * scope - {Object} Optional object to be set as the scope of the callback.
+ *
+ * Returns:
+ * {Array()} An array of response objects,
+ * one per request made to the server, each object's "priv" property
+ * references the corresponding HTTP request.
+ */
+ commit: function(features, options) {
+ options = OpenLayers.Util.applyDefaults(options, this.options);
+ var resp = [], nResponses = 0;
+
+ // Divide up features before issuing any requests. This properly
+ // counts requests in the event that any responses come in before
+ // all requests have been issued.
+ var types = {};
+ types[OpenLayers.State.INSERT] = [];
+ types[OpenLayers.State.UPDATE] = [];
+ types[OpenLayers.State.DELETE] = [];
+ var feature, list;
+ for(var i=0, len=features.length; i 0 ? 1 : 0) +
+ types[OpenLayers.State.UPDATE].length +
+ types[OpenLayers.State.DELETE].length;
+
+ function callback(response) {
+ nResponses++;
+ response.last = (nResponses >= nRequests);
+ this.callUserCallback(response, options);
+ }
+
+ // start issuing requests
+ var queue = types[OpenLayers.State.INSERT];
+ if(queue.length > 0) {
+ resp.push(this.create(
+ queue, OpenLayers.Util.applyDefaults(
+ {callback: callback, scope: this},
+ options.create || {} // remove || when #1716 is resolved
+ )
+ ));
+ }
+ queue = types[OpenLayers.State.UPDATE];
+ for(var i=queue.length-1; i>=0; --i) {
+ resp.push(this.update(
+ queue[i], OpenLayers.Util.applyDefaults(
+ {callback: callback, scope: this},
+ options.update || {} // remove || when #1716 is resolved
+ ))
+ );
+ }
+ queue = types[OpenLayers.State.DELETE];
+ for(var i=queue.length-1; i>=0; --i) {
+ resp.push(this["delete"](
+ queue[i], OpenLayers.Util.applyDefaults(
+ {callback: callback, scope: this},
+ options["delete"] || {} // remove || when #1716 is resolved
+ ))
+ );
+ }
+ return resp;
+ },
+
+ /**
+ * Method: callUserCallback
+ * This method is used from within the commit method each time an
+ * an HTTP response is received from the server, it is responsible
+ * for calling the user-supplied callbacks.
+ *
+ * Parameters:
+ * resp - {}
+ * options - {Object} The map of options passed to the commit call.
+ */
+ callUserCallback: function(resp, options) {
+ var opt = options[resp.requestType];
+ if(opt && opt.callback) {
+ opt.callback.call(opt.scope, resp);
+ }
+ if(resp.last && options.callback) {
+ options.callback.call(options.scope);
+ }
+ },
+
+ CLASS_NAME: "OpenLayers.Protocol.HTTP"
+});
diff --git a/tests/Protocol/HTTP.html b/tests/Protocol/HTTP.html
new file mode 100644
index 0000000000..56a27b4476
--- /dev/null
+++ b/tests/Protocol/HTTP.html
@@ -0,0 +1,669 @@
+
+
+
+
+
+
+
+
diff --git a/tests/list-tests.html b/tests/list-tests.html
index 9c68c3dbe0..adf2aaf8e8 100644
--- a/tests/list-tests.html
+++ b/tests/list-tests.html
@@ -113,6 +113,7 @@