package org.geoserver.python.datastore;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.geoserver.platform.FileWatcher;
import org.geoserver.python.Python;
import org.geotools.data.DataStoreFactorySpi;
import org.geotools.data.Parameter;
import org.geotools.data.DataAccessFactory.Param;
import org.python.core.Py;
import org.python.core.PyDictionary;
import org.python.core.PyException;
import org.python.core.PyFunction;
import org.python.core.PyList;
import org.python.core.PyNone;
import org.python.core.PyObject;
import org.python.core.PySequence;
import org.python.core.PyStringMap;
import org.python.core.PyType;
import org.python.util.PythonInterpreter;
public class PythonDataStoreAdapter {
Python py;
FileWatcher<PyType> fw;
PyType type;
public PythonDataStoreAdapter(File file, Python py) {
this.py = py;
fw = new FileWatcher<PyType>(file) {
@Override
protected PyType parseFileContents(InputStream in) throws IOException {
PythonInterpreter pi = PythonDataStoreAdapter.this.py.interpreter();
pi.execfile(in);
PyStringMap locals = (PyStringMap) pi.getLocals();
for (Object obj : locals.values()) {
if (obj instanceof PyType) {
PyType pobj = (PyType) obj;
try {
PyObject init = pobj.__getattr__("__init__");
if (init != null) {
if (init.__getattr__("__datastore__") != null) {
return (PyType) pobj;
}
}
}
catch(PyException e) {}
}
}
return null;
}
};
}
public String getTitle() {
return type().__getattr__("__init__").__getattr__("title").toString();
}
public String getDescription() {
PyObject desc = type().__getattr__("__init__").__getattr__("description");
if (desc.getType() == PyNone.TYPE) {
return getTitle();
}
return desc.toString();
}
public List<Param> getParameters() {
PyType type = type();
PythonInterpreter pi = py.interpreter();
pi.exec("from inspect import getargspec");
PyFunction getargspec = (PyFunction) pi.get("getargspec");
PyObject init = type.__getattr__("__init__");
PySequence argspec =
(PySequence) getargspec.__call__(init.__getattr__("wrapped")).__getitem__(0);
PyDictionary params = (PyDictionary) init.__getattr__("params");
List<Param> list = new ArrayList();
for (Object item : (Collection) argspec) {
String pname = item.toString();
if ("self".equals(pname)) continue;
PySequence pinfo = (PySequence) params.get(pname);
String pdesc = pinfo != null ? pinfo.__getitem__(0).toString() : pname;
Object ptype = null;
try {
ptype = pinfo != null ? pinfo.__getitem__(1) : null;
}
catch(PyException e) {}
Class clazz = null;
if (ptype != null && ptype instanceof PyType) {
clazz = Python.toJavaClass((PyType)ptype);
}
if (clazz == null) {
clazz = Object.class;
}
Map metadata = null;
if ("passwd".equalsIgnoreCase(pname) || "password".equalsIgnoreCase(pname)) {
metadata = Collections.singletonMap(Parameter.IS_PASSWORD, true);
}
list.add(new Param(pname, clazz, pdesc, true, null, metadata ));
}
return list;
}
public DataStoreFactorySpi getDataStoreFactory() {
return new PythonDataStoreFactory(this);
}
public PythonDataStore getDataStore(Map<String,Object> parameters) throws IOException {
return new PythonDataStore(parameters, this);
}
PyObject getWorkspace(Map<String,Object> parameters) {
List<PyObject> args = new ArrayList();
List<String> kw = new ArrayList();
int i = 0;
for (Map.Entry<String,Object> e : parameters.entrySet()) {
if (PythonDataStoreFactory.TYPE.key.equals(e.getKey()))
continue;
args.add(Py.java2py(e.getValue()));
kw.add(e.getKey());
}
return type().__call__(args.toArray(new PyObject[args.size()]),
kw.toArray(new String[kw.size()]));
}
PyType type() {
if (fw.isModified()) {
synchronized(this) {
if (fw.isModified()) {
try {
type = fw.read();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
return type;
}
}