2022-02-18 18:11:12 +01:00
|
|
|
package org.gcube.application.cms.sdi.plugins;
|
|
|
|
|
2022-04-01 19:11:11 +02:00
|
|
|
import com.vdurmont.semver4j.Semver;
|
2022-02-18 18:11:12 +01:00
|
|
|
import lombok.Data;
|
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
|
import org.bson.Document;
|
|
|
|
import org.gcube.application.cms.plugins.IndexerPluginInterface;
|
2022-03-04 11:30:31 +01:00
|
|
|
import org.gcube.application.cms.plugins.faults.IndexingException;
|
2022-02-18 18:11:12 +01:00
|
|
|
import org.gcube.application.cms.plugins.faults.InitializationException;
|
2022-03-04 11:30:31 +01:00
|
|
|
import org.gcube.application.cms.plugins.faults.InvalidPluginRequestException;
|
2022-02-24 18:09:30 +01:00
|
|
|
import org.gcube.application.cms.plugins.faults.InvalidProfileException;
|
2022-05-03 18:07:18 +02:00
|
|
|
import org.gcube.application.cms.sdi.engine.bboxes.BBOXByCoordinatePaths;
|
|
|
|
import org.gcube.application.cms.sdi.engine.bboxes.BBOXEvaluator;
|
|
|
|
import org.gcube.application.cms.sdi.engine.bboxes.BBOXPathScanner;
|
2022-04-11 17:23:27 +02:00
|
|
|
import org.gcube.application.geoportal.common.model.document.identification.IdentificationReference;
|
|
|
|
import org.gcube.application.geoportal.common.model.document.identification.SpatialReference;
|
2022-04-01 19:11:11 +02:00
|
|
|
import org.gcube.application.geoportal.common.model.plugins.IndexerPluginDescriptor;
|
|
|
|
import org.gcube.application.geoportal.common.model.plugins.PluginDescriptor;
|
2022-02-18 18:11:12 +01:00
|
|
|
import org.gcube.application.cms.plugins.reports.IndexDocumentReport;
|
|
|
|
import org.gcube.application.cms.plugins.reports.InitializationReport;
|
|
|
|
import org.gcube.application.cms.plugins.reports.Report;
|
2022-03-11 18:11:32 +01:00
|
|
|
import org.gcube.application.cms.plugins.requests.BaseRequest;
|
2022-02-18 18:11:12 +01:00
|
|
|
import org.gcube.application.cms.plugins.requests.IndexDocumentRequest;
|
|
|
|
import org.gcube.application.cms.sdi.engine.PostgisIndexer;
|
|
|
|
import org.gcube.application.cms.sdi.engine.PostgisTable;
|
|
|
|
import org.gcube.application.cms.sdi.faults.SDIInteractionException;
|
|
|
|
import org.gcube.application.cms.serialization.Serialization;
|
|
|
|
import org.gcube.application.geoportal.common.model.JSONPathWrapper;
|
2022-03-11 18:11:32 +01:00
|
|
|
import org.gcube.application.geoportal.common.model.configuration.Index;
|
2022-03-04 14:23:20 +01:00
|
|
|
import org.gcube.application.geoportal.common.model.document.Project;
|
2022-03-30 12:57:14 +02:00
|
|
|
import org.gcube.application.geoportal.common.model.document.filesets.sdi.GCubeSDILayer;
|
2022-03-11 18:11:32 +01:00
|
|
|
import org.gcube.application.geoportal.common.model.rest.ConfigurationException;
|
2022-03-04 14:23:20 +01:00
|
|
|
import org.gcube.application.geoportal.common.model.useCaseDescriptor.UseCaseDescriptor;
|
2022-03-07 17:59:06 +01:00
|
|
|
import org.geojson.GeoJsonObject;
|
|
|
|
import org.geojson.LngLatAlt;
|
|
|
|
import org.geojson.Point;
|
2022-02-23 17:13:22 +01:00
|
|
|
|
2022-03-11 18:11:32 +01:00
|
|
|
import java.sql.SQLException;
|
2022-02-24 18:09:30 +01:00
|
|
|
import java.util.ArrayList;
|
2022-02-18 18:11:12 +01:00
|
|
|
import java.util.List;
|
|
|
|
|
|
|
|
@Slf4j
|
|
|
|
public class SDIIndexerPlugin extends SDIAbstractPlugin implements IndexerPluginInterface {
|
|
|
|
|
|
|
|
@Data
|
2022-02-24 18:09:30 +01:00
|
|
|
private static class MappingObject{
|
2022-02-18 18:11:12 +01:00
|
|
|
private String name;
|
|
|
|
private String type;
|
|
|
|
private String path;
|
2022-02-24 18:09:30 +01:00
|
|
|
|
2022-03-04 11:30:31 +01:00
|
|
|
public void validate () throws InvalidProfileException {
|
|
|
|
if(name==null) throw new InvalidProfileException("Invalid mapping "+this+" : name is null");
|
|
|
|
if(type==null) throw new InvalidProfileException("Invalid mapping "+this+" : type is null");
|
|
|
|
if(path==null) throw new InvalidProfileException("Invalid mapping "+this+" : path is null");
|
2022-02-24 18:09:30 +01:00
|
|
|
}
|
2022-02-18 18:11:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2022-02-25 11:44:56 +01:00
|
|
|
static final PluginDescriptor DESCRIPTOR=new PluginDescriptor("SDI-Indexer-Plugin",
|
2022-04-01 19:11:11 +02:00
|
|
|
IndexerPluginDescriptor.INDEXER);
|
2022-02-18 18:11:12 +01:00
|
|
|
|
2022-05-03 18:07:18 +02:00
|
|
|
static final ArrayList<BBOXEvaluator> BBOX_EVALUATORS=new ArrayList<>();
|
|
|
|
|
2022-02-18 18:11:12 +01:00
|
|
|
static {
|
|
|
|
DESCRIPTOR.setDescription("SDI Indexer. " +
|
|
|
|
"Manage Centroids layers.");
|
2022-04-01 19:11:11 +02:00
|
|
|
DESCRIPTOR.setVersion(new Semver("1.0.0"));
|
2022-05-03 18:07:18 +02:00
|
|
|
|
|
|
|
BBOX_EVALUATORS.add(new BBOXPathScanner());
|
|
|
|
BBOX_EVALUATORS.add(new BBOXByCoordinatePaths());
|
|
|
|
|
|
|
|
|
|
|
|
|
2022-02-18 18:11:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public PluginDescriptor getDescriptor() {
|
|
|
|
return DESCRIPTOR;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public InitializationReport initInContext() throws InitializationException {
|
|
|
|
InitializationReport report = new InitializationReport();
|
|
|
|
report.setStatus(Report.Status.OK);
|
|
|
|
return report;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Expected parameters :
|
|
|
|
* - indexName (unique)
|
|
|
|
* - workspace
|
2022-03-04 11:30:31 +01:00
|
|
|
* - centroidRecord (OPT)
|
2022-02-18 18:11:12 +01:00
|
|
|
*
|
|
|
|
* @param request
|
|
|
|
* @return
|
|
|
|
*/
|
|
|
|
|
|
|
|
@Override
|
2022-03-04 11:30:31 +01:00
|
|
|
public IndexDocumentReport index(IndexDocumentRequest request) throws InvalidPluginRequestException {
|
2022-02-18 18:11:12 +01:00
|
|
|
|
2022-03-30 12:57:14 +02:00
|
|
|
log.info("Indexer {} : Serving Index Request {} ",this.getDescriptor().getId(),request);
|
2022-02-18 18:11:12 +01:00
|
|
|
|
2022-03-04 14:23:20 +01:00
|
|
|
Project project =request.getDocument();
|
|
|
|
UseCaseDescriptor useCaseDescriptor = request.getUseCaseDescriptor();
|
2022-02-18 18:11:12 +01:00
|
|
|
Document requestArguments=request.getCallParameters();
|
|
|
|
|
2022-02-23 17:13:22 +01:00
|
|
|
IndexDocumentReport report= new IndexDocumentReport(request);
|
2022-02-18 18:11:12 +01:00
|
|
|
|
2022-02-24 18:09:30 +01:00
|
|
|
|
2022-02-18 18:11:12 +01:00
|
|
|
|
|
|
|
try{
|
|
|
|
// ********* INIT INDEX
|
|
|
|
// TODO CACHE
|
2022-03-11 18:11:32 +01:00
|
|
|
PostgisIndexer indexer = getIndexer(useCaseDescriptor,requestArguments);
|
2022-02-18 18:11:12 +01:00
|
|
|
|
2022-03-04 14:23:20 +01:00
|
|
|
Document profileConfiguration =getConfigurationFromProfile(useCaseDescriptor).getConfiguration();
|
|
|
|
log.debug("UseCaseDescriptor Configuration is {} ",profileConfiguration);
|
2022-02-18 18:11:12 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ************* PREPARE RECORD
|
|
|
|
|
|
|
|
|
2022-03-04 14:23:20 +01:00
|
|
|
JSONPathWrapper documentNavigator=new JSONPathWrapper(Serialization.write(project));
|
2022-02-18 18:11:12 +01:00
|
|
|
|
2022-03-04 11:30:31 +01:00
|
|
|
Document centroidDoc = new Document();
|
|
|
|
if(requestArguments.containsKey("centroidRecord"))
|
|
|
|
centroidDoc.putAll(requestArguments.get("centroidRecords",Document.class));
|
2022-02-18 18:11:12 +01:00
|
|
|
// DEFAULT VALUES
|
2022-03-04 14:23:20 +01:00
|
|
|
centroidDoc.put("projectid", project.getId());
|
2022-02-18 18:11:12 +01:00
|
|
|
|
|
|
|
// ********************** EVALAUTE POSITION
|
2022-03-04 14:23:20 +01:00
|
|
|
log.debug("indexing UseCaseDescriptor {} : Evaluating Centroid... ", useCaseDescriptor.getId());
|
2022-04-11 17:23:27 +02:00
|
|
|
SpatialReference reference =null;
|
|
|
|
List<IdentificationReference> refs=project.getIdentificationReferenceByType(SpatialReference.SPATIAL_REFERENCE_TYPE);
|
|
|
|
if(!refs.isEmpty()){
|
2022-03-07 17:59:06 +01:00
|
|
|
|
2022-04-11 17:23:27 +02:00
|
|
|
// Use existing Reference
|
2022-03-07 17:59:06 +01:00
|
|
|
|
2022-04-11 17:23:27 +02:00
|
|
|
reference = Serialization.convert(refs.get(0), SpatialReference.class);
|
2022-03-07 17:59:06 +01:00
|
|
|
|
2022-05-05 14:15:39 +02:00
|
|
|
log.debug("Using already defined spatial reference " + reference);
|
2022-03-07 17:59:06 +01:00
|
|
|
|
2022-04-29 15:31:17 +02:00
|
|
|
|
2022-04-11 17:23:27 +02:00
|
|
|
GeoJsonObject object = Serialization.convert(reference.getGeoJson(), GeoJsonObject.class);
|
2022-03-07 17:59:06 +01:00
|
|
|
|
2022-04-11 17:23:27 +02:00
|
|
|
GCubeSDILayer.BBOX bbox = GCubeSDILayer.BBOX.fromGeoJSON(object.getBbox());
|
|
|
|
|
|
|
|
log.info("Found declared BBOX {} ", bbox);
|
|
|
|
Double pointX = (bbox.getMaxX() - bbox.getMinX());
|
|
|
|
Double pointY = bbox.getMaxY() - bbox.getMinY();
|
|
|
|
String wkt = String.format("POINT (%1$f %2$f) ",
|
|
|
|
pointX, pointY);
|
2022-03-07 17:59:06 +01:00
|
|
|
|
|
|
|
|
2022-04-11 17:23:27 +02:00
|
|
|
centroidDoc.put("geom", wkt);
|
|
|
|
|
2022-02-18 18:11:12 +01:00
|
|
|
throw new Exception("Not yet implemented");
|
2022-04-11 17:23:27 +02:00
|
|
|
} else{
|
|
|
|
// unable to use current Spatial reference, try evaluating it
|
2022-03-04 14:23:20 +01:00
|
|
|
log.debug("UseCaseDescriptor {} : Getting evaluation paths from useCaseDescriptor.. ", useCaseDescriptor.getId());
|
2022-04-11 17:23:27 +02:00
|
|
|
|
2022-05-03 18:07:18 +02:00
|
|
|
// for each configuration option try until found
|
2022-04-11 17:23:27 +02:00
|
|
|
GCubeSDILayer.BBOX toSet = null;
|
2022-05-03 18:07:18 +02:00
|
|
|
for(BBOXEvaluator evaluator : BBOX_EVALUATORS){
|
|
|
|
log.trace("UCD {}, Project {}. Evaluating BBOX with {}",useCaseDescriptor.getId(),project.getId(),evaluator);
|
|
|
|
try{
|
|
|
|
if(evaluator.isConfigured(profileConfiguration)){
|
|
|
|
toSet=evaluator.evaluate(profileConfiguration,useCaseDescriptor,documentNavigator);
|
|
|
|
if(toSet!=null) {
|
|
|
|
log.info("UCD {}, Project {}. Evaluated BBOX {} with method {}",
|
|
|
|
useCaseDescriptor.getId(),project.getId(),toSet,evaluator);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}catch (Throwable t){
|
|
|
|
log.warn("UCD {}, Project {}. Exception with {}",
|
|
|
|
useCaseDescriptor.getId(),project.getId(),evaluator,t);
|
2022-02-18 18:11:12 +01:00
|
|
|
}
|
|
|
|
}
|
2022-05-03 18:07:18 +02:00
|
|
|
if(toSet== null)
|
|
|
|
throw new IndexingException("No BBOX has been evaluated from project");
|
2022-03-04 11:30:31 +01:00
|
|
|
|
2022-03-07 17:59:06 +01:00
|
|
|
Double pointX=(toSet.getMaxX()-toSet.getMinX());
|
|
|
|
Double pointY = toSet.getMaxY()-toSet.getMinY();
|
2022-02-18 18:11:12 +01:00
|
|
|
log.info("Evaluated BBOX {} ",toSet);
|
2022-03-04 11:30:31 +01:00
|
|
|
String wkt = String .format("POINT (%1$f %2$f) ",
|
2022-03-07 17:59:06 +01:00
|
|
|
pointX, pointY);
|
2022-02-18 18:11:12 +01:00
|
|
|
|
|
|
|
|
2022-03-04 11:30:31 +01:00
|
|
|
centroidDoc.put("geom",wkt);
|
2022-02-18 18:11:12 +01:00
|
|
|
|
2022-04-11 17:23:27 +02:00
|
|
|
Point toSetgeoJSON = new Point();
|
2022-03-07 17:59:06 +01:00
|
|
|
LngLatAlt pointCoordinates = new LngLatAlt();
|
|
|
|
pointCoordinates.setLongitude(pointX);
|
|
|
|
pointCoordinates.setLatitude(pointY);
|
2022-04-11 17:23:27 +02:00
|
|
|
toSetgeoJSON.setCoordinates(pointCoordinates);
|
|
|
|
toSetgeoJSON.setBbox(toSet.asGeoJSONArray());
|
|
|
|
reference = new SpatialReference(toSetgeoJSON);
|
2022-03-07 17:59:06 +01:00
|
|
|
|
2022-04-11 17:23:27 +02:00
|
|
|
report.addIdentificationReference(reference);
|
2022-02-18 18:11:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2022-03-04 14:23:20 +01:00
|
|
|
//*********** Additional Values from useCaseDescriptor
|
2022-02-18 18:11:12 +01:00
|
|
|
|
2022-03-04 11:30:31 +01:00
|
|
|
log.info("Setting additional values to centroid from mappings ..");
|
2022-03-11 18:11:32 +01:00
|
|
|
for(MappingObject m : getMappings(useCaseDescriptor)){
|
2022-03-04 11:30:31 +01:00
|
|
|
List<Object> foundValues = documentNavigator.getByPath(m.getPath());
|
|
|
|
Object toSetValue=null;
|
|
|
|
if(!foundValues.isEmpty())
|
|
|
|
toSetValue=foundValues.get(0);
|
|
|
|
log.trace("Setting {} = {} in centroid doc ",m.getName(),toSetValue);
|
|
|
|
centroidDoc.put(m.getName(),foundValues.get(0));
|
|
|
|
}
|
2022-02-18 18:11:12 +01:00
|
|
|
|
2022-03-04 11:30:31 +01:00
|
|
|
log.info("Inserting Centroid {} into {} ",centroidDoc.toJson(),indexer);
|
|
|
|
indexer.insert(centroidDoc);
|
2022-02-18 18:11:12 +01:00
|
|
|
|
|
|
|
report.setStatus(Report.Status.OK);
|
|
|
|
}catch (SDIInteractionException e){
|
|
|
|
log.error("Unable to index "+request,e);
|
|
|
|
report.setStatus(Report.Status.ERROR);
|
|
|
|
report.putMessage(e.getMessage());
|
|
|
|
}catch (Throwable t){
|
|
|
|
log.error("Unable to index "+request,t);
|
|
|
|
report.setStatus(Report.Status.ERROR);
|
|
|
|
report.putMessage(t.getMessage());
|
|
|
|
}finally{
|
|
|
|
return report;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-30 12:57:14 +02:00
|
|
|
@Override
|
|
|
|
public IndexDocumentReport deindex(IndexDocumentRequest request) throws InvalidPluginRequestException {
|
|
|
|
log.info("Indexer {} : Serving Index Request {} ",this.getDescriptor().getId(),request);
|
|
|
|
IndexDocumentReport report= new IndexDocumentReport(request);
|
|
|
|
try{
|
|
|
|
PostgisIndexer indexer = getIndexer(request.getUseCaseDescriptor(),request.getCallParameters());
|
|
|
|
indexer.removeByFieldValue(Fields.PROJECT_ID,request.getDocument().getId());
|
|
|
|
}catch (SDIInteractionException e){
|
|
|
|
log.error("Unable to index "+request,e);
|
|
|
|
report.setStatus(Report.Status.ERROR);
|
|
|
|
report.putMessage(e.getMessage());
|
|
|
|
}catch (Throwable t){
|
|
|
|
log.error("Unable to index "+request,t);
|
|
|
|
report.setStatus(Report.Status.ERROR);
|
|
|
|
report.putMessage(t.getMessage());
|
|
|
|
}finally{
|
|
|
|
return report;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-17 17:54:00 +01:00
|
|
|
/**
|
|
|
|
* Expected parameters :
|
|
|
|
* workspace
|
|
|
|
* indexName
|
|
|
|
*
|
|
|
|
* @param request
|
|
|
|
* @return
|
|
|
|
* @throws ConfigurationException
|
|
|
|
*/
|
2022-03-11 18:11:32 +01:00
|
|
|
@Override
|
|
|
|
public Index getIndex(BaseRequest request) throws ConfigurationException {
|
|
|
|
try {
|
|
|
|
return getIndexer(request.getUseCaseDescriptor(), request.getCallParameters()).getIndexConfiguration();
|
|
|
|
}catch(Throwable t ){
|
|
|
|
throw new ConfigurationException("Unable to get Postgis index for ucd "+request.getUseCaseDescriptor().getId()+" in "+ request.getContext(),t);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Inits index
|
|
|
|
// TODO CACHE
|
|
|
|
private PostgisIndexer getIndexer(UseCaseDescriptor ucd,Document params) throws ConfigurationException, SQLException, InvalidProfileException, SDIInteractionException {
|
|
|
|
PostgisIndexer indexer = new PostgisIndexer(sdiCache.getObject(), ucd, postgisCache.getObject());
|
|
|
|
|
|
|
|
List<MappingObject> mappingObjects = getMappings(ucd);
|
|
|
|
List<PostgisTable.Field> fields = getFields(mappingObjects);
|
|
|
|
|
|
|
|
|
|
|
|
indexer.initIndex(params.getString("indexName"),
|
|
|
|
fields,
|
|
|
|
params.getString("workspace"),
|
|
|
|
params.getString("indexName"));
|
|
|
|
return indexer;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-03-30 12:57:14 +02:00
|
|
|
private static class Fields{
|
|
|
|
public static final PostgisTable.Field PROJECT_ID= new PostgisTable.Field("projectid", PostgisTable.FieldType.TEXT);
|
|
|
|
public static final PostgisTable.Field GEOM= new PostgisTable.Field("geom", PostgisTable.FieldType.GEOMETRY);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2022-03-11 18:11:32 +01:00
|
|
|
|
|
|
|
private List<PostgisTable.Field> getFields(List<MappingObject> mappings){
|
|
|
|
List<PostgisTable.Field> fields = new ArrayList<>(); // TODO From UseCaseDescriptor
|
2022-03-30 12:57:14 +02:00
|
|
|
fields.add(Fields.GEOM);
|
|
|
|
fields.add(Fields.PROJECT_ID);
|
2022-03-11 18:11:32 +01:00
|
|
|
|
|
|
|
mappings.forEach(m -> {
|
|
|
|
fields.add(new PostgisTable.Field(m.getName(), PostgisTable.FieldType.valueOf(m.getType())));
|
|
|
|
});
|
|
|
|
|
2022-04-11 17:23:27 +02:00
|
|
|
return fields;
|
2022-03-11 18:11:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private List<MappingObject> getMappings(UseCaseDescriptor ucd) throws InvalidProfileException {
|
|
|
|
log.debug("UseCaseDescriptor {} : Evaluating Index schema.. ", ucd.getId());
|
|
|
|
Document profileConfiguration = getConfigurationFromProfile(ucd).getConfiguration();
|
|
|
|
List mappingObjs= profileConfiguration.get("explicitFieldMapping",List.class);
|
|
|
|
log.trace("Loading mappings from useCaseDescriptor.. ");
|
|
|
|
List<MappingObject> mappingObjects= new ArrayList<>();
|
|
|
|
if(mappingObjs!=null){
|
|
|
|
for (Object mappingObj : mappingObjs) {
|
|
|
|
log.trace("Mapping is {} ",mappingObj);
|
|
|
|
MappingObject m = Serialization.convert(mappingObj,MappingObject.class);
|
|
|
|
m.validate();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return mappingObjects;
|
|
|
|
}
|
2022-02-18 18:11:12 +01:00
|
|
|
}
|