Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
Expert GeoServer

You're reading from   Expert GeoServer Build and secure advanced interfaces and interactive maps

Arrow left icon
Product type Paperback
Published in Jul 2018
Publisher Packt
ISBN-13 9781789538601
Length 134 pages
Edition 1st Edition
Languages
Arrow right icon
Author (1):
Arrow left icon
Ben Mearns Ben Mearns
Author Profile Icon Ben Mearns
Ben Mearns
Arrow right icon
View More author details
Toc

Process chaining

In the previous section, you learned about creating WPS requests with WPS request builder. In this section, you'll learn how to make more complex WPS requests with process chaining. First, we'll take a look at a chain process request in plain XML. Next, we'll create an even more complex request. Finally, we'll add this request to a minimal OpenLayers web app to test the results of POST.

Here is our first process-chained XML, and you can see that the first WPS process is started here with this wps:Execute operation. The identifier is gs:CollectGeometries, so it's the gs:CollectGeometries process that we're running here, as shown in the following code:

<?xml version="1.0" encoding="UTF-8"?>
<wps:Execute version="1.0.0" service="WPS" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.opengis.net/wps/1.0.0" xmlns:wfs="http://www.opengis.net/wfs" xmlns:wps="http://www.opengis.net/wps/1.0.0" xmlns:ows="http://www.opengis.net/ows/1.1" xmlns:gml="http://www.opengis.net/gml" xmlns:ogc="http://www.opengis.net/ogc" xmlns:wcs="http://www.opengis.net/wcs/1.1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="http://www.opengis.net/wps/1.0.0 http://schemas.opengis.net/wps/1.0.0/wpsAll.xsd">
<ows:Identifier>gs:CollectGeometries</ows:Identifier>
<wps:DataInputs>
...
// Full code in the code bundle
</wps:ResponseForm>
</wps:Execute>

But the interesting thing is that when you look at wps:Input of CollectGeometries, you can see it's getting the features parameter from wps:Reference. So, this is not wps:Execute, yet it still is wps:Reference, but it's referencing a text/xml type that includes an wps:Execute operation in it, which is a little bit convoluted, but that's just how it's set up. And this is usually how you're going to refer to process-chained processes, with XML inside of other processes.

So, we have our second wps:Execute operation here, inside a wps:Body section, and this is using the BufferFeatureCollection process, which also has a features input parameter:

<wps:Body>
<wps:Execute version="1.0.0" service="WPS">
<ows:Identifier>gs:BufferFeatureCollection</ows:Identifier>
<wps:DataInputs>
<wps:Input>
<ows:Identifier>features</ows:Identifier>
<wps:Reference mimeType="text/xml" xlink:href="http://geoserver/wfs" method="POST">
<wps:Body>
<wfs:GetFeature service="WFS" version="1.0.0" outputFormat="GML2" xmlns:learning-geoserver="http://packtpub.com/learning-geoserver">
<wfs:Query srsName="EPSG:2272" typeName="learning-geoserver:pois"/>
</wfs:GetFeature>
</wps:Body>
</wps:Reference>
</wps:Input>

Here, for features, we're also using wps:Reference, but rather than having an additional WPS request or WPS section inside of wps:Reference, we're using wfs. This section in here is actually just a valid wfs defined by the WFS standard:

<wfs:GetFeature service="WFS" version="1.0.0" outputFormat="GML2" xmlns:learning-geoserver="http://packtpub.com/learning-geoserver">
<wfs:Query srsName="EPSG:2272" typeName="learning-geoserver:pois"/>
</wfs:GetFeature>

So anything that you would put, for example, in a wfs:Query section on WFS would be valid, and in this section of this XML. We're just using a regular wfs:Query, getting all of the points of interest in the learning-geoserver:pois workspace. Some things to be aware of here are, again, data types, so we're going to be outputting the following little portion as text XML-based wfs-collection:

