Scripting GeoServer with GeoScript
-
Upload
justin-deoliveira -
Category
Technology
-
view
4.105 -
download
6
description
Transcript of Scripting GeoServer with GeoScript
Scripting GeoServer with GeoScript
Justin Deoliveira and Tim Schaub
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
GeoScript
GeoScript
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
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"));});
GeoServer
GeoServer
Script Hooks - Data Formats
Data Formats• Drivers for spatial formats• Map to internal data model
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
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
Script Hooks - Output Formats
Output Formats• Drivers for exchange formats• Map from internal data model
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
Script Hooks - Process
Processes• Smarts of WPS• Simplicity of scripting
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
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
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.
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
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()
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()
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()
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()
Data Summary App
Demo
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]]
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]]
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]]
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]]
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): ...
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): ...
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): ...
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)
Fusion Tables DataStore
Demo
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)
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)
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)
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)
H2 Output Format
Demo
Scripted WPS and WFS Transaction Hooks
Demo
Thanks!
http://geoscript.orghttp://geoserver.org
Questions?