Scripting Hooks¶
This page describes all available scripting hooks. Every hook listed on this page is implemented by all the supported language extensions. However, depending on the language, the interfaces and api used to write a script may differ. Continue reading for more details.
Applications¶
The “app” hook provides a way to contribute scripts that are intended to be run over http.
An app corresponds to a named directory under the scripts/apps
directory. For example:
GEOSERVER_DATA_DIR/
...
scripts/
apps/
hello/
An app directory must contain a main file that contains the “entry point” into the application. Every time the app is invoked via an http request this main file is executed.
The contains of the main file differ depending on the language. The default for all languages is simply that the main file contain a function named “run” that takes two arguments, the http request and response. For example, in beanshell:
import org.restlet.data.*;
run(request,response) {
response.setEntity("Hello World!", MediaType.TEXT_PLAIN);
}
As explained above this api can differ depending on the language. For example in Python we have the well defined WSGI specification that gives us a standard interface for Python web development. The equivalent Python script to that above is:
def app(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/plain')])
return ['Hello World!']
For the JavaScript app hook, scripts are expected to export an app
function that
conforms to the JSGI specification (v0.3).
The equivalent ‘Hello World’ app in JavaScript would look like the following
(in /scripts/apps/hello/main.js
):
exports.app = function(request) {
return {
status: 200,
headers: {"Content-Type": "text/plain"},
body: ["Hello World"]
}
};
Applications are http accessible at the path /script/apps/{app}
where {app}
is the name of the application. For example assuming a local GeoServer the url for
for the application would be:
http://localhost:8080/geoserver/script/apps/hello
Warning
Because of security risks the path will not be accessible if the default admin password has not been changed.
Web Processing Service¶
The wps hook provides a way to provides a way to contribute scripts runnable as a WPS process. The process is invoked using the standard WPS protocol the same way an existing well-known process would be.
All processes are located under the scripts/wps
directory. Each process is
located in a file named for the process. For example:
GEOSERVER_DATA_DIR/
...
scripts/
wps/
buffer.bsh
The process will be exposed using the extension as the namespace prefix, and the file name as
the process name, for example, the above process will show up as bsh:buffer
.
It is also possible to put scripts in subdirectories of script/wps
, in this case the directory name
will be used as the process namespace, for example:
GEOSERVER_DATA_DIR/
...
scripts/
wps/
foo/
buffer.bsh
will expose the process as foo:buffer
.
A process script must define two things:
- The process metadata: title, description, inputs, and outputs
- The process routine itself
The default for languages is to define the metadata as global variables in the script and the process routine as a function named “run”. For example, in groovy:
import com.vividsolutions.jts.geom.Geometry
title = 'Buffer'
description = 'Buffers a geometry'
inputs = [
geom: [name: 'geom', title: 'The geometry to buffer', type: Geometry.class],
distance: [name: 'distance', title: 'The buffer distance', type: Double.class]
]
outputs = [
result: [name: 'result', title: 'The buffered geometry', type: Geometry.class]
]
def run(input) {
return [result: input.geom.buffer(input.distance)]
}
In Python the api is slightly different and makes use of Python decorators:
from geoserver.wps import process
from com.vividsolutions.jts.geom import Geometry
@process(
title='Buffer',
description='Buffers a geometry',
inputs={
'geom': (Geometry, 'The geometry to buffer'),
'distance':(float,'The buffer distance')
},
outputs={
'result': (Geometry, 'The buffered geometry')
}
)
def run(geom, distance):
return geom.buffer(distance);
In JavaScript, a script exports a process
object (see the
GeoScript JS API docs for more detail)
in order to be exposed as a WPS process. The following is an example of a simple
buffer process (saved in scripts/wps/buffer.js
):
var Process = require("geoscript/process").Process;
exports.process = new Process({
title: "JavaScript Buffer Process",
description: "Process that buffers a geometry.",
inputs: {
geom: {
type: "Geometry",
title: "Input Geometry",
description: "The target geometry."
},
distance: {
type: "Double",
title: "Buffer Distance",
description: "The distance by which to buffer the geometry."
}
},
outputs: {
result: {
type: "Geometry",
title: "Result",
description: "The buffered geometry."
}
},
run: function(inputs) {
return {result: inputs.geom.buffer(inputs.distance)};
}
});
Once implemented a process is invoked using the standard WPS protocol. For example assuming a local GeoServer the url to execute the process would be:
http://localhost:8080/geoserver/wps
?service=WPS
&version=1.0.0
&request=Execute
&identifier=XX:buffer
&datainputs=geom=POINT(0 0)@mimetype=application/wkt;distance=10
(Substitue XX:buffer
for the script name followed by the extension. E.g.
py:buffer
for Python or js:buffer
for JavaScript.)
Filter Functions¶
The Filter Functions hook provides a way to create new Filter Function. These functions may be used, for example, in WFS/WMS filtering or in SLD expressions, for more information about Filter Functions see Filter functions. GeoServer already provides many built in functions, for a complete list see Filter Function Reference.
All created functions are located under the scripts/function
directory. For creating
new functions use Scripting Web User Interface or place directly function file in scripts/function
directory, for example, to create a function named camelcase
using the python language create file
scripts/function/camelcase.py
.
The contains of the function file differ depending on the language. The default for all languages is simply that the function file contains a function named “run”. For example, in python:
def run(value, args):
return ''.join(x for x in args[0].title() if not x.isspace())
The filter function name equals the function file name, for example, if there is scripts/function/camelcase.py
file then it can be used in SLD like this:
...
<TextSymbolizer>
<Label>
<ogc:Function name="camelcase">
<ogc:PropertyName>STATE_NAME</ogc:PropertyName>
</ogc:Function>
</Label>
...
</TextSymbolizer>
...
WFS Transactions¶
WFS Transactions hook provides a way one can intercept WFS Transactions. It could be used, for example, to add validation or fill some attributes based on other ones.
All created WFS Transactions hooks are located under the scripts/wfs/tx
directory. For creating
new functions use Scripting Web User Interface or place file directly in scripts/wfs/tx
directory. The file name
does not matter in WFS Transaction hook.
To intercept transaction one should declare a method with name specific to transaction phase, for example,
to manipulate data before update use preUpdate
. Available methods in python are:
from geoserver.wfs import tx
def before(req, context):
context['before'] = True
def preInsert(inserted, req, context):
context['preInsert'] = True
def postInsert(inserted, req, context):
context['postInsert'] = True
def preUpdate(updated, props, req, context):
context['preUpdate'] = True
def postUpdate(updated, props, req, context):
context['postUpdate'] = True
def preDelete(deleted, req, context):
context['preDelete'] = True
def postDelete(deleted, req, context):
context['postDelete'] = True
def preCommit(req, context):
context['preCommit'] = True
def postCommit(req, res, context):
context['postCommit'] = True
def abort(req, res, context):
context['abort'] = True
For example, to disallow feature deleting in python, create script:
from org.geoserver.wfs import WFSException
def preDelete(deleted, req, context):
raise WFSException("It is not allowed to delete Features in this layer!")