scripting geoserver with geoscript
DESCRIPTION
GeoServer is a solid and mature implementation of a variety of OGC services including Web Feature Service, Web Map Service, Web Coverage Service, and Web Processing Service. Add to this a KML engine, integrated security framework, powerful styling language with SLD and this rich feature set makes GeoServer very appealing to the user. However it has always been somewhat lacking when it comes to the developer. Developing with GeoServer has a steep learning curve and requires expert knowledge to do simple tasks like writing new output formats, implementing new WPS processes, and adding custom filter functions. GeoScript to the rescue!GeoScript adds spatial capabilities to popular languages such as Python, JavaScript, Scala, and Groovy. Scripting languages are the perfect tool for developers who want to do simple coding tasks quickly in a lightweight development environment. GeoScript builds on top of the very powerful GeoTools library to provide an interface to its capabilities though concise and easy to use API's. Recent extensions to GeoServer now allow developers to write components and plug-ins in the scripting language of their choice, using GeoScript as the engine for spatial functionality.This presentation is geared toward developers who are interested in developing with GeoServer but not necessarily ready to get their hands dirty with low level Java. The talk will detail the various scripting hooks available and provide examples, complete with code, of how to write some simple plug-ins. Check out this presentation and you'll be developing with GeoServer in no time.TRANSCRIPT
![Page 1: Scripting GeoServer with GeoScript](https://reader033.vdocument.in/reader033/viewer/2022061616/554fc798b4c9050e7d8b510c/html5/thumbnails/1.jpg)
Scripting GeoServer with GeoScript
Justin Deoliveira and Tim Schaub
![Page 2: Scripting GeoServer with GeoScript](https://reader033.vdocument.in/reader033/viewer/2022061616/554fc798b4c9050e7d8b510c/html5/thumbnails/2.jpg)
GeoScript?
• Spatial capabilities for scripting languageso Groovyo JavaScripto Pythono Scala
• Higher level api for GeoToolso Convenient, concise, completeo Make easy things easy
• Faster development turnaroundo No recompilation/rebuilding
![Page 3: Scripting GeoServer with GeoScript](https://reader033.vdocument.in/reader033/viewer/2022061616/554fc798b4c9050e7d8b510c/html5/thumbnails/3.jpg)
GeoScript
![Page 4: Scripting GeoServer with GeoScript](https://reader033.vdocument.in/reader033/viewer/2022061616/554fc798b4c9050e7d8b510c/html5/thumbnails/4.jpg)
GeoScript
![Page 5: Scripting GeoServer with GeoScript](https://reader033.vdocument.in/reader033/viewer/2022061616/554fc798b4c9050e7d8b510c/html5/thumbnails/5.jpg)
GeoScript...import org.geotools.data.DataStore;import org.geotools.data.postgis.PostgisNGDataStoreFactory;import org.geotools.feature.FeatureCollection;import org.geotools.feature.FeatureIterator;import org.geotools.jdbc.JDBCDataStoreFactory;import org.opengis.feature.Feature;...
Map<String,Serializable> params = new HashMap<String, Serializable>();params.put(JDBCDataStoreFactory.HOST.key, "localhost");params.put(JDBCDataStoreFactory.PORT.key, 5432);params.put(JDBCDataStoreFactory.DATABASE.key, "geoscript");params.put(JDBCDataStoreFactory.DBTYPE.key, "postgis");params.put(JDBCDataStoreFactory.USER.key, "jdeolive");PostgisNGDataStoreFactory factory = new PostgisNGDataStoreFactory();DataStore pg = factory.createDataStore(params); FeatureCollection features = pg.getFeatureSource("states").getFeatures();FeatureIterator it = features.features();try { while(it.hasNext()) { Feature f = it.next(); System.out.println(f.getProperty("STATE_NAME").getValue()); }}finally { it.close();}
Java
![Page 6: Scripting GeoServer with GeoScript](https://reader033.vdocument.in/reader033/viewer/2022061616/554fc798b4c9050e7d8b510c/html5/thumbnails/6.jpg)
GeoScript
from geoscript.workspace import PostGIS
pg = PostGIS('geoscript')for f in pg['states'].features(): print f['STATE_NAME']
Python
JavaScript
var PostGIS = require("geoscript/workspace").PostGIS;
var pg = PostGIS("geoscript");pg.get("states").features.forEach(function(f) { print(f.get("STATE_NAME"));});
![Page 7: Scripting GeoServer with GeoScript](https://reader033.vdocument.in/reader033/viewer/2022061616/554fc798b4c9050e7d8b510c/html5/thumbnails/7.jpg)
GeoServer
![Page 8: Scripting GeoServer with GeoScript](https://reader033.vdocument.in/reader033/viewer/2022061616/554fc798b4c9050e7d8b510c/html5/thumbnails/8.jpg)
GeoServer
![Page 9: Scripting GeoServer with GeoScript](https://reader033.vdocument.in/reader033/viewer/2022061616/554fc798b4c9050e7d8b510c/html5/thumbnails/9.jpg)
Script Hooks - Data Formats
Data Formats• Drivers for spatial formats• Map to internal data model
![Page 10: Scripting GeoServer with GeoScript](https://reader033.vdocument.in/reader033/viewer/2022061616/554fc798b4c9050e7d8b510c/html5/thumbnails/10.jpg)
Script Hooks - Data Formats
from geoserver import datastorefrom geoscript.layer import readJSON
class GeoJSON(object):
@datastore('GeoJSON', 'GeoJSON', file=('GeoJSON file', str)) def __init__(self, file): self.json = readJSON(file)
def layers(self): return [self.json.name]
def get(self, layer): return self.json
GeoJSON DataStore
![Page 11: Scripting GeoServer with GeoScript](https://reader033.vdocument.in/reader033/viewer/2022061616/554fc798b4c9050e7d8b510c/html5/thumbnails/11.jpg)
Script Hooks - Data Formats
from geoserver import datastorefrom geoscript.layer import readJSON
class GeoJSON(object):
@datastore('GeoJSON', 'GeoJSON', file=('GeoJSON file', str)) def __init__(self, file): self.json = readJSON(file)
def layers(self): return [self.json.name]
def get(self, layer): return self.json
GeoJSON DataStore
![Page 12: Scripting GeoServer with GeoScript](https://reader033.vdocument.in/reader033/viewer/2022061616/554fc798b4c9050e7d8b510c/html5/thumbnails/12.jpg)
Script Hooks - Output Formats
Output Formats• Drivers for exchange formats• Map from internal data model
![Page 13: Scripting GeoServer with GeoScript](https://reader033.vdocument.in/reader033/viewer/2022061616/554fc798b4c9050e7d8b510c/html5/thumbnails/13.jpg)
Script Hooks - Output Formats
from geoserver.format import vector_format
@vector_format('property', 'text/plain')def write(data, out): for f in data.features: values = [str(val) for val in f.values()] out.write('%s=%s\n' % (f.id, '|'.join(values))
Property File Format
states.1=MULTIPOLYGON (((37.51 -88.07, ... 37.51 -88.07)))|Illinoisstates.2=MULTIPOLYGON (((38.97 -77.00, ... 38.97 -77.01)))|District of Columbiastates.3=MULTIPOLYGON (((38.56 -75.71, ... 38.56 -75.71)))|Delawarestates.4=MULTIPOLYGON (((38.48 -79.23, ... 38.48 -79.23)))|West Virginia . . .
.../wfs?request=GetFeature&typename=topp:states&outputformat=property
![Page 14: Scripting GeoServer with GeoScript](https://reader033.vdocument.in/reader033/viewer/2022061616/554fc798b4c9050e7d8b510c/html5/thumbnails/14.jpg)
Script Hooks - Process
Processes• Smarts of WPS• Simplicity of scripting
![Page 15: Scripting GeoServer with GeoScript](https://reader033.vdocument.in/reader033/viewer/2022061616/554fc798b4c9050e7d8b510c/html5/thumbnails/15.jpg)
Script Hooks - Processvar 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" }, distance: { type: "Double", title: "Buffer Distance" } }, outputs: { result: { type: "Geometry", title: "Result" } }, run: function(inputs) { return {result: inputs.geom.buffer(inputs.distance)}; }});
JavaScript
![Page 16: Scripting GeoServer with GeoScript](https://reader033.vdocument.in/reader033/viewer/2022061616/554fc798b4c9050e7d8b510c/html5/thumbnails/16.jpg)
Script Hooks - Filter Functions
Filter Functions• Filtering for WFS and WMS• Callable via SLD
from geosever.filter import functionfrom geoscript.geom import Polygon@functiondef areaGreaterThan(feature, area): return feature.geom.area > area
Area Function
![Page 17: Scripting GeoServer with GeoScript](https://reader033.vdocument.in/reader033/viewer/2022061616/554fc798b4c9050e7d8b510c/html5/thumbnails/17.jpg)
Script Hooks - Transactions
exports.beforeCommit = function(details, request) { LOGGER.info("beforeCommit"); var records = details["PreInsert"] || []; records.forEach(function(record) { var feature = record.feature; feature.geometry = feature.geometry.simplify(10); });
};
JavaScript
Intercept WFS transactions with a wfs.js script in your data directory.
![Page 18: Scripting GeoServer with GeoScript](https://reader033.vdocument.in/reader033/viewer/2022061616/554fc798b4c9050e7d8b510c/html5/thumbnails/18.jpg)
Script Hooks - Web/HTTP
"apps"• Simple WGSI-like environment• Access to catalog/data
def app(environ, start_response): start_response('200 OK', [('Content-type','text/plain')]) return 'Hello world!'
Hello World App
![Page 19: Scripting GeoServer with GeoScript](https://reader033.vdocument.in/reader033/viewer/2022061616/554fc798b4c9050e7d8b510c/html5/thumbnails/19.jpg)
Data Summary Appfrom geoserver.catalog import Layerfrom StringIO import StringIO
def app(env, start_response): kvp = dict([tuple(kv.split('=')) for kv in env['QUERY_STRING'].split('&')]) layer = kvp['layer'] l = Layer(layer, store=None)
buf = StringIO() buf.write('Layer: %s\n' % l.name)
data = l.data buf.write(' Format: %s\n' % data.format) buf.write(' Feature count: %d\n' % data.count()) buf.write(' CRS/Projection: %s\n' % data.proj.wkt)
b = data.bounds() buf.write(' Bounds: (%f,%f,%f,%f)\n' % (b.west, b.south, b.east, b.north))
buf.write(' Fields:\n') buf.write('\n'.join([' %s' % repr(fld) for fld in data.schema.fields])) buf.write('\n')
start_response('200 OK', [('Content-type','text/plain')]) return buf.getvalue()
![Page 20: Scripting GeoServer with GeoScript](https://reader033.vdocument.in/reader033/viewer/2022061616/554fc798b4c9050e7d8b510c/html5/thumbnails/20.jpg)
Data Summary Appfrom geoserver.catalog import Layerfrom StringIO import StringIO
def app(env, start_response): kvp = dict([tuple(kv.split('=')) for kv in env['QUERY_STRING'].split('&')]) layer = kvp['layer'] l = Layer(layer, store=None)
buf = StringIO() buf.write('Layer: %s\n' % l.name)
data = l.data buf.write(' Format: %s\n' % data.format) buf.write(' Feature count: %d\n' % data.count()) buf.write(' CRS/Projection: %s\n' % data.proj.wkt)
b = data.bounds() buf.write(' Bounds: (%f,%f,%f,%f)\n' % (b.west, b.south, b.east, b.north))
buf.write(' Fields:\n') buf.write('\n'.join([' %s' % repr(fld) for fld in data.schema.fields])) buf.write('\n')
start_response('200 OK', [('Content-type','text/plain')]) return buf.getvalue()
![Page 21: Scripting GeoServer with GeoScript](https://reader033.vdocument.in/reader033/viewer/2022061616/554fc798b4c9050e7d8b510c/html5/thumbnails/21.jpg)
Data Summary Appfrom geoserver.catalog import Layerfrom StringIO import StringIO
def app(env, start_response): kvp = dict([tuple(kv.split('=')) for kv in env['QUERY_STRING'].split('&')]) layer = kvp['layer'] l = Layer(layer, store=None)
buf = StringIO() buf.write('Layer: %s\n' % l.name)
data = l.data buf.write(' Format: %s\n' % data.format) buf.write(' Feature count: %d\n' % data.count()) buf.write(' CRS/Projection: %s\n' % data.proj.wkt)
b = data.bounds() buf.write(' Bounds: (%f,%f,%f,%f)\n' % (b.west, b.south, b.east, b.north))
buf.write(' Fields:\n') buf.write('\n'.join([' %s' % repr(fld) for fld in data.schema.fields])) buf.write('\n')
start_response('200 OK', [('Content-type','text/plain')]) return buf.getvalue()
![Page 22: Scripting GeoServer with GeoScript](https://reader033.vdocument.in/reader033/viewer/2022061616/554fc798b4c9050e7d8b510c/html5/thumbnails/22.jpg)
Data Summary Appfrom geoserver.catalog import Layerfrom StringIO import StringIO
def app(env, start_response): kvp = dict([tuple(kv.split('=')) for kv in env['QUERY_STRING'].split('&')]) layer = kvp['layer'] l = Layer(layer, store=None)
buf = StringIO() buf.write('Layer: %s\n' % l.name)
data = l.data buf.write(' Format: %s\n' % data.format) buf.write(' Feature count: %d\n' % data.count()) buf.write(' CRS/Projection: %s\n' % data.proj.wkt)
b = data.bounds() buf.write(' Bounds: (%f,%f,%f,%f)\n' % (b.west, b.south, b.east, b.north))
buf.write(' Fields:\n') buf.write('\n'.join([' %s' % repr(fld) for fld in data.schema.fields])) buf.write('\n')
start_response('200 OK', [('Content-type','text/plain')]) return buf.getvalue()
![Page 23: Scripting GeoServer with GeoScript](https://reader033.vdocument.in/reader033/viewer/2022061616/554fc798b4c9050e7d8b510c/html5/thumbnails/23.jpg)
Data Summary App
Demo
![Page 24: Scripting GeoServer with GeoScript](https://reader033.vdocument.in/reader033/viewer/2022061616/554fc798b4c9050e7d8b510c/html5/thumbnails/24.jpg)
Fusion Tables DataStore
class GFT(object):
@datastore('GFT', 'Google Fusion Tables', user=('User email', str), passwd=('Password', str)) def __init__(self, user, passwd): token = ClientLogin().authorize(user, passwd) self.ft = ftclient.ClientLoginFTClient(token)
def layers(self): return [tbl.name for tbl in self.tables()] def get(self, layer): try: return Layer(filter(lambda t: t.name == layer, self.tables())[0]) except IndexError: raise Exception('No table named %s' % layer)
def tables(self): tables = self.ft.query(SQL().showTables()) return [Table(self,*row.split(',')) for row in tables.split('\n')[1:-1]]
![Page 25: Scripting GeoServer with GeoScript](https://reader033.vdocument.in/reader033/viewer/2022061616/554fc798b4c9050e7d8b510c/html5/thumbnails/25.jpg)
Fusion Tables DataStore
class GFT(object):
@datastore('GFT', 'Google Fusion Tables', user=('User email', str), passwd=('Password', str)) def __init__(self, user, passwd): token = ClientLogin().authorize(user, passwd) self.ft = ftclient.ClientLoginFTClient(token)
def layers(self): return [tbl.name for tbl in self.tables()] def get(self, layer): try: return Layer(filter(lambda t: t.name == layer, self.tables())[0]) except IndexError: raise Exception('No table named %s' % layer)
def tables(self): tables = self.ft.query(SQL().showTables()) return [Table(self,*row.split(',')) for row in tables.split('\n')[1:-1]]
![Page 26: Scripting GeoServer with GeoScript](https://reader033.vdocument.in/reader033/viewer/2022061616/554fc798b4c9050e7d8b510c/html5/thumbnails/26.jpg)
Fusion Tables DataStore
class GFT(object):
@datastore('GFT', 'Google Fusion Tables', user=('User email', str), passwd=('Password', str)) def __init__(self, user, passwd): token = ClientLogin().authorize(user, passwd) self.ft = ftclient.ClientLoginFTClient(token)
def layers(self): return [tbl.name for tbl in self.tables()] def get(self, layer): try: return Layer(filter(lambda t: t.name == layer, self.tables())[0]) except IndexError: raise Exception('No table named %s' % layer)
def tables(self): tables = self.ft.query(SQL().showTables()) return [Table(self,*row.split(',')) for row in tables.split('\n')[1:-1]]
![Page 27: Scripting GeoServer with GeoScript](https://reader033.vdocument.in/reader033/viewer/2022061616/554fc798b4c9050e7d8b510c/html5/thumbnails/27.jpg)
Fusion Tables DataStore
class GFT(object):
@datastore('GFT', 'Google Fusion Tables', user=('User email', str), passwd=('Password', str)) def __init__(self, user, passwd): token = ClientLogin().authorize(user, passwd) self.ft = ftclient.ClientLoginFTClient(token)
def layers(self): return [tbl.name for tbl in self.tables()] def get(self, layer): try: return Layer(filter(lambda t: t.name == layer, self.tables())[0]) except IndexError: raise Exception('No table named %s' % layer)
def tables(self): tables = self.ft.query(SQL().showTables()) return [Table(self,*row.split(',')) for row in tables.split('\n')[1:-1]]
![Page 28: Scripting GeoServer with GeoScript](https://reader033.vdocument.in/reader033/viewer/2022061616/554fc798b4c9050e7d8b510c/html5/thumbnails/28.jpg)
Fusion Tables DataStore
__types = {'string':str, 'number': float, 'location':Geometry}
class Layer(object):
def __init__(self, tbl): self.tbl = tbl self.name = tbl.name self.workspace = tbl.gft
self.proj = Projection('epsg:4326') self.schema = Schema(tbl.name, [(col[0], __types[col[1]]) for col in tbl.schema()])
def bounds(self): return reduce(lambda x,y: x.expand(y.bounds), self.features(), Bounds())
def features(self): ...
![Page 29: Scripting GeoServer with GeoScript](https://reader033.vdocument.in/reader033/viewer/2022061616/554fc798b4c9050e7d8b510c/html5/thumbnails/29.jpg)
Fusion Tables DataStore
__types = {'string':str, 'number': float, 'location':Geometry}
class Layer(object):
def __init__(self, tbl): self.tbl = tbl self.name = tbl.name self.workspace = tbl.gft
self.proj = Projection('epsg:4326') self.schema = Schema(tbl.name, [(col[0], __types[col[1]]) for col in tbl.schema()])
def bounds(self): return reduce(lambda x,y: x.expand(y.bounds), self.features(), Bounds())
def features(self): ...
![Page 30: Scripting GeoServer with GeoScript](https://reader033.vdocument.in/reader033/viewer/2022061616/554fc798b4c9050e7d8b510c/html5/thumbnails/30.jpg)
Fusion Tables DataStore
__types = {'string':str, 'number': float, 'location':Geometry}
class Layer(object):
def __init__(self, tbl): self.tbl = tbl self.name = tbl.name self.workspace = tbl.gft
self.proj = Projection('epsg:4326') self.schema = Schema(tbl.name, [(col[0], __types[col[1]]) for col in tbl.schema()])
def bounds(self): return reduce(lambda x,y: x.expand(y.bounds), self.features(), Bounds())
def features(self): ...
![Page 31: Scripting GeoServer with GeoScript](https://reader033.vdocument.in/reader033/viewer/2022061616/554fc798b4c9050e7d8b510c/html5/thumbnails/31.jpg)
Fusion Tables DataStore
class Layer(object):
...
def features(self): rows = self.tbl.gft.ft.query(SQL().select(self.tbl.id)) rows = rows.split('\n')[1:-1]
for row in rows: vals = csv.reader([row]).next() atts = [] for i in range(0, len(vals)): val = vals[i] fld = self.schema.get(i) if issubclass(fld.typ, Geometry): val = readKML(val) atts.append(val) yield Feature(atts, schema=self.schema)
![Page 32: Scripting GeoServer with GeoScript](https://reader033.vdocument.in/reader033/viewer/2022061616/554fc798b4c9050e7d8b510c/html5/thumbnails/32.jpg)
Fusion Tables DataStore
Demo
![Page 33: Scripting GeoServer with GeoScript](https://reader033.vdocument.in/reader033/viewer/2022061616/554fc798b4c9050e7d8b510c/html5/thumbnails/33.jpg)
H2 Output Format@vector_format('h2', 'application/zip')def write(data, out): dir = tempfile.mkdtemp()
# create the database and copy the features into it db = H2(data.schema.name, dir=dir) layer = db.create(schema=data.schema) for f in data.features: layer.add(f) db.close()
# zip and ship file = tempfile.mktemp() zip = zipfile.ZipFile(file, 'w') for root, dirs, files in os.walk(dir): name = abspath(root)[len(abspath(dir)):] for f in files: zip.write(join(root,f), join(name,f), zipfile.ZIP_DEFLATED) zip.close()
shutil.copyfileobj(open(file, 'r'), out)
# clean up os.remove(file) shutil.rmtree(dir)
![Page 34: Scripting GeoServer with GeoScript](https://reader033.vdocument.in/reader033/viewer/2022061616/554fc798b4c9050e7d8b510c/html5/thumbnails/34.jpg)
H2 Output Format@vector_format('h2', 'application/zip')def write(data, out): dir = tempfile.mkdtemp()
# create the database and copy the features into it db = H2(data.schema.name, dir=dir) layer = db.create(schema=data.schema) for f in data.features: layer.add(f) db.close()
# zip and ship file = tempfile.mktemp() zip = zipfile.ZipFile(file, 'w') for root, dirs, files in os.walk(dir): name = abspath(root)[len(abspath(dir)):] for f in files: zip.write(join(root,f), join(name,f), zipfile.ZIP_DEFLATED) zip.close()
shutil.copyfileobj(open(file, 'r'), out)
# clean up os.remove(file) shutil.rmtree(dir)
![Page 35: Scripting GeoServer with GeoScript](https://reader033.vdocument.in/reader033/viewer/2022061616/554fc798b4c9050e7d8b510c/html5/thumbnails/35.jpg)
H2 Output Format@vector_format('h2', 'application/zip')def write(data, out): dir = tempfile.mkdtemp()
# create the database and copy the features into it db = H2(data.schema.name, dir=dir) layer = db.create(schema=data.schema) for f in data.features: layer.add(f) db.close()
# zip and ship file = tempfile.mktemp() zip = zipfile.ZipFile(file, 'w') for root, dirs, files in os.walk(dir): name = abspath(root)[len(abspath(dir)):] for f in files: zip.write(join(root,f), join(name,f), zipfile.ZIP_DEFLATED) zip.close()
shutil.copyfileobj(open(file, 'r'), out)
# clean up os.remove(file) shutil.rmtree(dir)
![Page 36: Scripting GeoServer with GeoScript](https://reader033.vdocument.in/reader033/viewer/2022061616/554fc798b4c9050e7d8b510c/html5/thumbnails/36.jpg)
H2 Output Format@vector_format('h2', 'application/zip')def write(data, out): dir = tempfile.mkdtemp()
# create the database and copy the features into it db = H2(data.schema.name, dir=dir) layer = db.create(schema=data.schema) for f in data.features: layer.add(f) db.close()
# zip and ship file = tempfile.mktemp() zip = zipfile.ZipFile(file, 'w') for root, dirs, files in os.walk(dir): name = abspath(root)[len(abspath(dir)):] for f in files: zip.write(join(root,f), join(name,f), zipfile.ZIP_DEFLATED) zip.close()
shutil.copyfileobj(open(file, 'r'), out)
# clean up os.remove(file) shutil.rmtree(dir)
![Page 37: Scripting GeoServer with GeoScript](https://reader033.vdocument.in/reader033/viewer/2022061616/554fc798b4c9050e7d8b510c/html5/thumbnails/37.jpg)
H2 Output Format
Demo
![Page 38: Scripting GeoServer with GeoScript](https://reader033.vdocument.in/reader033/viewer/2022061616/554fc798b4c9050e7d8b510c/html5/thumbnails/38.jpg)
Scripted WPS and WFS Transaction Hooks
Demo
![Page 39: Scripting GeoServer with GeoScript](https://reader033.vdocument.in/reader033/viewer/2022061616/554fc798b4c9050e7d8b510c/html5/thumbnails/39.jpg)
Thanks!
http://geoscript.orghttp://geoserver.org
Questions?