Advertisements

Archive

Tag Archives: Geoserver

Today’s post is mostly notes-to-self about using Docker. These steps were tested on a fresh Ubuntu 17.04 install.

Install Docker as described in https://docs.docker.com/engine/installation/linux/docker-ce/ubuntu/ “Install using the repository” section.

Then add the current user to the docker user group (otherwise, all docker commands have to be prefixed with sudo)

$ sudo gpasswd -a $USER docker
$ newgrp docker

Test run the hello world image

$ docker run hello-world

For some more Docker basics, see https://github.com/docker/labs/blob/master/beginner/chapters/alpine.md.

Pull Geodocker images, for example from https://quay.io/organization/geodocker

$ docker pull quay.io/geodocker/base
$ docker pull quay.io/geodocker/geoserver

Get a list of pulled images

$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
quay.io/geodocker/geoserver latest c60753e05956 8 months ago 904MB
quay.io/geodocker/base latest 293209905a47 8 months ago 646MB

Test run quay.io/geodocker/base

$ docker run -it --rm quay.io/geodocker/base:latest java -version
java version "1.8.0_45"
Java(TM) SE Runtime Environment (build 1.8.0_45-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.45-b02, mixed mode)

Run quay.io/geodocker/geoserver

$ docker run --name geoserver -e AUTHOR="Anita" \
 -d -P quay.io/geodocker/geoserver

The important options are:

-d … Run container in background and print container ID

-P … Publish all exposed ports to random ports

Check if the image is running

$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
684598b57868 quay.io/geodocker/geoserver "/opt/tomcat/bin/c..." 
2 hours ago Up 2 hours 0.0.0.0:32772->9090/tcp geoserver

You can also check which ports to access using

$ docker port geoserver
9090/tcp -> 0.0.0.0:32772

Geoserver should now run on http://localhost:32772/geoserver/ (user=admin, password=geoserver)

For more tests, let’s connect to Geoserver from QGIS

All default example layers are listed

and can be loaded into QGIS

Advertisements

“-T”, this small appendix can be found after many popular GIS-related acronym. But of course, it always means something different. Take for example GIS-T (GIS for Transportation), WFS-T (Transactional WFS) and WMS-T (WMS with time support). The world of acronyms is a fun place!

Let’s see what a WMS-T can do for us. From the WMS standard:

Some geographic information may be available at multiple times (for example, an hourly weather map). A WMS
may announce available times in its service metadata, and the GetMap operation includes a parameter for
requesting a particular time
. […] Depending on the context, time
values may appear as a single value, a list of values, or an interval, …

Currently, only Mapserver supports WMS-T but the Geoserver team is working on it.

Mapserver

MapServer 4.4 and above provides support to interpret the TIME parameter and transform the resulting values into appropriate requests.

Time attributes are specified within the metadata section:

METADATA
"wms_title" "Earthquakes"
"wms_timeextent" "2011-06-01/2011-07-01"
"wms_timeitem" "TIME"
"wms_timedefault" "2011-06-10 12:10:00"
END

Mapserver supports temporal queries for single values, multiple values, single range values or even multiple range values:

...&TIME=2011-06-10&...
...&TIME=2011-06-10, 2004-10-13, 2011-06-19&...
...&TIME=2011-06-10/2011-06-13&...
...&TIME=2011-06-10/2011-06-15, 2011-06-20/2011-06-25&...

Geoserver

GeoSolutions has developed support for TIME and ELEVATION dimensions in WMS.
There are plans to backport this feature to the stable 2.1.x series after the 2.1.1 release.

Configuration of time-enabled layers can be done via the normal user interface:

The following video by GeoSolutions demonstrates the use of Geoserver’s WMS-T:

Both server solutions seem to support only one time attribute per layer. An optional second time attribute would be nice to support datasets with start and end time like Time Manager for QGIS does.

GeoServer has always been good at simply publishing database tables. But anything more complex (e.g. pre-filtering data in a table, joining two tables together, or generating values on the fly) could be painful. With Geoserver 2.1 one can finally create a layer directly from an SQL query.

"Create New SQL View" interface

Even dynamic queries are possible, e.g.

select gid, state_name, the_geom from pgstates where persons between %low% and %high%

To select for example all states with 2 to 5 millions inhabitants, the following parameters can be added to the normal GetMap request:

&viewparams=low:2000000;high:5000000

Find more information on SQL layers in Geoserver 2.1 documentation.

The OGC filter encoding standard – for whatever reason – lacks the useful IN operator we know and love from other languages like SQL [1]. Geoserver developers have therefore implemented this functionality as a non-standard SLD function [2]. Unfortunately this implementation requires prior knowledge of the number of arguments in the IN clause and it’s limited to 10 arguments.

An example filter would look like this:

