package org.geoserver.python.datastore; import java.io.IOException; import org.geotools.data.FeatureReader; import org.geotools.data.FeatureWriter; import org.geotools.data.Query; import org.geotools.data.simple.SimpleFeatureSource; import org.geotools.data.simple.SimpleFeatureStore; import org.geotools.data.store.ContentEntry; import org.geotools.data.store.ContentFeatureSource; import org.geotools.data.store.ContentFeatureStore; import org.geotools.feature.simple.SimpleFeatureTypeBuilder; import org.geotools.filter.text.cql2.CQL; import org.geotools.geometry.jts.ReferencedEnvelope; import org.opengis.feature.simple.SimpleFeature; import org.opengis.feature.simple.SimpleFeatureType; import org.opengis.filter.Filter; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.python.core.PyInstance; import org.python.core.PyJavaType; import org.python.core.PyList; import org.python.core.PyMethod; import org.python.core.PyObject; import org.python.core.PyString; import org.python.core.PyType; public class PythonFeatureStore extends ContentFeatureSource implements SimpleFeatureSource { PyObject layer; PyObject schema; public PythonFeatureStore(ContentEntry entry, Query query) { super(entry, query); PythonDataStore dataStore = (PythonDataStore) entry.getDataStore(); PyObject workspace = dataStore.getWorkspace(); PyMethod get = (PyMethod) workspace.__findattr__("get"); if (get == null) { get = (PyMethod) workspace.__findattr__("__getitem__"); } this.layer = get.__call__(new PyObject[]{new PyString(entry.getName().getLocalPart())}); this.schema = layer.__findattr__("schema"); } @Override protected SimpleFeatureType buildFeatureType() throws IOException { SimpleFeatureTypeBuilder tb = new SimpleFeatureTypeBuilder(); tb.setName(((PyString)schema.__findattr__("name")).asString()); PyObject proj = schema.__findattr__("proj"); if (proj != null) { CoordinateReferenceSystem crs = (CoordinateReferenceSystem) proj.__getattr__("_crs").__tojava__(CoordinateReferenceSystem.class); if (crs != null) { tb.setCRS(crs); } } PyList fields = (PyList) schema.__findattr__("fields"); for (Object o : fields.toArray()) { PyObject field = (PyObject) o; String name = ((PyString)field.__findattr__("name")).asString(); PyType type = (PyType)field.__findattr__("typ"); Class clazz = (Class) type.__tojava__(Object.class); tb.add(name, unwrapClass(clazz)); } return tb.buildFeatureType(); } Class unwrapClass(Class clazz) { if (PyString.class.isAssignableFrom(clazz)) { return String.class; } return clazz; } @Override protected ReferencedEnvelope getBoundsInternal(Query query) throws IOException { PyMethod bounds = (PyMethod) layer.__findattr__("bounds"); PyObject filter = convertFilter(query.getFilter()); PyObject result = bounds.__call__(filter != null ? new PyObject[]{filter} : new PyObject[]{}); //do not return the actual envelope synce it is a python object return new ReferencedEnvelope((ReferencedEnvelope) result.__tojava__(ReferencedEnvelope.class)); } @Override protected int getCountInternal(Query query) throws IOException { PyMethod count = (PyMethod) layer.__findattr__("count"); PyObject filter = convertFilter(query.getFilter()); PyObject result = count.__call__(filter != null ? new PyObject[]{filter} : new PyObject[]{}); return (Integer) result.__tojava__(Integer.class); } @Override protected FeatureReader<SimpleFeatureType, SimpleFeature> getReaderInternal(Query query) throws IOException { return new PythonFeatureReader(getSchema(), layer); } PyObject convertFilter(Filter f) { PyString filter = null; if (f != Filter.INCLUDE) { //TODO: figure out how to pass filter object in directly filter = new PyString(CQL.toCQL(f)); } return filter; } }