Download - Scripting GeoServer with GeoScript

Transcript
Page 1: Scripting GeoServer with GeoScript

Scripting GeoServer with GeoScript

Justin Deoliveira and Tim Schaub

Page 2: Scripting GeoServer with GeoScript

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

GeoScript

Page 4: Scripting GeoServer with GeoScript

GeoScript

Page 5: Scripting GeoServer with 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

Page 6: Scripting GeoServer with GeoScript

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

GeoServer

Page 8: Scripting GeoServer with GeoScript

GeoServer

Page 9: Scripting GeoServer with GeoScript

Script Hooks - Data Formats

Data Formats• Drivers for spatial formats• Map to internal data model

Page 10: Scripting GeoServer with GeoScript

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

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

Script Hooks - Output Formats

Output Formats• Drivers for exchange formats• Map from internal data model

Page 13: Scripting GeoServer with GeoScript

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

Script Hooks - Process

Processes• Smarts of WPS• Simplicity of scripting

Page 15: Scripting GeoServer with GeoScript

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

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

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

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

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

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

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

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

Data Summary App

Demo

Page 24: Scripting GeoServer with GeoScript

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

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

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

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

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

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

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

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

Fusion Tables DataStore

Demo

Page 33: Scripting GeoServer with GeoScript

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

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

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

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

H2 Output Format

Demo

Page 38: Scripting GeoServer with GeoScript

Scripted WPS and WFS Transaction Hooks

Demo

Page 39: Scripting GeoServer with GeoScript

Thanks!

http://geoscript.orghttp://geoserver.org

Questions?