<wps:RawDataOutput mimeType="text/xml; subtype=wfs-collection/1.0">
<ows:Identifier>result</ows:Identifier>
</wps:RawDataOutput>

That is just the way this buffer features collection process returns data, and, of course, gs:CollectGeometries will turn that collection into geometries. So, be aware of data formats. You'll be using a lot of different formats through a process-chained operation. A lot of the time, you'll be changing between different formats, so of course, the spatial reference will be important. In this case, we'd have trouble doing some of these operations if we're not using a linear spatial reference, and we end up having to change or reproject the spatial reference into a different system later on, which you'll see in the next section, with OpenLayers.

The namespaces are also very important. Because this is just a feature of XML, you have to explain what your tag is referring to so that all the different data types appear in their own way. If you are using XML namespaces correctly, it separates out portions of the XML in the correct way so that the services you're feeding it to understand how to read the data.

You can see many namespaces are defined up here; not all of them are necessary, but you can see that wfs is there, defining this little section and the syntax for this section, which comes from a WFS standard:

<wps:Reference mimeType="text/xml" xlink:href="http://geoserver/wfs" method="POST">
<wps:Body>
<wfs:GetFeature service="WFS" version="1.0.0" outputFormat="GML2" xmlns:learning-geoserver="http://packtpub.com/learning-geoserver">
<wfs:Query srsName="EPSG:2272" typeName="learning-geoserver:pois"/>
</wfs:GetFeature>
</wps:Body>
</wps:Reference>

Here is the result of this as GML:

<wps:RawDataOutput mimeType="text/xml; subtype=gml/3.1.1">
<ows:Identifier>result</ows:Identifier>
</wps:RawDataOutput>

So, that's our first XML example of a WPS request. Let's look at our second example, as follows:

<ows:Identifier>JTS:difference</ows:Identifier>
<wps:DataInputs>
<wps:Input>
<ows:Identifier>a</ows:Identifier>
<wps:Reference mimeType="text/xml; subtype=gml/3.1.1" xlink:href="http://geoserver/wps" method="POST">
<wps:Body>
<wps:Execute version="1.0.0" service="WPS">
<ows:Identifier>gs:CollectGeometries</ows:Identifier>
<wps:DataInputs>
<wps:Input>
<ows:Identifier>features</ows:Identifier>
<wps:Reference mimeType="text/xml" xlink:href="http://geoserver/wps" method="POST">

This is our second WPS request, and it will be even more complex than the last one, with process chaining. In the last process chain, we look at this gs:CollectGeometries section and everything below it. In this process-chained operation, we're using this difference process, which is based on a JTS namespace, and this takes two wps:Input parameters:

<ows:Identifier>JTS:difference</ows:Identifier>

Each of these inputs gives geometry in GML, and this process will take the difference of these geometries and give us that as a separate geometry feature collection or single geometry in GeoJSON format:

<wps:RawDataOutput mimeType="application/json">
<ows:Identifier>result</ows:Identifier>
</wps:RawDataOutput>

Now I'm moving over into OpenLayers. We can run a very simple WPS request as follows:

<!DOCTYPE html>
<html lang="en">
<head>
<title>WPS-Request Example</title><!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content=
"width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- OL stylesheet -->
<link rel="stylesheet" href="https://openlayers.org/en/v4.4.2/css/ol.css" type="text/css">
</head>
<body>
<h1>WPS-Request Example</h1>

<!-- OpenLayers JS dependency, debug build -->
<script type="text/javascript" src="https://openlayers.org/en/v4.4.2/build/ol-debug.js"></script>
<!-- Begin wps-request Javascript -->
<script type="text/javascript">

The preceding code is based on a stripped-down OpenLayers app, which sends an HTTP POST request with XML. We can start with this, doing incremental testing to build up a chained WPS request in the OpenLayers code. So, it's pretty stripped down; there's not a whole lot going on there. We just have our postData with all of the WPS text XML body, which is as follows:

