package org.gcube.application.geoportal.service.engine; import java.io.File; import java.net.MalformedURLException; import java.net.URL; import org.gcube.application.geoportal.common.model.legacy.BBOX; import org.gcube.application.geoportal.common.model.legacy.GeoServerContent; import org.gcube.application.geoportal.common.model.legacy.PersistedContent; import org.gcube.application.geoportal.common.model.legacy.SDILayerDescriptor; import org.gcube.application.geoportal.common.model.legacy.WorkspaceContent; import org.gcube.application.geoportal.common.utils.Files; import org.gcube.application.geoportal.service.model.internal.faults.SDIInteractionException; import org.gcube.common.storagehub.client.dsl.FileContainer; import org.gcube.data.transfer.library.DataTransferClient; import org.gcube.data.transfer.library.TransferResult; import org.gcube.data.transfer.library.faults.RemoteServiceException; import org.gcube.data.transfer.model.Destination; import org.gcube.data.transfer.model.DestinationClashPolicy; import org.gcube.data.transfer.model.RemoteFileDescriptor; import org.gcube.spatial.data.gis.GISInterface; import org.gcube.spatial.data.gis.is.AbstractGeoServerDescriptor; import it.geosolutions.geoserver.rest.GeoServerRESTPublisher; import it.geosolutions.geoserver.rest.GeoServerRESTPublisher.UploadMethod; import it.geosolutions.geoserver.rest.GeoServerRESTReader; import it.geosolutions.geoserver.rest.decoder.RESTFeatureType; import it.geosolutions.geoserver.rest.decoder.RESTLayer; import it.geosolutions.geoserver.rest.encoder.GSLayerEncoder; import it.geosolutions.geoserver.rest.encoder.datastore.GSPostGISDatastoreEncoder; import it.geosolutions.geoserver.rest.encoder.feature.GSFeatureTypeEncoder; import lombok.Getter; import lombok.extern.slf4j.Slf4j; @Slf4j public class SDIManager { static private String DEFAULT_CRS="EPSG:4326"; private GISInterface gis; @Getter private DataTransferClient dtGeoServer; private String geoserverHostName; public SDIManager() throws SDIInteractionException { try{ log.debug("Initializing GIS Interface.."); gis=GISInterface.get(); AbstractGeoServerDescriptor geoserver=gis.getCurrentGeoServer(); if(geoserver==null) throw new Exception("Unable to contact data transfer for geoserver "); log.debug("Found geoserver descriptor "+geoserver); geoserverHostName=new URL(gis.getCurrentGeoServer().getUrl()).getHost(); log.debug("Contacting Data Transfer from geoserver {} ",geoserverHostName); dtGeoServer=DataTransferClient.getInstanceByEndpoint("http://"+geoserverHostName); if(!gis.getCurrentGeoServer().getReader().existGeoserver()) throw new Exception("Geoserver not reachable"); }catch(Exception e) { throw new SDIInteractionException("Unable to initialize SDI Manager",e); } } public RemoteFileDescriptor getGeoServerRemoteFolder() throws RemoteServiceException { return dtGeoServer.getWebClient().getInfo("geoserver/GNA"); } public String createWorkspace(String toCreate) throws SDIInteractionException { try { if(!gis.getCurrentGeoServer().getReader().getWorkspaceNames().contains(toCreate)) { log.debug("Creating workspace : "+toCreate); if(!gis.getCurrentGeoServer().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); } } // GEOSERVER-PERSISTENCE-ID / GNA / PROJECT-ID/ LAYER-ID /FILENAME(no extension)/... public GeoServerContent pushShapeLayerFileSet(SDILayerDescriptor currentElement,String workspace, String projectId) throws SDIInteractionException{ try { // String remoteFolder=null; // String fileName=null; log.debug("Publishing "+currentElement+" files to geoserver @ "+geoserverHostName); GeoServerContent content=new GeoServerContent(); content.setGeoserverHostName(geoserverHostName); content.setWorkspace(workspace); WorkspaceManager wsManager=new WorkspaceManager(); currentElement.getActualContent().forEach((PersistedContent c)->{ try { if(c instanceof WorkspaceContent) { WorkspaceContent wc=(WorkspaceContent) c; FileContainer fc=wsManager.getFileById(wc.getStorageID()); String completeFilename=Files.fixFilename(fc.get().getName()); String filename=completeFilename.contains(".")?completeFilename.substring(0, completeFilename.lastIndexOf(".")):completeFilename; Destination destination=new Destination(completeFilename); destination.setCreateSubfolders(true); destination.setOnExistingFileName(DestinationClashPolicy.REWRITE); destination.setOnExistingSubFolder(DestinationClashPolicy.APPEND); destination.setPersistenceId("geoserver"); destination.setSubFolder("GNA/"+projectId+"/"+ currentElement.getMongo_id()+"/"+filename); log.debug("Sending "+wc+" to "+destination); TransferResult result=dtGeoServer.httpSource(fc.getPublicLink(), destination); log.debug("Transferred "+result); content.getFileNames().add(completeFilename); content.setGeoserverPath(result.getRemotePath().substring(0,result.getRemotePath().lastIndexOf("/"))); } }catch(Throwable t) { log.warn("Unable to transfer Persisted content"+c,t); } }); if(content.getFileNames().isEmpty()) throw new SDIInteractionException("No Persisted content found in "+currentElement); String completeFileName=content.getFileNames().get(0); String filename=completeFileName.contains(".")?completeFileName.substring(0, completeFileName.lastIndexOf(".")):completeFileName; String remoteFolder=content.getGeoserverPath(); String toSetLayerName=filename; int count=0; while(gis.getCurrentGeoServer().getReader().getLayer(workspace,toSetLayerName)!=null){ count++; toSetLayerName=filename+"_"+count; log.debug("layer for "+filename+" already existing, trying "+toSetLayerName); }; String storeName=toSetLayerName+"_store"; content.setStore(storeName); content.setFeatureType(toSetLayerName); GeoServerRESTPublisher publisher=gis.getCurrentGeoServer().getPublisher(); log.debug("Trying to create remote workspace : "+workspace); createWorkspace(workspace); log.debug("Publishing remote folder "+remoteFolder); URL directoryPath=new URL("file:"+remoteFolder+"/"+filename+".shp"); //TODO Evaluate SRS boolean published=publisher.publishShp( workspace, storeName, null, toSetLayerName, // UploadMethod.FILE, // neeeds zip UploadMethod.EXTERNAL, // needs shp directoryPath.toURI(), DEFAULT_CRS, //SRS ""); // default style if(!published) { throw new SDIInteractionException("Unable to publish layer "+toSetLayerName+" under "+workspace+". Unknown Geoserver fault."); } currentElement.setLayerName(toSetLayerName); GeoServerRESTReader reader=gis.getCurrentGeoServer().getReader(); RESTLayer l=reader.getLayer(workspace, toSetLayerName); RESTFeatureType f= reader.getFeatureType(l); /*http://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 */ currentElement.setWmsLink( 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(), DEFAULT_CRS, 400, 400)); currentElement.setWorkspace(workspace); currentElement.setBbox(new BBOX(f.getMaxY(), f.getMaxX(), f.getMinY(), f.getMinX())); // TODO Metadata return content; // } catch (InvalidSourceException | SourceNotSetException | FailedTransferException | InitializationException // | InvalidDestinationException | DestinationNotSetException e) { // throw new SDIInteractionException("Unable to transfer fileSet for content "+currentElement,e); } catch (SDIInteractionException e) { throw e; } catch (Throwable t) { throw new SDIInteractionException("Unexpected internal fault while interacting with SDI.",t); } } private String createStoreFromPostgisDB(String workspace,String storeName) throws SDIInteractionException { //SET BY PROVISIONING GSPostGISDatastoreEncoder encoder=new GSPostGISDatastoreEncoder(storeName); encoder.setJndiReferenceName("java:comp/env/jdbc/postgres"); encoder.setLooseBBox(true); encoder.setDatabaseType("postgis"); encoder.setEnabled(true); encoder.setFetchSize(1000); encoder.setValidateConnections(true); try { log.debug("Looking for datastore "+storeName+" under "+workspace); if(gis.getCurrentGeoServer().getReader().getDatastore(workspace,storeName)==null) if(!gis.getCurrentGeoServer().getDataStoreManager().create(workspace, encoder)) throw new SDIInteractionException("Unable to create store "+storeName+" in "+workspace); log.debug("Store "+storeName+" exists under "+workspace); return storeName; } catch (IllegalArgumentException | MalformedURLException e) { throw new SDIInteractionException("Unable to create store "+storeName,e); } } private String publishStyle(File sldFile,String name) throws SDIInteractionException { try { if(!gis.getCurrentGeoServer().getReader().existsStyle(name)) { log.debug("Registering style "+name); if(!gis.getCurrentGeoServer().getPublisher().publishStyle(sldFile, name)) throw new SDIInteractionException("Unable to register style "+name); }else log.debug("Style "+name+" already existing"); return name; } catch (IllegalArgumentException | MalformedURLException e) { throw new SDIInteractionException("Unable to create style "+name,e); } } public String configureCentroidLayer(String name,String workspace,String storeName) throws SDIInteractionException { GSFeatureTypeEncoder fte=new GSFeatureTypeEncoder(); fte.setAbstract("Centroid layer for "+name); fte.setEnabled(true); fte.setNativeCRS(DEFAULT_CRS); fte.setTitle(name); fte.setName(name); String style="clustered_centroids"; GSLayerEncoder layerEncoder=new GSLayerEncoder(); layerEncoder.setDefaultStyle(style); layerEncoder.setEnabled(true); layerEncoder.setQueryable(true); try { //Checking workspace createWorkspace(workspace); //Checking store createStoreFromPostgisDB(workspace, storeName); //Checkig layer publishStyle(Files.getFileFromResources("styles/clustered_points.sld"),style); if(gis.getCurrentGeoServer().getReader().getLayer(workspace, name)==null) if(!gis.getCurrentGeoServer().getPublisher().publishDBLayer(workspace, storeName, fte, layerEncoder)) throw new SDIInteractionException("Unable to create layer "+name); log.debug("layer "+name+" already exists"); return name; } catch (IllegalArgumentException | MalformedURLException e) { throw new SDIInteractionException("Unable to create layer "+name,e); } } public void deleteContent(GeoServerContent toDelete) throws IllegalArgumentException, MalformedURLException, RemoteServiceException { log.debug("Deleting geoserver layer "+toDelete); //delete layer GeoServerRESTPublisher publisher=gis.getCurrentGeoServer().getPublisher(); //delete store publisher.removeDatastore(toDelete.getWorkspace(), toDelete.getStore(), true); //delete WS if empty GeoServerRESTReader reader=gis.getCurrentGeoServer().getReader(); if(reader.getDatastores(toDelete.getWorkspace()).isEmpty()) { log.debug("Deleting emtpy workspace "+toDelete.getWorkspace()); publisher.removeWorkspace(toDelete.getWorkspace(), true); } //delete file dtGeoServer.getWebClient().delete(toDelete.getGeoserverPath()); } }