<ogc:Filter>
   <ogc:PropertyIsEqualsTo>
       <ogc:Function name="in3">
          <ogc:PropertyName>first_name</ogc:PropertyName>
          <ogc:Literal>Paul</ogc:Literal>
          <ogc:Literal>Mary</ogc:Literal>
          <ogc:Literal>Luke</ogc:Literal>
       </ogc:Function>
       <ogc:Literal>true</ogc:Literal>
   </ogc:PropertyIsEqualsTo>
</ogc:Filter>

[1] https://underdark.wordpress.com/2010/06/14/the-missing-in-operator-ogc-filter-standards/
[2] http://docs.geoserver.org/stable/en/user/styling/sld-tipstricks/mixed-geometries.html#using-non-standard-sld-functions

There is a new layer class in OpenLayers API: OpenLayers.Layer.WMS.Post [1]. – Great work!

While the “normal” OpenLayers.Layer.WMS class requests maps via HTTP GET, this new class sends the request via HTTP POST. This way, we can now send big client-side created SLD files in our GetMap requests that used to exceed size limits of GET.

This code snippet shows the basic use of OpenLayers.Layer.WMS.Post with a client-side created SLD. You’ll need at least OpenLayers 2.9 to test this on your server. (A full example can be found at http://www.openlayers.org/dev/examples/wms-long-url.html)

var sld = 'define your SLD here';

wms = new OpenLayers.Layer.WMS.Post(
  "name",
  "http://localhost:8080/geoserver/wms",
  {
    'layers': 'myNs:layername',
    format: 'image/jpeg',
    sld_body: sld
  },
  {
    unsupportedBrowsers: []
  }
);

Setting unsupportedBrowsers to an empty list is important! This list by default contains [“mozilla”, “firefox”, “opera”]. These browsers support long GET requests so the developers argued that these browsers wouldn’t need to use POST. Well, turns out that they do ;)

I performed a small stress test using an SLD with approximately 1,000 rules being applied on a big city road network. While my browser would willingly send a GET request of that size, Apache doesn’t want to accept it. So, I tried the POST way and it turns out that it really works! (But it’s slow, very slow …)

Thanks to the developers for yet another great feature!

[1] http://trac.openlayers.org/ticket/2224

Usually, I use CQL filter statements to dynamically filter features in a Geoserver WMS. These CQL filters can be added easily to the URL and Geoserver responds accordingly. There’s just one problem: There is a size limit for URLs and (very!) long filter statements won’t fit in. (And I’m not talking about the limit imposed by IE, but the more serious one in Apache.) This makes it necessary to switch from HTTP GET to POST. An easy way to send POST requests is using curl:

curl --data-binary @getMap.xml -H "Content-Type: text/xml" -o map.png "http://localhost:8080/geoserver/wms/GetMap"

I found that it’s important to use –data-binary to avoid that the text in getMap.xml is interpreted in any way. The “@” tells curl that a filename follows. Furthermore it’s necessary to specify the Content-Type. This results in the PNG map being stored in the current directory. My getMap.xml looks like follows:

<?xml version="1.0" encoding="UTF-8"?>
<ogc:GetMap
xmlns:ogc="http://www.opengis.net/ows"
xmlns:gml="http://www.opengis.net/gml"
version="1.1.1" service="WMS">

<StyledLayerDescriptor version="1.0.0">
<NamedLayer>
 <Name>myNs:roads</Name>
 <NamedStyle>
  <Name>simple_roads</Name>
 </NamedStyle>
</NamedLayer>
</StyledLayerDescriptor>

<BoundingBox srsName="http://www.opengis.net/gml/srs/epsg.xml#31287">
<gml:coord>
<gml:X>621005.1594799113</gml:X>
<gml:Y>471313.0306986364</gml:Y>
</gml:coord>
<gml:coord>
<gml:X>635174.7245025429</gml:X>
<gml:Y>484404.226939031</gml:Y>
</gml:coord>
</BoundingBox>

<Output>
 <Format>image/png</Format>
 <Size>
 <Width>600</Width>
 <Height>320</Height>
 </Size>
</Output>

<Exceptions>application/vnd.ogc.se+xml</Exceptions>

</ogc:GetMap>

It’s also pretty straightforward to add a filter to the NamedLayer element. Basically it can be copied from any SLD you have at hand.

Today I’ve been fighting again with how to get GetFeatureInfo working in my Geoserver, Apache, Tomcat environment. It’s pretty simple actually: One needs a proxy which I put in
/usr/lib/cgi-bin/proxy.cgi.

Proxy code can be found in OpenLayers-2.9/examples/proxy.cgi (Download the full package of OpenLayers and use it instead of the package that ships with Geoserver). Add all necessary hosts to allowedHosts list.

Don’t forget to set it executable:
sudo chmod +x /usr/lib/cgi-bin/proxy.cgi

To tell your website to use the proxy, add the following javascript line:
OpenLayers.ProxyHost = "/cgi-bin/proxy.cgi?url=";

%d bloggers like this: