The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Geo::OGC::Service - Perl extension for geospatial web services

SYNOPSIS

In a service.psgi file write something like this

  use strict;
  use warnings;
  use Plack::Builder;
  use Geo::OGC::Service;
  use Geo::OGC::Service::XXX;
  my $server = Geo::OGC::Service->new({
      config => '/var/www/etc/test.conf',
      services => {
          XXX => 'Geo::OGC::Service::XXX',
      }
  });
  builder {
      mount "/XXX" => $server->to_app;
      mount "/" => $default_app;
  };

The bones of a service class are

  package Geo::OGC::Service::XXX;
  sub process_request {
    my ($self, $responder) = @_;
    my $writer = $responder->([200, [ 'Content-Type' => 'text/plain',
                                      'Content-Encoding' => 'UTF-8' ]]);
    $writer->write("I'm ok!");
    $writer->close;
  }

Geo::OGC::Service::WFS exists in the CPAN and Geo::OGC::Service::WMTS will be there real soon now.

DESCRIPTION

Geo::OGC::Service is a subclass of Plack::Component and a middleware between a web client and an actual content providing service object. A Geo::OGC::Service object has a to_app method for booting a web service.

A Geo::OGC::Service object creates a specialized service object as a result of a web service request. The specialized service object is a hash reference blessed into an appropriate class (the class is deduced from GET parameter, POSTed service name, or from the script name in the case of RESTful services). The new object contains keys env, request, plugin, config, service, and optionally posted, filter, and parameters.

env

The PSGI $env.

request

A Plack::Request object constructed from the $env;

plugin

The plugin object given as an argument to Geo::OGC::Service in its constructor as a top level attribute or as a service specific attribute.

config

The constructed configuration for the web service.

service

The name of the requested service.

parameters

A hash made from Plack::Request->parameters (thus removing its multi value nature). The keys are all converted to lower case and the values are decoded to Perl's internal format assuming they are in the encoding defined $request->content_encoding (or UTF-8).

posted

A XML::LibXML documentElement of the POSTed XML. The XML is decoded into Perl's internal format.

filter

A XML::LibXML documentElement contructed from a filter GET parameter. The XML is decoded into Perl's internal format.

SERVICE CONFIGURATION

Setting up a PSGI service consists typically of three things:

1) write a service.psgi file (see above) and put it somewhere like

   /var/www/service/service.psgi 

2) Set up starman service and add to its init-file line something like

   exec starman --daemonize --error-log /var/log/starman/log --l localhost:5000 /var/www/service/service.psgi

3) Add a proxy service to your httpd configuration. For Apache it would be something like this:

   <Location /Service>
     ProxyPass http://localhost:5000
     ProxyPassReverse http://localhost:5000
   </Location>

Setting up a geospatial web service through this module requires a configuration file, for example

/var/www/etc/service.conf

(make sure this file is not served by your httpd)

The configuration must be in JSON format. I.e., something like

  {
    Common: {
        "CORS": {
                "Allow-Origin" : "*",
                "Allow-Headers" : "Content-Type, X-Requested-With"
        },
        "Content-Type": "text/xml; charset=utf-8",
        "TARGET_NAMESPACE": "http://ogr.maptools.org/"
    },
    WFS: {
        "resource": "http://$HTTP_HOST/WFS",
        "version": "1.1.0",
        "TARGET_NAMESPACE": "http://ogr.maptools.org/",
        "PREFIX": "ogr",
        "Transaction": "Insert,Update,Delete",
        "FeatureTypeList": [
            {
            }
        ]
    },
    "WMS": {
        "resource": "http://$HTTP_HOST/WMS"
    },
    "TMS": {
        "resource": "http://$HTTP_HOST/TMS"
    },
    "WMTS": {
        "resource": "http://$HTTP_HOST/WMTS"
    },
    "TileSets": [
    ],
    "BoundingBox3857": {
        "SRS": "EPSG:3857",
        "minx": 2399767,
        "miny": 8645741,
        "maxx": 2473612,
        "maxy": 8688005
    }
  }

The keys and structure of this file depend on the type of the service(s) you are setting up. "CORS" is the only one that is recognized by this module. "CORS" is either a string denoting the allowed origin or a hash of "Allow-Origin", "Allow-Methods", "Allow-Headers", and "Max-Age".

$HTTP_HOST and $SCRIPT_NAME are replaced in runtime to the HTTP_HOST and SCRIPT_NAME values respectively in the environment given by Plack.

EXPORT

None by default.

METHODS

new

This creates a new Geo::OGC::Service app. You need to call it in the psgi file as a class method with a named parameter hash reference. The parameters are

  config, services

config is required and it is a path to a file or a reference to an anonymous hash containing the configuration for the services. The top level keys are service names. If it is a file, it is expected to be JSON. A configuration in a file may use top level Common hash and references. A reference is a key,value pair, where the value begins with 'ref:/' followed by a top level key name. The Common block is cloned and references are solved and cloned into each service configuration.

services is a reference to a hash of service names associated with names of classes, which will process service requests. The key of the hash is the requested service.

call

This method is called internally by the method to_app of Plack::Component. The method fails unless this module is running in a psgi.streaming environment. Otherwise, it returns a subroutine, which calls the respond method.

respond

This method is called for each request from the Internet. The call is responded during the execution of the subroutine.

