From 0108250ed94957558bde6cf3d0c631cc20491089 Mon Sep 17 00:00:00 2001 From: ahocevar Date: Fri, 27 Jul 2012 14:18:37 +0200 Subject: [PATCH] WPSClient and WPSProcess for convenient WPS interaction. --- examples/wps-client.html | 29 ++++ examples/wps-client.js | 64 +++++++++ lib/OpenLayers.js | 4 +- lib/OpenLayers/WPSClient.js | 126 +++++++++++++++++ lib/OpenLayers/WPSProcess.js | 257 +++++++++++++++++++++++++++++++++++ 5 files changed, 479 insertions(+), 1 deletion(-) create mode 100644 examples/wps-client.html create mode 100644 examples/wps-client.js create mode 100644 lib/OpenLayers/WPSClient.js create mode 100644 lib/OpenLayers/WPSProcess.js diff --git a/examples/wps-client.html b/examples/wps-client.html new file mode 100644 index 0000000000..b588f7fba2 --- /dev/null +++ b/examples/wps-client.html @@ -0,0 +1,29 @@ + + + + + + + OpenLayers WPS Client Example + + + + + + +

WPS Client Example

+ +
+ wps +
+ +
Shows the usage of the WPS Client
+ +
+ +
+

This example shows how simple it is to use the WPS Client. See + wps-client.js to see how this is done.

