KEMBAR78
Scripting GeoServer | PDF
Scripting GeoServer
Jared Erickson
CUGOS
December 2012
GEOSERVER
Open Source (GPL) WMS Server
Main language is Java
Also implements WFS, WCS, WPS, ect...
Uses GeoTools and JTS libraries
Scripting Module
Geoserver Community Module
Developed by: Justin Deoliveira and Tim
Schaub
I am adding Geoscript Groovy support
https://github.com/jericks/geoserver/tree/script_groovy
Python, JavaScript, Groovy, BeanShell, Ruby
Uses javax.scripting to execute scripts
Extend GeoServer on the fly
Scripting Hooks
Applications
Web Processing Services (WPS)
Geospatial web services
Rendering Transformations in SLD
Filter Functions
String, Date, Geometry Functions in SLD
Script Location
$DATA_DIR/scripts/
apps
function
wps
lib
Scripts dynamically reloaded
Python, JavaScript, and Groovy have
GeoScript API
Applications
Generic web applications or web services
Python - WSGI
JavaScript - JSGI
Groovy - Restlet
Hello World App
1 import org.restlet.data.*
2
3 def run(request, response) {
4 response.setEntity("Groovy rocks!", MediaType.TEXT_PLAIN)
5 }
$DATA_DIR/scripts/apps/hello/main.groovy
Color Brewer App
1 import org.restlet.data.*
2 import org.restlet.resource.OutputRepresentation
3 import javax.imageio.ImageIO
4 import geoscript.filter.Color
5 import groovy.xml.MarkupBuilder
6
7 def run(request, response) {
8 String name = request.getResourceRef().getQueryAsForm().getFirstValue("name")
9 if (name) {
10 def image = Color.drawToImage(Color.getPaletteColors(name))
11 def output = new OutputRepresentation(MediaType.IMAGE_PNG) {
12 void write(OutputStream out) throws IOException {
13 ImageIO.write(image,"png",out)
14 }
15 }
16 response.setEntity(output)
17 }
18 else {
19 def out = new StringWriter()
20 def html = new MarkupBuilder(out)
21 html.html {
22 head {
23 title: "Color Brewer Palettes"
24 }
25 body {
26 h1 "Color Brewer Palettes"
27 ul {
28 Color.paletteNames.each { nm ->
29 li {
30 a href: "colorbrewer?name=${nm}", "${nm}"
31 }
32 }
33 }
34 }
35 }
36 response.setEntity(out.toString(), MediaType.TEXT_HTML)
37 }
38 }
$DATA_DIR/scripts/apps/colorbrewer/main.groovy
Color Brewer App
Function List app
1 import org.restlet.data.*
2 import geoscript.filter.Function
3 import groovy.xml.MarkupBuilder
4
5 def run(request, response) {
6 def out = new StringWriter()
7 def html = new MarkupBuilder(out)
8 html.html {
9 head {
10 titie: "Filter Functions"
11 }
12 body {
13 h1 "Filter Function"
14 ul {
15 Function.functionNames.each { nm ->
16 li "${nm}"
17 }
18 }
19 }
20 }
21 response.setEntity(out.toString(), MediaType.TEXT_HTML)
22
23 }
$DATA_DIR/scripts/apps/functions/main.groovy
Function List app
Groovy Geoserver API
geoserver
Geoserver: Main entry point for Catalog and Config
Config: Metadata about GeoServer
geoserver.catalog
Catalog: Contains Workspaces, Layers, Stores
Workspace: Contains Stores
Store: Contains Layers, Converts to GeoScript Workspace
Layer: Converts to GeoScript Layer
layer as table app
1 import org.restlet.data.*
2 import geoserver.*
3 import groovy.xml.MarkupBuilder
4
5 def run(request, response) {
6
7 def layer = new GeoServer().catalog.getLayer("sf:archsites")
8 def gsLayer = layer.geoScriptLayer
9
10 def out = new StringWriter()
11 def html = new MarkupBuilder(out)
12 html.html {
13 head {
14 title: "Layer Table"
15 }
16 body {
17 h1 "${layer.name}"
18 table(border:1) {
19 tr {
20 gsLayer.schema.fields.each {fld ->
21 td "${fld.name}"
22 }
23 }
24 gsLayer.eachFeature { f ->
25 tr {
26 f.attributes.each { att ->
27 td "${att.value}"
28 }
29 }
30 }
31 }
32 }
33 }
34 response.setEntity(out.toString(), MediaType.TEXT_HTML)
35 }
$DATA_DIR/scripts/apps/table/main.groovy
Layer as table app
Filter Functions
Transform a value before displaying it
Format a date or a number
Capitalize a string
Manipulate a geometry
GeoTools input objects are wrapped as
GeoScript objects
GeoScript result objects are unwrapped as
GeoTools objects
Filter Function
1 /**
2 * Convert a Geometry into a buffered centroid
3 * @param value The Feature
4 * @param args A List of arguments
5 * args[0] is the Geometry
6 * args[1] is the buffer distance
7 */
8 def run(value, args) {
9 args[0].centroid.buffer(args[1] as double)
10 }
$DATA_DIR/scripts/function/bufferCentroid.groovy
Geometry filter function
1 <?xml version="1.0" encoding="ISO-8859-1"?>
2 <StyledLayerDescriptor version="1.0.0"
3 xsi:schemaLocation="http://www.opengis.net/sld StyledLayerDescriptor.xsd"
4 xmlns="http://www.opengis.net/sld" xmlns:ogc="http://www.opengis.net/ogc"
5 xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
6 <NamedLayer>
7 <Name>Buffered Centroid</Name>
8 <UserStyle>
9 <Title>Buffered Centroids Polygons</Title>
10 <Abstract>Draw buffered centroids of polygons</Abstract>
11 <FeatureTypeStyle>
12 <Rule>
13 <Name>Rule 1</Name>
14 <Title>Gray Polygon with Black Outline</Title>
15 <Abstract>A polygon with a gray fill and a 1 pixel black outline</Abstract>
16 <PolygonSymbolizer>
17 <Geometry>
18 <ogc:Function name="bufferCentroid">
19 <ogc:PropertyName>the_geom</ogc:PropertyName>
20 <ogc:Literal>1</ogc:Literal>
21 </ogc:Function>
22 </Geometry>
23 <Fill>
24 <CssParameter name="fill">#AAAAAA</CssParameter>
25 </Fill>
26 <Stroke>
27 <CssParameter name="stroke">#000000</CssParameter>
28 <CssParameter name="stroke-width">1</CssParameter>
29 </Stroke>
30 </PolygonSymbolizer>
31 </Rule>
32 </FeatureTypeStyle>
33 </UserStyle>
34 </NamedLayer>
35 </StyledLayerDescriptor>
Geometry Filter Function
WPS
Web Processing Service
Model builder for the web
Generic web services for spatial data
GeoTools inputs are wrapped as GeoScript
objects
GeoScript results are unwrapped as GeoTools
objects
Geometry Buffer WPS
1 import geoscript.geom.Geometry
2
3 title = 'Buffer'
4 description = 'Buffers a geometry'
5
6 inputs = [
7 geom: [name: 'geom', title: 'The geometry to buffer', type: Geometry.class],
8 distance: [name: 'distance', title: 'The buffer distance', type: Double.class]
9 ]
10
11 outputs = [
12 result: [name: 'result', title: 'The buffered geometry', type: Geometry.class]
13 ]
14
15 def run(input) {
16 [result: input.geom.buffer(input.distance as double)]
17 }
18
$DATA_DIR/scripts/wps/buffer.groovy
WPS REQUEST BUILDER
Buffer geometry WPS
POLYGON ((11 1, 10.807852804032304 -0.9509032201612824, 10.238795325112868 -2.826834323650898, 9.314696123025453 -4.555702330196022, 8.071067811865476
-6.071067811865475, 6.555702330196023 -7.314696123025453, 4.826834323650898 -8.238795325112868, 2.9509032201612833 -8.807852804032304, 1.0000000000000007 -9,
-0.9509032201612819 -8.807852804032304, -2.826834323650897 -8.238795325112868, -4.55570233019602 -7.314696123025453, -6.071067811865475 -6.0710678118654755,
-7.314696123025453 -4.555702330196022, -8.238795325112868 -2.8268343236508944, -8.807852804032306 -0.9509032201612773, -9 1.0000000000000075,
-8.807852804032303 2.950903220161292, -8.238795325112862 4.826834323650909, -7.3146961230254455 6.555702330196034, -6.071067811865463 8.071067811865486,
-4.555702330196008 9.314696123025463, -2.826834323650879 10.238795325112875, -0.9509032201612606 10.807852804032308, 1.0000000000000249 11,
2.950903220161309 10.807852804032299, 4.826834323650925 10.238795325112857, 6.555702330196048 9.314696123025435, 8.071067811865499 8.07106781186545,
9.314696123025472 6.555702330195993, 10.238795325112882 4.826834323650862, 10.807852804032311 2.9509032201612437, 11 1))
http://localhost:8080/geoserver/wps?service=WPS
&version=1.0.0
&request=Execute
&identifier=groovy:buffer
&datainputs=geom=POINT%20(1%201)
@mimetype=application/wkt;distance=10
&RawDataOutput=result=@mimetype=application/wkt
Voronoi Layer WPS
1 import geoscript.geom.*
2 import geoscript.layer.*
3
4 title = 'VoronoiLayer'
5 description = 'Create a voronoi diagram around the features of a Layer'
6
7 inputs = [
8 layer: [name: 'layer', title: 'The Layer', type: Layer.class],
9 ]
10
11 outputs = [
12 result: [name: 'result', title: 'The voronoi diagram as a Layer', type: Layer.class]
13 ]
14
15 def run(input) {
16 def geoms = new GeometryCollection(input.layer.features*.geom.centroid)
17 def output = new Layer()
18 output.add([geoms.voronoiDiagram])
19 [result: output]
20 }
21
$DATA_DIR/scripts/wps/voronoi.groovy
WPS Request Builder
Rendering transformations
Modify an entire dataset
Buffer the entire layer not each feature
Create a heatmap from points (vector to raster)
http://docs.geoserver.org/latest/en/user/
styling/sld-extensions/rendering-
transform.html
Rendering Transform sld
1 <?xml version="1.0" encoding="ISO-8859-1"?>
2 <StyledLayerDescriptor version="1.0.0"
3 xsi:schemaLocation="http://www.opengis.net/sld StyledLayerDescriptor.xsd"
4 xmlns="http://www.opengis.net/sld"
5 xmlns:ogc="http://www.opengis.net/ogc"
6 xmlns:xlink="http://www.w3.org/1999/xlink"
7 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
8 <!-- a Named Layer is the basic building block of an SLD document -->
9 <NamedLayer>
10 <Name>default_polygon</Name>
11 <UserStyle>
12 <!-- Styles can have names, titles and abstracts -->
13 <Title>Default Polygon</Title>
14 <Abstract>A sample style that draws a polygon</Abstract>
15 <!-- FeatureTypeStyles describe how to render different features -->
16 <!-- A FeatureTypeStyle for rendering polygons -->
17 <FeatureTypeStyle>
18 <Transformation>
19 <ogc:Function name="groovy:voronoi">
20 <ogc:Function name="parameter">
21 <ogc:Literal>layer</ogc:Literal>
22 </ogc:Function>
23 </ogc:Function>
24 </Transformation>
25 <Rule>
26 <Name>rule1</Name>
27 <Title>Gray Polygon with Black Outline</Title>
28 <Abstract>A polygon with a gray fill and a 1 pixel black outline</Abstract>
29 <PolygonSymbolizer>
30 <Fill>
31 <CssParameter name="fill">#AAAAAA</CssParameter>
32 </Fill>
33 <Stroke>
34 <CssParameter name="stroke">#000000</CssParameter>
35 <CssParameter name="stroke-width">1</CssParameter>
36 </Stroke>
37 </PolygonSymbolizer>
38 </Rule>
39 </FeatureTypeStyle>
40 </UserStyle>
41 </NamedLayer>
42 </StyledLayerDescriptor>
43
Voronoi Diagram
Conclusion
GeoServer is well known as a WMS, WFS,
WCS, WPS server
GeoServer is also a platform for spatial web
services
Scripting just finally makes it easy
Thank you!

