gcube-cms-suite/concessioni-lifecycle/src/main/java/org/gcube/application/cms/concessioni/sdi/SDIManager.java

283 lines
10 KiB
Java
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package org.gcube.application.cms.concessioni.sdi;
import it.geosolutions.geoserver.rest.GeoServerRESTPublisher;
import it.geosolutions.geoserver.rest.GeoServerRESTReader;
import it.geosolutions.geoserver.rest.decoder.RESTFeatureType;
import it.geosolutions.geoserver.rest.decoder.RESTLayer;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.bson.Document;
import org.gcube.application.cms.concessioni.sdi.faults.SDIInteractionException;
import org.gcube.application.cms.plugins.requests.BaseExecutionRequest;
import org.gcube.application.cms.serialization.Serialization;
import org.gcube.application.geoportal.common.model.document.filesets.GCubeSDILayer;
import org.gcube.application.geoportal.common.model.document.filesets.RegisteredFile;
import org.gcube.application.geoportal.common.model.document.filesets.RegisteredFileSet;
import org.gcube.application.geoportal.common.utils.Files;
import org.gcube.data.transfer.library.DataTransferClient;
import org.gcube.data.transfer.library.TransferResult;
import org.gcube.data.transfer.model.Destination;
import org.gcube.data.transfer.model.DestinationClashPolicy;
import org.gcube.spatial.data.gis.GISInterface;
import org.gcube.spatial.data.gis.is.AbstractGeoServerDescriptor;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
@Slf4j
public class SDIManager {
static private final String EPSG_4326="EPSG:4326";
static private final String WGS84_FULL="GEOGCS[\"WGS 84\", DATUM[\"World Geodetic System 1984\", SPHEROID[\"WGS 84\", 6378137.0, 298.257223563, AUTHORITY[\"EPSG\",\"7030\"]],"+
"AUTHORITY[\"EPSG\",\"6326\"]], PRIMEM[\"Greenwich\", 0.0, AUTHORITY[\"EPSG\",\"8901\"]], UNIT[\"degree\", 0.017453292519943295],"+
"AXIS[\"Geodetic longitude\", EAST], AXIS[\"Geodetic latitude\", NORTH], AUTHORITY[\"EPSG\",\"4326\"]]";
public static final Pattern HOSTNAME_PATTERN=Pattern.compile("(?<=\\:\\/\\/)[^\\:]*");
public static final Pattern PORT_PATTERN=Pattern.compile("(?<=\\:)[\\d]+");
public static final Pattern DB_NAME_PATTERN=Pattern.compile("(?<=\\/)[^\\/]*(?=$)");
private final GISInterface gis;
@Getter
private final DataTransferClient dtGeoServer;
@Getter
private final String geoserverHostName;
@Getter
private final AbstractGeoServerDescriptor currentGeoserver;
public SDIManager() throws SDIInteractionException {
try{
log.debug("Initializing GIS Interface..");
gis=GISInterface.get();
currentGeoserver=gis.getCurrentGeoServer();
if(currentGeoserver==null)
throw new Exception("Unable to contact data transfer for geoserver ");
log.debug("Found geoserver descriptor "+currentGeoserver);
geoserverHostName=new URL(currentGeoserver.getUrl()).getHost();
log.debug("Contacting Data Transfer from geoserver {} ",geoserverHostName);
dtGeoServer=DataTransferClient.getInstanceByEndpoint("https://"+geoserverHostName);
if(!currentGeoserver.getReader().existGeoserver())
throw new Exception("Geoserver not reachable");
}catch(Exception e) {
throw new SDIInteractionException("Unable to initialize SDI Manager",e);
}
}
/**
* Expected paramters :
* - "workspace"
* - "layerTitle"
* - "documentID"
* - "basePersistencePath" (profile specific, e.g. "GNA")
*
* @param fileSet
* @param params
* @return
* @throws SDIInteractionException
*/
public RegisteredFileSet materializeLayer(RegisteredFileSet fileSet, Document params) throws SDIInteractionException{
try {
log.debug("Materializing FS {} on {} ", fileSet, geoserverHostName);
// validate parameters
String workspace = BaseExecutionRequest.getMandatory("workspace", params);
String documentID = BaseExecutionRequest.getMandatory("documentID", params);
String basePersistencePAth = BaseExecutionRequest.getMandatory("basePersistencePath", params);
// check if empty
if (fileSet.getPayloads().isEmpty()) throw new SDIInteractionException("No payload to materialize");
Document geoserverInfo = new Document();
geoserverInfo.put("_type", "Geoserver");
geoserverInfo.put("workspace", workspace);
// Evaluate Layer Name
String baseName = getToUseBaseLayerName(fileSet);
log.debug("Base layer name is {}, checking conflicts.. ");
String toSetLayerName = baseName;
//Check if layer already exists
int count = 0;
GeoServerRESTReader gsReader = currentGeoserver.getReader();
while (gsReader.getLayer(workspace, toSetLayerName) != null) {
count++;
toSetLayerName = baseName + "_" + count;
log.debug("layer for " + baseName + " already existing, trying " + toSetLayerName);
}
geoserverInfo.put("layerName", toSetLayerName);
log.debug("Layer name will be {} ", toSetLayerName);
String folderRelativePath = basePersistencePAth + "/" + documentID + "/" + fileSet.getUUID() + "/" + toSetLayerName;
log.debug("GS Relative destination path is {} ", folderRelativePath);
geoserverInfo.put("persistencePath", folderRelativePath);
List<String> filenames = new ArrayList<>();
String absolutePath = null;
for (Object o : fileSet.getPayloads()) {
RegisteredFile file = Serialization.convert(o, RegisteredFile.class);
log.info("Sending {} to GS {} at {} ", file, geoserverHostName, folderRelativePath);
String completeFilename = Files.fixFilename(file.getName());
completeFilename = completeFilename.replaceAll(baseName, toSetLayerName);
Destination destination = new Destination(completeFilename);
destination.setCreateSubfolders(true);
destination.setOnExistingFileName(DestinationClashPolicy.REWRITE);
destination.setOnExistingSubFolder(DestinationClashPolicy.APPEND);
destination.setPersistenceId("geoserver");
destination.setSubFolder(folderRelativePath);
log.debug("Sending {} to {}", file, destination);
TransferResult result = getDtGeoServer().httpSource(new URL(file.getLink()), destination);
log.debug("Transferred " + result);
filenames.add(completeFilename);
// NB Clash con subfolder is APPEND, thus FOLDER is expected to be the one specified by caller
//geoserverInfo.put(""result.getRemotePath().substring(0, result.getRemotePath().lastIndexOf("/")));
absolutePath = result.getRemotePath().substring(0, result.getRemotePath().lastIndexOf("/"));
}
geoserverInfo.put("files", filenames);
// Publishing layer in GS
String storeName = toSetLayerName + "_store";
geoserverInfo.put("storeName", storeName);
GeoServerRESTPublisher publisher = currentGeoserver.getPublisher();
log.debug("Trying to create remote workspace : " + workspace);
createWorkspace(workspace);
log.debug("Publishing remote folder " + absolutePath);
URL directoryPath = new URL("file:" + absolutePath + "/" + toSetLayerName + ".shp");
//TODO Evaluate SRS
boolean published = publisher.publishShp(
workspace,
storeName,
null,
toSetLayerName,
// UploadMethod.FILE, // neeeds zip
GeoServerRESTPublisher.UploadMethod.EXTERNAL, // needs shp
directoryPath.toURI(),
EPSG_4326, //SRS
""); // default style
if (!published) {
throw new SDIInteractionException("Unable to publish layer " + toSetLayerName + " under " + workspace + ". Unknown Geoserver fault.");
}
RESTLayer l = gsReader.getLayer(workspace, toSetLayerName);
RESTFeatureType f = gsReader.getFeatureType(l);
/*https://geoserver1.dev.d4science.org/geoserver/gna_conc_18/wms?
service=WMS&version=1.1.0&request=GetMap&layers=gna_conc_18:pos&
styles=&bbox=8.62091913167495,40.62975046683799,8.621178639172953,40.630257904721645&
width=392&height=768&srs=EPSG:4326&format=application/openlayers */
List<Document> ogcLinks = new ArrayList<>();
Document wmsLink = new Document();
wmsLink.put("wms", String.format("https://%1$s/geoserver/%2$s/wms?"
+ "service=WMS&version=1.1.0&request=GetMap&layers=%2$s:%3$s&"
+ "styles=&bbox=%4$f,%5$f,%6$f,%7$f&srs=%8$s&format=application/openlayers&width=%9$d&height=%10$d",
geoserverHostName,
workspace,
toSetLayerName,
f.getMinX(),
f.getMinY(),
f.getMaxX(),
f.getMaxY(),
EPSG_4326,
400,
400));
ogcLinks.add(wmsLink);
List<Document> platformInfo = new ArrayList<>();
platformInfo.add(geoserverInfo);
// TODO Metadata
// Materialization object
GCubeSDILayer materialization = new GCubeSDILayer();
materialization.put(GCubeSDILayer.OGC_LINKS, ogcLinks);
materialization.put(GCubeSDILayer.B_BOX, new GCubeSDILayer.BBOX(f.getMaxX(), f.getMaxY(), f.getMinX(), f.getMinY()));
materialization.put(GCubeSDILayer.PLATFORM_INFO, platformInfo);
log.info("Generated Materialization {}", materialization);
//Add Materialization to registered file set
List materializations = fileSet.getMaterializations();
if (materializations == null) materializations = new ArrayList();
materializations.add(materialization);
fileSet.put(RegisteredFileSet.MATERIALIZATIONS, materializations);
return fileSet;
}catch(SDIInteractionException e){
throw e;
}catch (Throwable t){
throw new SDIInteractionException("Unexpected exception while trying to materialize File Set "+t.getMessage(),t);
}
}
public String createWorkspace(String toCreate) throws SDIInteractionException {
try {
if(!currentGeoserver.getReader().getWorkspaceNames().contains(toCreate)) {
log.debug("Creating workspace : "+toCreate);
if(!currentGeoserver.getPublisher().createWorkspace(toCreate))
throw new SDIInteractionException("Unable to create workspace "+toCreate);
}else log.debug("Workspace "+toCreate+" exists.");
return toCreate;
} catch (IllegalArgumentException | MalformedURLException e) {
throw new SDIInteractionException("Unable to create workspace "+toCreate,e);
}
}
private static final String getToUseBaseLayerName(RegisteredFileSet fileset){
// ******** IDENTIFY LAYER NAME correct layer name
// Must be unique under same WS
// equal to shp base name
String baseName= "";
// Chose layer name first identifying filename
for(Object p:fileset.getPayloads()){
RegisteredFile f = Serialization.convert(p,RegisteredFile.class);
String name=f.getName();
if(name.endsWith(".shp")) {
log.debug("SHP is {}",name);
baseName= Files.fixFilename(name.substring(0,name.lastIndexOf('.')));
break;
}
}
return baseName;
}
}