postData = '<?xml version="1.0" encoding="UTF-8"?><wps:Execute version="1.0.0" service="WPS" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.opengis.net/wps/1.0.0" xmlns:wfs="http://www.opengis.net/wfs" xmlns:wps="http://www.opengis.net/wps/1.0.0" xmlns:ows="http://www.opengis.net/ows/1.1" xmlns:gml="http://www.opengis.net/gml" xmlns:ogc="http://www.opengis.net/ogc" xmlns:wcs="http://www.opengis.net/wcs/1.1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="http://www.opengis.net/wps/1.0.0 http://schemas.opengis.net/wps/1.0.0/wpsAll.xsd"> <ows:Identifier>gs:Aggregate</ows:Identifier><wps:DataInputs><wps:Input><ows:Identifier>features</ows:Identifier><wps:Reference mimeType="text/xml" xlink:href="http://geoserver/wfs" method="POST"><wps:Body><wfs:GetFeature service="WFS" version="1.0.0" outputFormat="GML2" xmlns:sf="http://www.openplans.org/spearfish"><wfs:Query typeName="topp:states"/></wfs:GetFeature></wps:Body></wps:Reference></wps:Input><wps:Input><ows:Identifier>aggregationAttribute</ows:Identifier><wps:Data><wps:LiteralData>PERSONS</wps:LiteralData></wps:Data></wps:Input><wps:Input><ows:Identifier>function</ows:Identifier><wps:Data><wps:LiteralData>Count</wps:LiteralData></wps:Data></wps:Input><wps:Input><ows:Identifier>function</ows:Identifier><wps:Data><wps:LiteralData>Average</wps:LiteralData></wps:Data></wps:Input><wps:Input><ows:Identifier>function</ows:Identifier><wps:Data><wps:LiteralData>Sum</wps:LiteralData></wps:Data></wps:Input><wps:Input><ows:Identifier>function</ows:Identifier><wps:Data><wps:LiteralData>Min</wps:LiteralData></wps:Data></wps:Input><wps:Input><ows:Identifier>function</ows:Identifier><wps:Data><wps:LiteralData>Max</wps:LiteralData></wps:Data></wps:Input><wps:Input><ows:Identifier>singlePass</ows:Identifier><wps:Data><wps:LiteralData>false</wps:LiteralData></wps:Data></wps:Input></wps:DataInputs><wps:ResponseForm><wps:RawDataOutput mimeType="application/json"><ows:Identifier>result</ows:Identifier></wps:RawDataOutput></wps:ResponseForm></wps:Execute>';

Then, postData is sent via this XML HTTP request object posted to GeoServer. Then we'll get a response in as an alert, which can be achieved with the following code:

url = 'http://localhost:8080/geoserver/wps';
var req = new XMLHttpRequest();
req.open("POST", url, true);
req.setRequestHeader('Content-type', 'text/xml');
req.onreadystatechange = function() {
if (req.readyState != 4) return;
if (req.status != 200 && req.status != 304) {
alert('HTTP error ' + req.status);
return;
}
alert(req.responseText);
if (req.readyState == 4) return;
};
req.send(postData);

So, we can test that out, and you can see the following result of that operation, which is in JSON; it's the data corresponding to the request:

Taking that one step further, we just add the XML from the more complex chained operation that we showed in the second example XML previously. Now, if we run this process-chained POST request, running this more complex process-chained POST request will sometimes require some time before it returns a result. Here you can see the result as GeoJSON:

Again, the spatial reference system is linear, so we're seeing much longer coordinates than we would normally see, but we're getting a successful result from our complex process-chained operation.

You've seen now how to create a complex process-chained operation. In the next section, we'll look at full integration of that WPS request into OpenLayers, as well as the result.

lock icon The rest of the chapter is locked
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $19.99/month. Cancel anytime
Banner background image