gcube-cms-suite/sdi-plugins/src/main/java/org/gcube/application/cms/sdi/plugins/SDIIndexerPlugin.java

277 lines
12 KiB
Java

package org.gcube.application.cms.sdi.plugins;
import com.sun.tools.javac.code.Type;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.bson.Document;
import org.gcube.application.cms.plugins.IndexerPluginInterface;
import org.gcube.application.cms.plugins.faults.IndexingException;
import org.gcube.application.cms.plugins.faults.InitializationException;
import org.gcube.application.cms.plugins.faults.InvalidPluginRequestException;
import org.gcube.application.cms.plugins.faults.InvalidProfileException;
import org.gcube.application.cms.plugins.model.PluginDescriptor;
import org.gcube.application.cms.plugins.reports.IndexDocumentReport;
import org.gcube.application.cms.plugins.reports.InitializationReport;
import org.gcube.application.cms.plugins.reports.Report;
import org.gcube.application.cms.plugins.requests.BaseRequest;
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;
import org.gcube.application.cms.plugins.model.ComparableVersion;
import org.gcube.application.geoportal.common.model.configuration.Index;
import org.gcube.application.geoportal.common.model.document.Project;
import org.gcube.application.geoportal.common.model.document.filesets.GCubeSDILayer;
import org.gcube.application.geoportal.common.model.rest.ConfigurationException;
import org.gcube.application.geoportal.common.model.useCaseDescriptor.UseCaseDescriptor;
import org.gcube.application.geoportal.common.utils.ContextUtils;
import org.geojson.Crs;
import org.geojson.GeoJsonObject;
import org.geojson.LngLatAlt;
import org.geojson.Point;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
@Slf4j
public class SDIIndexerPlugin extends SDIAbstractPlugin implements IndexerPluginInterface {
@Data
private static class MappingObject{
private String name;
private String type;
private String path;
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");
}
}
static final PluginDescriptor DESCRIPTOR=new PluginDescriptor("SDI-Indexer-Plugin",
PluginDescriptor.BaseTypes.INDEXER);
static {
DESCRIPTOR.setDescription("SDI Indexer. " +
"Manage Centroids layers.");
DESCRIPTOR.setVersion(new ComparableVersion("1.0.0"));
}
@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
* - centroidRecord (OPT)
*
* @param request
* @return
*/
@Override
public IndexDocumentReport index(IndexDocumentRequest request) throws InvalidPluginRequestException {
log.info("Indexer {} : Performing {} ",this.getDescriptor().getId(),request);
Project project =request.getDocument();
UseCaseDescriptor useCaseDescriptor = request.getUseCaseDescriptor();
Document requestArguments=request.getCallParameters();
IndexDocumentReport report= new IndexDocumentReport(request);
try{
// ********* INIT INDEX
// TODO CACHE
PostgisIndexer indexer = getIndexer(useCaseDescriptor,requestArguments);
Document profileConfiguration =getConfigurationFromProfile(useCaseDescriptor).getConfiguration();
log.debug("UseCaseDescriptor Configuration is {} ",profileConfiguration);
// ************* PREPARE RECORD
JSONPathWrapper documentNavigator=new JSONPathWrapper(Serialization.write(project));
Document centroidDoc = new Document();
if(requestArguments.containsKey("centroidRecord"))
centroidDoc.putAll(requestArguments.get("centroidRecords",Document.class));
// DEFAULT VALUES
centroidDoc.put("projectid", project.getId());
// ********************** EVALAUTE POSITION
log.debug("indexing UseCaseDescriptor {} : Evaluating Centroid... ", useCaseDescriptor.getId());
if(project.getSpatialReference()!=null){
log.debug("Using user defined spatial reference "+ project.getSpatialReference());
GeoJsonObject object = Serialization.convert(project.getSpatialReference(), GeoJsonObject.class);
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);
centroidDoc.put("geom",wkt);
throw new Exception("Not yet implemented");
}else {
log.debug("UseCaseDescriptor {} : Getting evaluation paths from useCaseDescriptor.. ", useCaseDescriptor.getId());
List bboxEvaluationPaths = profileConfiguration.get("bboxEvaluation",List.class);
if(bboxEvaluationPaths==null || bboxEvaluationPaths.isEmpty())
throw new Exception("Missing configuration bboxEvaluation");
GCubeSDILayer.BBOX toSet = null;
for(Object pathObj : bboxEvaluationPaths){
log.debug("UseCaseDescriptor {} : Evaluating path {} ", useCaseDescriptor.getId(),pathObj);
List<Object> bboxObjects = documentNavigator.getByPath(pathObj.toString());
log.debug("UseCaseDescriptor {} : Evaluating path {} .. results {} ", useCaseDescriptor.getId(),pathObj,bboxObjects);
for(Object bboxObject : bboxObjects) {
log.info("Matched path {}, value is {} ",pathObj.toString(),bboxObject);
GCubeSDILayer.BBOX box = Serialization.convert(bboxObject, GCubeSDILayer.BBOX.class);
if(toSet == null) toSet = box;
if(box.getMaxX()>toSet.getMaxX()) toSet.setMaxX(box.getMaxX());
if(box.getMaxY()>toSet.getMaxY()) toSet.setMaxY(box.getMaxY());
if(box.getMinX()<toSet.getMinX()) toSet.setMinX(box.getMinX());
if(box.getMinY()<toSet.getMinY()) toSet.setMinY(box.getMinY());
}
}
if(toSet == null)
throw new IndexingException("No BBOX has been found on paths : "+bboxEvaluationPaths);
Double pointX=(toSet.getMaxX()-toSet.getMinX());
Double pointY = toSet.getMaxY()-toSet.getMinY();
log.info("Evaluated BBOX {} ",toSet);
String wkt = String .format("POINT (%1$f %2$f) ",
pointX, pointY);
centroidDoc.put("geom",wkt);
Point toSetSpatialReference = new Point();
LngLatAlt pointCoordinates = new LngLatAlt();
pointCoordinates.setLongitude(pointX);
pointCoordinates.setLatitude(pointY);
toSetSpatialReference.setCoordinates(pointCoordinates);
toSetSpatialReference.setBbox(toSet.asGeoJSONArray());
report.setToSetSpatialReference(Serialization.asDocument(toSetSpatialReference));
}
//*********** Additional Values from useCaseDescriptor
log.info("Setting additional values to centroid from mappings ..");
for(MappingObject m : getMappings(useCaseDescriptor)){
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));
}
log.info("Inserting Centroid {} into {} ",centroidDoc.toJson(),indexer);
indexer.insert(centroidDoc);
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;
}
}
@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;
}
private List<PostgisTable.Field> getFields(List<MappingObject> mappings){
List<PostgisTable.Field> fields = new ArrayList<>(); // TODO From UseCaseDescriptor
fields.add(new PostgisTable.Field("geom", PostgisTable.FieldType.GEOMETRY));
fields.add(new PostgisTable.Field("projectid", PostgisTable.FieldType.TEXT));
mappings.forEach(m -> {
fields.add(new PostgisTable.Field(m.getName(), PostgisTable.FieldType.valueOf(m.getType())));
});
return fields;
}
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;
}
}