In the default case this method constructs a new service object using the method 'service' and calls its process_request method with PSGI style $responder object as a parameter.

This subroutine may fail while interpreting the request, or while processing the request.

service

This method does a preliminary interpretation of the request and converts it into a service object, which is returned.

The returned service object contains

  config => the configuration for this type of service
  env => the PSGI environment

and may contain

  plugin => plugin object

  posted => XML::LibXML DOM document element of the posted data
  filter => XML::LibXML DOM document element of the filter
  parameters => hash of rquest parameters obtained from Plack::Request

config is the service specific part of the config given to this Geo::OGC::Service object in its constructor, possibly worked to clone the Common block and references. The service should treat it strictly read-only as it is shared between workers.

plugin is the plugin object that was given to this Geo::OGC::Service object in its constructor.

Note: all keys in request parameters are converted to lower case in parameters.

This subroutine may fail due to a request for an unknown service. The error is reported as an XML message using OGC conventions.

error($responder, $msg)

Stream an error report as an XML message of type

  <?xml version="1.0" encoding="UTF-8"?>
  <ExceptionReport>
      <Exception exceptionCode="$msg->{exceptionCode}" locator="$msg->{locator}">
          <ExceptionText>$msg->{ExceptionText}<ExceptionText>
      <Exception>
  </ExceptionReport>

Geo::OGC::Service::Common

A base type for all OGC services.

SYNOPSIS

  $service->DescribeService($writer);
  $service->Operation($writer, $operation, $protocols, $parameters);

DESCRIPTION

The class contains methods for common tasks for all services.

METHODS

CORS

Return the CORS headers as a list according to the configuration. CORS may be in the configuration as a scalar or as a hash. A scalar value is taken as a value for Access-Control-Allow-Origin. A hash may have the following keys. (Note the missing prefix Access-Control-.)

      key                      default value
  -----------------  ----------------------------------
  Allow-Origin              
  Allow-Credentials
  Expose-Headers
  Max-Age                        60*60*24
  Allow-Methods                  GET,POST
  Allow-Headers    origin,x-requested-with,content-type

DescribeService($writer)

Create ows:ServiceIdentification and ows:ServiceProvider elements.

Operation($writer, $operation, $protocols, $parameters)

Create ows:Operation element and its ows:DCP and ows:Parameter sub elements.

Geo::OGC::Service::XMLWriter

A helper class for writing XML.

SYNOPSIS

  my $writer = Geo::OGC::Service::XMLWriter::Caching->new();
  $writer->open_element(
        'wfs:WFS_Capabilities', 
        { 'xmlns:gml' => "http://www.opengis.net/gml" });
  $writer->element('ows:ServiceProvider',
                     [['ows:ProviderName'],
                      ['ows:ProviderSite', {'xlink:type'=>"simple", 'xlink:href'=>""}],
                      ['ows:ServiceContact']]);
  $writer->close_element;
  $writer->stream($responder);

or

  my $writer = Geo::OGC::Service::XMLWriter::Streaming->new($responder);
  $writer->prolog;
  $writer->open_element('MyXML');
  while (a long time) {
      $writer->element('MyElement');
  }
  $writer->close_element;
  # $writer is closed when it goes out of scope

DESCRIPTION

The classes Geo::OGC::Service::XMLWriter (abstract), Geo::OGC::Service::XMLWriter::Streaming (concrete), and Geo::OGC::Service::XMLWriter::Caching (concrete) are provided as a convenience for writing XML to the client.

The element method has the syntax

  $writer->element($tag[, $attributes][, $content])

or

  $writer->element($element)

where $element is a reference to an array [$tag[, $attributes][, $content]].

$attributes is a reference to a hash

$content is nothing, undef, '/>', plain content (string), an element (as above), a list of elements, or a reference to a list of elements. If there is no $content or $content is undef, a self-closing tag is written. If $content is '/>' a closing tag is written.

Setting $tag to 0 or 1, allows writing plain content.

If $attribute{$key} is undefined the attribute is not written at all.

Geo::OGC::Service::XMLWriter::Streaming

A helper class for writing XML into a stream.

SYNOPSIS

  my $w = Geo::OGC::Service::XMLWriter::Streaming($responder, $headers, $declaration);

Using $w as XMLWriter sets writer, which is obtained from $responder, to write XML. The writer is closed when $w is destroyed.

$headers and $declaration are optional. The defaults are 'Content-Type' => 'text/xml; charset=utf-8' and '<?xml version="1.0" encoding="UTF-8"?>'.

Geo::OGC::Service::XMLWriter::Caching

A helper class for writing XML into a cache.

SYNOPSIS

 my $w = Geo::OGC::Service::XMLWriter::Caching($headers, $declaration);
 $w->stream($responder);

Using $w to produce XML caches the XML. The cached XML can be written by a writer obtained from a $responder.

$headers and $declaration are optional. The defaults are as in Geo::OGC::Service::XMLWriter::Streaming.

SEE ALSO

Discuss this module on the Geo-perl email list.

https://list.hut.fi/mailman/listinfo/geo-perl

For PSGI/Plack see

http://plackperl.org/

REPOSITORY

https://github.com/ajolma/Geo-OGC-Service

AUTHOR

Ari Jolma, <ari.jolma at gmail.com>

COPYRIGHT AND LICENSE

Copyright (C) 2015- by Ari Jolma

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.22.0 or, at your option, any later version of Perl 5 you may have available.