+
+ + diff --git a/examples/wps-client.js b/examples/wps-client.js new file mode 100644 index 0000000000..fad7a5868c --- /dev/null +++ b/examples/wps-client.js @@ -0,0 +1,64 @@ +var map, client, process; + +function init() { + + map = new OpenLayers.Map('map', { + allOverlays: true, + center: [114, 16], + zoom: 4, + layers: [new OpenLayers.Layer.Vector()] + }); + + var features = [new OpenLayers.Format.WKT().read( + 'LINESTRING(117 22,112 18,118 13, 115 8)' + )]; + var geometry = (new OpenLayers.Format.WKT().read( + 'POLYGON((110 20,120 20,120 10,110 10,110 20),(112 17,118 18,118 16,112 15,112 17))' + )).geometry; + + map.baseLayer.addFeatures(features); + map.baseLayer.addFeatures([new OpenLayers.Feature.Vector(geometry)]); + + client = new OpenLayers.WPSClient({ + servers: { + local: "/geoserver/wps" + } + }); + + // Create a process and execute it + process = client.getProcess("local", "JTS:intersection"); + process.execute({ + // spatial input can be a feature or a geometry or an array of + // features or geometries + inputs: { + a: features, + b: geometry + }, + success: function(outputs) { + // outputs.result is a feature or an array of features for spatial + // processes. + map.baseLayer.addFeatures(outputs.result); + } + }); + + // Instead of creating a process and executing it, we could call execute on + // the client directly if we are only dealing with a single process: + /* + client.execute({ + server: "local", + process: "JTS:intersection", + // spatial input can be a feature or a geometry or an array of + // features or geometries + inputs: { + a: features, + b: geometry + }, + success: function(outputs) { + // outputs.result is a feature or an array of features for spatial + // processes. + map.baseLayer.addFeatures(outputs.result); + } + }); + */ + +} \ No newline at end of file diff --git a/lib/OpenLayers.js b/lib/OpenLayers.js index c8c80d847f..cca76a78d8 100644 --- a/lib/OpenLayers.js +++ b/lib/OpenLayers.js @@ -394,7 +394,9 @@ "OpenLayers/Symbolizer/Raster.js", "OpenLayers/Lang.js", "OpenLayers/Lang/en.js", - "OpenLayers/Spherical.js" + "OpenLayers/Spherical.js", + "OpenLayers/WPSClient.js", + "OpenLayers/WPSProcess.js" ]; // etc. } diff --git a/lib/OpenLayers/WPSClient.js b/lib/OpenLayers/WPSClient.js new file mode 100644 index 0000000000..11b42c3ab7 --- /dev/null +++ b/lib/OpenLayers/WPSClient.js @@ -0,0 +1,126 @@ +/** + * Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. + * + * @requires OpenLayers/SingleFile.js + */ + +/** + * Class: OpenLayers.WPSClient + */ +OpenLayers.WPSClient = OpenLayers.Class({ + + /** + * Property: servers + * {Object} Service metadata, keyed by a local identifier. + * + * Properties: + * url - {String} the url of the server + * knownProcesses: {Object} Cache of DescribeProcess responses, keyed by + * process identifier. + */ + servers: null, + + /** + * Property: lazy + * {Boolean} Should the DescribeProcess be deferred until a process is + * fully configured? Default is false. + */ + lazy: false, + + /** + * Constructor: OpenLayers.WPSClient + * + * Parameters: + * options - {Object} Object whose properties will be set on the instance. + * + * Avaliable options: + * servers - {Object} Mandatory. Service metadata, keyed by a local + * identifier. Can either be a string with the service url or an + * object literal with additional metadata: + * + * (code) + * servers: { + * local: '/geoserver/wps' + * }, { + * opengeo: { + * url: 'http://demo.opengeo.org/geoserver/wps', + * version: '1.0.0' + * } + * } + * (end) + * + * lazy - {Boolean} Optional. Set to true if DescribeProcess should not be + * requested until a process is fully configured. Default is false. + */ + initialize: function(options) { + OpenLayers.Util.extend(this, options); + this.servers = {}; + for (var s in options.servers) { + this.servers[s] = typeof options.servers[s] == 'string' ? { + url: options.servers[s], + version: '1.0.0' + } : options.servers[s]; + } + }, + + /** + * APIMethod: execute + * + * Parameters: + * options - {Object} Options for the execute operation. + * + * Available options: + * server - {String} Mandatory. One of the local identifiers of the + * configured servers. + * process - {String} Mandatory. A process identifier known to the + * server. + * inputs - {Object} The inputs for the process, keyed by input identifier. + * For spatial data inputs, the value of an input is usually an + * , an or an array of + * geometries or features. + * success - {Function} Callback to call when the process is complete. + * This function is called with an outputs object as argument, which + * will have a 'result' property. For processes that generate spatial + * output, this will either be a single or + * an array of features. + * scope - {Object} Optional scope for the success callback. + */ + execute: function(options) { + var process = this.getProcess(options.server, options.process); + process.execute({ + inputs: options.inputs, + success: options.success, + scope: options.scope + }); + }, + + /** + * APIMethod: getProcess + * Creates an . + * + * Parameters: + * server - {String} Local identifier from the servers that this instance + * was constructed with. + * identifier - {String} Process identifier known to the server. + * + * Returns: + * {} + */ + getProcess: function(server, identifier) { + var process = new OpenLayers.WPSProcess({ + client: this, + server: server, + identifier: identifier + }); + if (!this.lazy) { + process.describe(); + } + return process; + }, + + CLASS_NAME: 'OpenLayers.WPSClient' + +}); diff --git a/lib/OpenLayers/WPSProcess.js b/lib/OpenLayers/WPSProcess.js new file mode 100644 index 0000000000..2d8eb82af3 --- /dev/null +++ b/lib/OpenLayers/WPSProcess.js @@ -0,0 +1,257 @@ +/** + * Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. + * + * @requires OpenLayers/SingleFile.js + */ + +/** + * @requires OpenLayers/Events.js + * @requires OpenLayers/Geometry.js + * @requires OpenLayers/Feature/Vector.js + */ + +/** + * Class: OpenLayers.WPSProces + */ +OpenLayers.WPSProcess = OpenLayers.Class({ + + /** + * APIProperty: events + * {} + * + * Supported event types: + * describeprocess - fires when the process description is available + */ + events: null, + + /** + * Property: client + * {} The client that manages this process. + */ + client: null, + + /** + * Property: server + * {String} Local client identifier for this process's server. + */ + server: null, + + /** + * Property: identifier + * {String} Process identifier known to the server. + */ + identifier: null, + + /** + * Property: description + * {Object} DescribeProcess response for this process. + */ + description: null, + + /** + * Property: formats + * {Object} OpenLayers.Format instances keyed by mimetype. + */ + formats: null, + + /** + * Constructor: OpenLayers.WPSProcess + * + * Parameters: + * options - {Object} Object whose properties will be set on the instance. + * + * Avaliable options: + * client - {. + */ + describe: function() { + if (this._describePending || this.description) { + return; + } + this._describePending = true; + var server = this.client.servers[this.server]; + OpenLayers.Request.GET({ + url: server.url, + params: { + SERVICE: 'WPS', + VERSION: server.version, + REQUEST: 'DescribeProcess', + IDENTIFIER: this.identifier + }, + success: function(response) { + this.description = new OpenLayers.Format.WPSDescribeProcess() + .read(response.responseText) + .processDescriptions[this.identifier]; + delete this._describePending; + this.events.triggerEvent('describeprocess'); + }, + scope: this + }); + }, + + /** + * APIMethod: execute + * Executes the process + * + * Parameters: + * options - {Object} + * + * Available options: + * inputs - {Object} The inputs for the process, keyed by input identifier. + * For spatial data inputs, the value of an input is usually an + * , an or an array of + * geometries or features. + * success - {Function} Callback to call when the process is complete. + * This function is called with an outputs object as argument, which + * will have a 'result' property. For processes that generate spatial + * output, this will either be a single or + * an array of features. + * scope - {Object} Optional scope for the success callback. + */ + execute: function(options) { + if (!this.description) { + this.events.register('describeprocess', this, function execute() { + this.events.unregister('describeprocess', this, execute); + this.execute(options); + }); + this.describe(); + return; + } + var description = this.description, + inputs = options.inputs, + input, i, ii; + for (i=0, ii=description.dataInputs.length; i, an or an array of + * geometries or features. + */ + setInputData: function(input, data) { + // clear any previous data + input.data = {}; + if (data) { + var complexData = input.complexData; + if (complexData) { + var format = this.findMimeType(complexData); + input.data.complexData = { + mimeType: format, + value: this.formats[format].write(this.toFeatures(data)) + }; + } + } + }, + + /** + * Method: setResponseForm + * Sets the responseForm property of the payload. + */ + setResponseForm: function() { + output = this.description.processOutputs[0]; + this.description.responseForm = { + rawDataOutput: { + identifier: output.identifier, + mimeType: this.findMimeType(output.complexOutput) + } + }; + }, + + /** + * Method: toFeatures + * Converts spatial input into features so it can be processed by + * instances. + * + * Parameters: + * source - {Mixed} An , an + * , or an array of geometries or features + * + * Returns: + * {Array()} + */ + toFeatures: function(source) { + var isArray = OpenLayers.Util.isArray(source); + if (!isArray) { + source = [source]; + } + var target = new Array(source.length), + current; + for (var i=0, ii=source.length; i