org.integratedmodelling.engine.modelling.kbox.ObservationKbox2 Maven / Gradle / Ivy
The newest version!
package org.integratedmodelling.engine.modelling.kbox;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.h2gis.utilities.SpatialResultSet;
import org.integratedmodelling.api.engine.IModelingEngine;
import org.integratedmodelling.api.knowledge.IConcept;
import org.integratedmodelling.api.knowledge.IObservation;
import org.integratedmodelling.api.modelling.IModel;
import org.integratedmodelling.api.modelling.resolution.IResolutionScope;
import org.integratedmodelling.api.monitoring.IMonitor;
import org.integratedmodelling.api.space.ISpatialExtent;
import org.integratedmodelling.api.time.ITemporalExtent;
import org.integratedmodelling.common.beans.Model;
import org.integratedmodelling.common.beans.Observation;
import org.integratedmodelling.common.beans.requests.ObservationQuery;
import org.integratedmodelling.common.configuration.KLAB;
import org.integratedmodelling.common.model.Models;
import org.integratedmodelling.common.space.IGeometricShape;
import org.integratedmodelling.common.utils.Escape;
import org.integratedmodelling.engine.kbox.sql.SQL;
import org.integratedmodelling.engine.kbox.sql.h2.H2Kbox;
import org.integratedmodelling.engine.kbox.sql.h2.schema.CompoundSchema;
import org.integratedmodelling.engine.modelling.resolver.ResolutionScope;
import org.integratedmodelling.exceptions.KlabException;
import org.integratedmodelling.exceptions.KlabRuntimeException;
import com.vividsolutions.jts.geom.Geometry;
public class ObservationKbox2 extends ObservableKbox {
private static ObservationKbox2 _this;
private boolean workRemotely = false;
public static ObservationKbox2 get() {
if (_this == null) {
H2Kbox.set("observations2_"
+ KBOX_VERSION, new ObservationKbox2("observations2_" + KBOX_VERSION, KLAB.ENGINE
.getMonitor()));
_this = (ObservationKbox2) H2Kbox.get("observations2_" + KBOX_VERSION);
}
return _this;
}
private ObservationKbox2(String name, IMonitor monitor) {
super(name, monitor);
setSchema(Observation.class, new CompoundSchema(Observation.class) {
@Override
public String getTableName() {
return getMainTableId();
}
@Override
public String getCreateSQL() {
String ret = "CREATE TABLE observation ("
+ "oid LONG, "
+ "serverid VARCHAR(64), "
+ "id VARCHAR(256), "
+ "name VARCHAR(256), "
+ "namespaceid VARCHAR(128), "
+ "projectid VARCHAR(128), "
+ "typeid LONG, "
+ "otypeid LONG, "
+ "isprivate BOOLEAN, "
+ "isresolved BOOLEAN, "
+ "isreification BOOLEAN, "
+ "inscenario BOOLEAN, "
+ "hasdirectobjects BOOLEAN, "
+ "hasdirectdata BOOLEAN, "
+ "timestart LONG, "
+ "timeend LONG, "
+ "isspatial BOOLEAN, "
+ "istemporal BOOLEAN, "
+ "timemultiplicity LONG, "
+ "spacemultiplicity LONG, "
+ "scalemultiplicity LONG, "
+ "dereifyingattribute VARCHAR(256), "
+ "space GEOMETRY, "
+ "); "
+ "CREATE INDEX model_oid_index ON model(oid); "
+ "CREATE SPATIAL INDEX model_space ON model(space);";
return ret;
}
});
setSerializer(Observation.class, new Serializer() {
private String cn(Object o) {
return o == null ? "" : o.toString();
}
@Override
public String serialize(Observation model, Schema schema, long primaryKey, long foreignKey) {
// long tid = requireConceptId(model.getObservableConcept());
// long oid = requireConceptId(model.getObservationConcept());
String ret = "INSERT INTO observation VALUES ("
+ primaryKey + ", "
// + "'" + cn(model.getServerId()) + "', "
// + "'" + cn(model.getId()) + "', "
// + "'" + cn(model.getName()) + "', "
// + "'" + cn(model.getNamespaceId()) + "', "
// + "'" + cn(model.getProjectId()) + "', "
// + tid + ", "
// + oid + ", "
// + (model.isPrivateModel() ? "TRUE" : "FALSE") + ", "
// + (model.isResolved() ? "TRUE" : "FALSE") + ", "
// + (model.isReification() ? "TRUE" : "FALSE") + ", "
// + (model.isInScenario() ? "TRUE" : "FALSE") + ", "
// + (model.isHasDirectObjects() ? "TRUE" : "FALSE") + ", "
// + (model.isHasDirectData() ? "TRUE" : "FALSE") + ", "
// + model.getTimeStart() + ", "
// + model.getTimeEnd() + ", "
// + (model.isSpatial() ? "TRUE" : "FALSE") + ", "
// + (model.isTemporal() ? "TRUE" : "FALSE") + ", "
// + model.getTimeMultiplicity() + ", "
// + model.getSpaceMultiplicity() + ", "
// + model.getScaleMultiplicity() + ", "
// + "'" + cn(model.getDereifyingAttribute()) + "', "
// + "'"
// + (model.getShape() == null
// ? "GEOMETRYCOLLECTION EMPTY"
// : model.getShape().getStandardizedGeometry().toString())
// + "'"
+ ");";
if (model.getMetadata() != null && model.getMetadata().getData().size() > 0) {
storeMetadataFor(primaryKey, model.getMetadata());
}
return ret;
}
});
}
/**
* Pass the output of queryModelData to a contextual prioritizer and return the ranked
* list of IModels. If we're a personal engine, also broadcast the query to the
* network and merge results before returning.
*
* @param observable
* @param context
* @return models resulting from query, best first.
* @throws KlabException
*/
public List query(IConcept observable, IResolutionScope context)
throws KlabException {
//
// IModelPrioritizer prioritizer = context.getPrioritizer2();
// ModelQueryResult ret = new ModelQueryResult(prioritizer, ((ResolutionScope)
// context).getMonitor());
Set local = new HashSet<>();
ObservationQueryResult ret = new ObservationQueryResult(((ResolutionScope) context).getMonitor());
/*
* only query locally if we've seen a model before.
*/
if (database.hasTable("observation")) {
for (Observation md : queryObservations(observable, context)) {
local.add(md);
ret.addObservationBean(md);
}
}
/**
* If we're a modeling engine, dispatch the request to all nodes that allow it,
* which we do simply by using the result list as a distributed operation.
*/
if (KLAB.ENGINE instanceof IModelingEngine && workRemotely) {
ObservationQuery mquery = new ObservationQuery();
mquery.setObservable(KLAB.MFACTORY
.adapt(observable, org.integratedmodelling.common.beans.Observable.class));
mquery.setContext(KLAB.MFACTORY.adapt(context, org.integratedmodelling.common.beans.Scope.class));
KLAB.ENGINE.getNetwork().broadcast(ret, ((ResolutionScope) context).getMonitor());
}
return ret;
}
/**
* Find and deserialize all modeldata matching the parameters. Do not rank or
* anything.
*
* @param observable
* @param context
* @throws KlabException
*/
public List queryObservations(IConcept observable, IResolutionScope context)
throws KlabException {
List ret = new ArrayList<>();
if (!database.hasTable("observation")) {
return ret;
}
String query = "SELECT observation.oid FROM observation WHERE ";
String typequery = observableQuery(observable, context);
if (typequery == null) {
return ret;
}
query += "(" + scopeQuery(context, observable) + ")";
query += " AND (" + typequery + ")";
if (context.getScale().getSpace() != null) {
String sq = spaceQuery(context.getScale().getSpace());
if (!sq.isEmpty()) {
query += " AND (" + sq + ")";
}
}
String tquery = timeQuery(context.getScale().getTime());
if (!tquery.isEmpty()) {
query += " AND (" + tquery + ");";
}
KLAB.info(query);
final List oids = database.queryIds(query);
for (long l : oids) {
Observation model = retrieveModel(l);
if (model != null) {
ret.add(model);
} else {
KLAB.warn("kbox is out of sync with knowledge base");
}
}
// KLAB.info(KLAB.ENGINE.getName() + ": model query for "
// + (context.isForInstantiation() ? "instantiation of " : "explanation of ") +
// observable
// + " found "
// + (ret.size() == 1 ? ret.get(0).getName() : (ret.size() + " models")));
return ret;
}
private String observableQuery(IConcept observable, IResolutionScope context) {
Set ids = this.getCompatibleTypeIds(observable, context);
if (ids == null || ids.size() == 0) {
return null;
}
String ret = "";
for (long id : ids) {
ret += (ret.isEmpty() ? "" : ", ") + id;
}
return "typeid IN (" + ret + ")";
}
/*
* select models that are [instantiators if required] AND:] [private and in the home
* namespace if not dummy OR] (non-private and non-scenario) OR (in any of the
* scenarios in the context).
*/
private String scopeQuery(IResolutionScope context, IConcept observable) {
String ret = "";
String namespaceId = context.getResolutionNamespace() == null ? DUMMY_NAMESPACE_ID
: context.getResolutionNamespace().getId();
if (!namespaceId.equals(DUMMY_NAMESPACE_ID)) {
// ret += "(observation.isprivate AND observation.namespaceid = '" + namespaceId
// + "')";
ret += "(observation.namespaceid = '" + namespaceId + "')";
}
ret += (ret.isEmpty() ? "" : " OR ") + "((NOT observation.isprivate) AND (NOT observation.inscenario))";
if (context.getScenarios() != null && context.getScenarios().size() > 0) {
ret += " OR (" + joinStringConditions("observation.namespaceid", context.getScenarios(), "OR") + ")";
}
return ret;
}
/*
* select models that intersect the given space or have no space at all.
*/
private String spaceQuery(ISpatialExtent space) {
if (space.getExtent().getShape().isEmpty()) {
return "";
}
return "observation.space && '"
+ ((IGeometricShape) (space.getExtent().getShape())).getStandardizedGeometry()
+ "' OR ST_IsEmpty(observation.space)";
}
/*
* Entirely TODO. For initialization we should use time only to select for most
* current info - either closer to the context or to today if time is null. For
* dynamic models we should either not have a context or cover the context. Guess this
* is the job of the prioritizer, and we should simply let anything through except
* when we look for process models.
*/
private String timeQuery(ITemporalExtent time) {
String ret = "";
boolean checkBoundaries = false;
if (time != null && checkBoundaries) {
ret = "(timestart == -1 AND timeend == -1) OR (";
long start = time.getStart() == null ? -1 : time.getStart().getMillis();
long end = time.getEnd() == null ? -1 : time.getEnd().getMillis();
if (start > 0 && end > 0) {
ret += "timestart >= " + start + " AND timeend <= " + end;
} else if (start > 0) {
ret += "timestart >= " + start;
} else if (end > 0) {
ret += "timeend <= " + end;
}
ret += ")";
}
return ret;
}
public List retrieveAll() throws KlabException {
List ret = new ArrayList<>();
if (!database.hasTable("observation")) {
return ret;
}
for (long oid : database.queryIds("SELECT oid FROM observation;")) {
ret.add(retrieveModel(oid));
}
return ret;
}
public Observation retrieveModel(long oid) throws KlabException {
final Observation ret = new Observation();
database.query("SELECT * FROM observation WHERE oid = " + oid, new SQL.SimpleResultHandler() {
@Override
public void onRow(ResultSet rs) {
try {
SpatialResultSet srs = rs.unwrap(SpatialResultSet.class);
long tyid = srs.getLong(7);
long obid = srs.getLong(8);
IConcept mtype = getType(tyid);
IConcept otype = getType(obid);
if (mtype == null || otype == null) {
return;
}
// ret.setObservableConcept(mtype);
// ret.setObservationConcept(otype);
// ret.setObservable(getTypeDefinition(tyid));
// ret.setObservationType(getTypeDefinition(obid));
//
// ret.setServerId(nullify(srs.getString(2)));
// ret.setId(srs.getString(3));
// ret.setName(srs.getString(4));
// ret.setNamespaceId(srs.getString(5));
// ret.setProjectId(nullify(srs.getString(6)));
//
// ret.setPrivateModel(srs.getBoolean(9));
// ret.setResolved(srs.getBoolean(10));
// ret.setReification(srs.getBoolean(11));
// ret.setInScenario(srs.getBoolean(12));
// ret.setHasDirectObjects(srs.getBoolean(13));
// ret.setHasDirectData(srs.getBoolean(14));
// ret.setTimeStart(srs.getLong(15));
// ret.setTimeEnd(srs.getLong(16));
// ret.setSpatial(srs.getBoolean(17));
// ret.setTemporal(srs.getBoolean(18));
// ret.setTimeMultiplicity(srs.getLong(19));
// ret.setSpaceMultiplicity(srs.getLong(20));
// ret.setScaleMultiplicity(srs.getLong(21));
// ret.setDereifyingAttribute(nullify(srs.getString(22)));
Geometry geometry = srs.getGeometry(23);
if (!geometry.isEmpty()) {
// ret.setShape(new ShapeValue(geometry,
// Geospace.get().getDefaultCRS())); // +
}
} catch (SQLException e) {
throw new KlabRuntimeException(e);
}
}
});
ret.setMetadata(getMetadataFor(oid));
return ret;
}
@Override
protected String getMainTableId() {
return "observation";
}
/**
* @param name
* @return true if model with given id exists in database
* @throws KlabException
*/
public boolean hasModel(String name) throws KlabException {
if (!database.hasTable("observation")) {
return false;
}
return database.queryIds("SELECT oid FROM observation WHERE name = '" + name + "';").size() > 0;
}
@Override
protected int deleteAllObjectsWithNamespace(String namespaceId) throws KlabException {
int n = 0;
for (long oid : database
.queryIds("SELECT oid FROM observation where namespaceid = '" + Escape.forSQL(namespaceId)
+ "';")) {
deleteObjectWithId(oid);
n++;
}
return n;
}
@Override
protected void deleteObjectWithId(long id) throws KlabException {
database.execute("DELETE FROM observation WHERE oid = " + id);
deleteMetadataFor(id);
}
@Override
public long store(Object o) throws KlabException {
ArrayList