Scripting GeoServer

  • 1.
  • 2.
    GEOSERVER Open Source (GPL)WMS Server Main language is Java Also implements WFS, WCS, WPS, ect... Uses GeoTools and JTS libraries
  • 3.
    Scripting Module Geoserver CommunityModule Developed by: Justin Deoliveira and Tim Schaub I am adding Geoscript Groovy support https://github.com/jericks/geoserver/tree/script_groovy Python, JavaScript, Groovy, BeanShell, Ruby Uses javax.scripting to execute scripts Extend GeoServer on the fly
  • 4.
    Scripting Hooks Applications Web ProcessingServices (WPS) Geospatial web services Rendering Transformations in SLD Filter Functions String, Date, Geometry Functions in SLD
  • 5.
    Script Location $DATA_DIR/scripts/ apps function wps lib Scripts dynamicallyreloaded Python, JavaScript, and Groovy have GeoScript API
  • 6.
    Applications Generic web applicationsor web services Python - WSGI JavaScript - JSGI Groovy - Restlet
  • 7.
    Hello World App 1import org.restlet.data.* 2 3 def run(request, response) { 4 response.setEntity("Groovy rocks!", MediaType.TEXT_PLAIN) 5 } $DATA_DIR/scripts/apps/hello/main.groovy
  • 8.
    Color Brewer App 1import org.restlet.data.* 2 import org.restlet.resource.OutputRepresentation 3 import javax.imageio.ImageIO 4 import geoscript.filter.Color 5 import groovy.xml.MarkupBuilder 6 7 def run(request, response) { 8 String name = request.getResourceRef().getQueryAsForm().getFirstValue("name") 9 if (name) { 10 def image = Color.drawToImage(Color.getPaletteColors(name)) 11 def output = new OutputRepresentation(MediaType.IMAGE_PNG) { 12 void write(OutputStream out) throws IOException { 13 ImageIO.write(image,"png",out) 14 } 15 } 16 response.setEntity(output) 17 } 18 else { 19 def out = new StringWriter() 20 def html = new MarkupBuilder(out) 21 html.html { 22 head { 23 title: "Color Brewer Palettes" 24 } 25 body { 26 h1 "Color Brewer Palettes" 27 ul { 28 Color.paletteNames.each { nm -> 29 li { 30 a href: "colorbrewer?name=${nm}", "${nm}" 31 } 32 } 33 } 34 } 35 } 36 response.setEntity(out.toString(), MediaType.TEXT_HTML) 37 } 38 } $DATA_DIR/scripts/apps/colorbrewer/main.groovy
  • 9.
  • 10.
    Function List app 1import org.restlet.data.* 2 import geoscript.filter.Function 3 import groovy.xml.MarkupBuilder 4 5 def run(request, response) { 6 def out = new StringWriter() 7 def html = new MarkupBuilder(out) 8 html.html { 9 head { 10 titie: "Filter Functions" 11 } 12 body { 13 h1 "Filter Function" 14 ul { 15 Function.functionNames.each { nm -> 16 li "${nm}" 17 } 18 } 19 } 20 } 21 response.setEntity(out.toString(), MediaType.TEXT_HTML) 22 23 } $DATA_DIR/scripts/apps/functions/main.groovy
  • 11.
  • 12.
    Groovy Geoserver API geoserver Geoserver:Main entry point for Catalog and Config Config: Metadata about GeoServer geoserver.catalog Catalog: Contains Workspaces, Layers, Stores Workspace: Contains Stores Store: Contains Layers, Converts to GeoScript Workspace Layer: Converts to GeoScript Layer
  • 13.
    layer as tableapp 1 import org.restlet.data.* 2 import geoserver.* 3 import groovy.xml.MarkupBuilder 4 5 def run(request, response) { 6 7 def layer = new GeoServer().catalog.getLayer("sf:archsites") 8 def gsLayer = layer.geoScriptLayer 9 10 def out = new StringWriter() 11 def html = new MarkupBuilder(out) 12 html.html { 13 head { 14 title: "Layer Table" 15 } 16 body { 17 h1 "${layer.name}" 18 table(border:1) { 19 tr { 20 gsLayer.schema.fields.each {fld -> 21 td "${fld.name}" 22 } 23 } 24 gsLayer.eachFeature { f -> 25 tr { 26 f.attributes.each { att -> 27 td "${att.value}" 28 } 29 } 30 } 31 } 32 } 33 } 34 response.setEntity(out.toString(), MediaType.TEXT_HTML) 35 } $DATA_DIR/scripts/apps/table/main.groovy
  • 14.
  • 15.
    Filter Functions Transform avalue before displaying it Format a date or a number Capitalize a string Manipulate a geometry GeoTools input objects are wrapped as GeoScript objects GeoScript result objects are unwrapped as GeoTools objects
  • 16.
    Filter Function 1 /** 2* Convert a Geometry into a buffered centroid 3 * @param value The Feature 4 * @param args A List of arguments 5 * args[0] is the Geometry 6 * args[1] is the buffer distance 7 */ 8 def run(value, args) { 9 args[0].centroid.buffer(args[1] as double) 10 } $DATA_DIR/scripts/function/bufferCentroid.groovy
  • 17.
    Geometry filter function 1<?xml version="1.0" encoding="ISO-8859-1"?> 2 <StyledLayerDescriptor version="1.0.0" 3 xsi:schemaLocation="http://www.opengis.net/sld StyledLayerDescriptor.xsd" 4 xmlns="http://www.opengis.net/sld" xmlns:ogc="http://www.opengis.net/ogc" 5 xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 6 <NamedLayer> 7 <Name>Buffered Centroid</Name> 8 <UserStyle> 9 <Title>Buffered Centroids Polygons</Title> 10 <Abstract>Draw buffered centroids of polygons</Abstract> 11 <FeatureTypeStyle> 12 <Rule> 13 <Name>Rule 1</Name> 14 <Title>Gray Polygon with Black Outline</Title> 15 <Abstract>A polygon with a gray fill and a 1 pixel black outline</Abstract> 16 <PolygonSymbolizer> 17 <Geometry> 18 <ogc:Function name="bufferCentroid"> 19 <ogc:PropertyName>the_geom</ogc:PropertyName> 20 <ogc:Literal>1</ogc:Literal> 21 </ogc:Function> 22 </Geometry> 23 <Fill> 24 <CssParameter name="fill">#AAAAAA</CssParameter> 25 </Fill> 26 <Stroke> 27 <CssParameter name="stroke">#000000</CssParameter> 28 <CssParameter name="stroke-width">1</CssParameter> 29 </Stroke> 30 </PolygonSymbolizer> 31 </Rule> 32 </FeatureTypeStyle> 33 </UserStyle> 34 </NamedLayer> 35 </StyledLayerDescriptor>
  • 18.
  • 19.
    WPS Web Processing Service Modelbuilder for the web Generic web services for spatial data GeoTools inputs are wrapped as GeoScript objects GeoScript results are unwrapped as GeoTools objects
  • 20.
    Geometry Buffer WPS 1import geoscript.geom.Geometry 2 3 title = 'Buffer' 4 description = 'Buffers a geometry' 5 6 inputs = [ 7 geom: [name: 'geom', title: 'The geometry to buffer', type: Geometry.class], 8 distance: [name: 'distance', title: 'The buffer distance', type: Double.class] 9 ] 10 11 outputs = [ 12 result: [name: 'result', title: 'The buffered geometry', type: Geometry.class] 13 ] 14 15 def run(input) { 16 [result: input.geom.buffer(input.distance as double)] 17 } 18 $DATA_DIR/scripts/wps/buffer.groovy
  • 21.
  • 22.
    Buffer geometry WPS POLYGON((11 1, 10.807852804032304 -0.9509032201612824, 10.238795325112868 -2.826834323650898, 9.314696123025453 -4.555702330196022, 8.071067811865476 -6.071067811865475, 6.555702330196023 -7.314696123025453, 4.826834323650898 -8.238795325112868, 2.9509032201612833 -8.807852804032304, 1.0000000000000007 -9, -0.9509032201612819 -8.807852804032304, -2.826834323650897 -8.238795325112868, -4.55570233019602 -7.314696123025453, -6.071067811865475 -6.0710678118654755, -7.314696123025453 -4.555702330196022, -8.238795325112868 -2.8268343236508944, -8.807852804032306 -0.9509032201612773, -9 1.0000000000000075, -8.807852804032303 2.950903220161292, -8.238795325112862 4.826834323650909, -7.3146961230254455 6.555702330196034, -6.071067811865463 8.071067811865486, -4.555702330196008 9.314696123025463, -2.826834323650879 10.238795325112875, -0.9509032201612606 10.807852804032308, 1.0000000000000249 11, 2.950903220161309 10.807852804032299, 4.826834323650925 10.238795325112857, 6.555702330196048 9.314696123025435, 8.071067811865499 8.07106781186545, 9.314696123025472 6.555702330195993, 10.238795325112882 4.826834323650862, 10.807852804032311 2.9509032201612437, 11 1)) http://localhost:8080/geoserver/wps?service=WPS &version=1.0.0 &request=Execute &identifier=groovy:buffer &datainputs=geom=POINT%20(1%201) @mimetype=application/wkt;distance=10 &RawDataOutput=result=@mimetype=application/wkt
  • 23.
    Voronoi Layer WPS 1import geoscript.geom.* 2 import geoscript.layer.* 3 4 title = 'VoronoiLayer' 5 description = 'Create a voronoi diagram around the features of a Layer' 6 7 inputs = [ 8 layer: [name: 'layer', title: 'The Layer', type: Layer.class], 9 ] 10 11 outputs = [ 12 result: [name: 'result', title: 'The voronoi diagram as a Layer', type: Layer.class] 13 ] 14 15 def run(input) { 16 def geoms = new GeometryCollection(input.layer.features*.geom.centroid) 17 def output = new Layer() 18 output.add([geoms.voronoiDiagram]) 19 [result: output] 20 } 21 $DATA_DIR/scripts/wps/voronoi.groovy
  • 24.
  • 25.
    Rendering transformations Modify anentire dataset Buffer the entire layer not each feature Create a heatmap from points (vector to raster) http://docs.geoserver.org/latest/en/user/ styling/sld-extensions/rendering- transform.html
  • 26.
    Rendering Transform sld 1<?xml version="1.0" encoding="ISO-8859-1"?> 2 <StyledLayerDescriptor version="1.0.0" 3 xsi:schemaLocation="http://www.opengis.net/sld StyledLayerDescriptor.xsd" 4 xmlns="http://www.opengis.net/sld" 5 xmlns:ogc="http://www.opengis.net/ogc" 6 xmlns:xlink="http://www.w3.org/1999/xlink" 7 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 8 <!-- a Named Layer is the basic building block of an SLD document --> 9 <NamedLayer> 10 <Name>default_polygon</Name> 11 <UserStyle> 12 <!-- Styles can have names, titles and abstracts --> 13 <Title>Default Polygon</Title> 14 <Abstract>A sample style that draws a polygon</Abstract> 15 <!-- FeatureTypeStyles describe how to render different features --> 16 <!-- A FeatureTypeStyle for rendering polygons --> 17 <FeatureTypeStyle> 18 <Transformation> 19 <ogc:Function name="groovy:voronoi"> 20 <ogc:Function name="parameter"> 21 <ogc:Literal>layer</ogc:Literal> 22 </ogc:Function> 23 </ogc:Function> 24 </Transformation> 25 <Rule> 26 <Name>rule1</Name> 27 <Title>Gray Polygon with Black Outline</Title> 28 <Abstract>A polygon with a gray fill and a 1 pixel black outline</Abstract> 29 <PolygonSymbolizer> 30 <Fill> 31 <CssParameter name="fill">#AAAAAA</CssParameter> 32 </Fill> 33 <Stroke> 34 <CssParameter name="stroke">#000000</CssParameter> 35 <CssParameter name="stroke-width">1</CssParameter> 36 </Stroke> 37 </PolygonSymbolizer> 38 </Rule> 39 </FeatureTypeStyle> 40 </UserStyle> 41 </NamedLayer> 42 </StyledLayerDescriptor> 43
  • 27.
  • 28.
    Conclusion GeoServer is wellknown as a WMS, WFS, WCS, WPS server GeoServer is also a platform for spatial web services Scripting just finally makes it easy
  • 29.