package org.gcube.portlets.user.geoportaldataviewer.server; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import org.gcube.application.geoportal.managers.AbstractRecordManager; import org.gcube.application.geoportal.managers.ManagerFactory; import org.gcube.application.geoportal.model.Record; import org.gcube.application.geoportal.model.concessioni.Concessione; import org.gcube.application.geoportal.model.content.UploadedImage; import org.gcube.portlets.user.geoportaldataviewer.client.GeoportalDataViewerConstants; import org.gcube.portlets.user.geoportaldataviewer.client.GeoportalDataViewerService; import org.gcube.portlets.user.geoportaldataviewer.server.gis.FeatureParser; import org.gcube.portlets.user.geoportaldataviewer.server.gis.WMSUrlValidator; import org.gcube.portlets.user.geoportaldataviewer.server.util.SessionUtil; import org.gcube.portlets.user.geoportaldataviewer.server.util.URLParserUtil; import org.gcube.portlets.user.geoportaldataviewer.shared.GeoNaDataViewerProfile; import org.gcube.portlets.user.geoportaldataviewer.shared.GeoNaItemRef; import org.gcube.portlets.user.geoportaldataviewer.shared.GeoNaSpatialQueryResult; import org.gcube.portlets.user.geoportaldataviewer.shared.PublicLink; import org.gcube.portlets.user.geoportaldataviewer.shared.gis.BoundsMap; import org.gcube.portlets.user.geoportaldataviewer.shared.gis.LayerItem; import org.gcube.portlets.user.geoportaldataviewer.shared.gis.LayerObject; import org.gcube.portlets.user.geoportaldataviewer.shared.gis.wfs.FeatureRow; import org.gcube.portlets.user.geoportaldataviewer.shared.gis.wms.GeoInformationForWMSRequest; import org.gcube.portlets.user.geoportaldataviewer.shared.gis.wms.Styles; import org.gcube.portlets.user.geoportaldataviewer.shared.gis.wms.ZAxis; import org.gcube.portlets.user.geoportaldataviewer.shared.products.ConcessioneDV; import org.gcube.portlets.user.geoportaldataviewer.shared.products.content.WorkspaceContentDV; import org.gcube.portlets.user.geoportaldataviewer.shared.products.model.UploadedImageDV; import org.gcube.portlets.user.urlshortener.UrlShortener; import org.gcube.spatial.data.geoutility.GeoNcWMSMetadataUtility; import org.gcube.spatial.data.geoutility.bean.LayerStyles; import org.gcube.spatial.data.geoutility.bean.LayerZAxis; import org.gcube.spatial.data.geoutility.bean.WmsParameters; import org.gcube.vomanagement.usermanagement.model.GCubeUser; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.gwt.user.server.rpc.RemoteServiceServlet; /** * The server side implementation of the RPC service. * * @author Francesco Mangiacrapa at ISTI-CNR (francesco.mangiacrapa@isti.cnr.it) * * Nov 12, 2020 */ @SuppressWarnings("serial") public class GeoportalDataViewerServiceImpl extends RemoteServiceServlet implements GeoportalDataViewerService { public static final String PRODUCT_ID = "product_id"; /** The Constant LOG. */ private static final Logger LOG = LoggerFactory.getLogger(GeoportalDataViewerServiceImpl.class); /** * Parses the wms request. * * @param wmsRequest the wms request * @param layerName the layer name * @return the geo information for WMS request * @throws Exception the exception */ @Override public GeoInformationForWMSRequest parseWmsRequest(String wmsRequest, String layerName) throws Exception { return loadGeoInfoForWmsRequest(wmsRequest, layerName); } /** * Load geo info for wms request. * * @param wmsLink the wms link * @param layerName the layer name * @return the geo information for WMS request * @throws Exception the exception */ public static GeoInformationForWMSRequest loadGeoInfoForWmsRequest(String wmsLink, String layerName) throws Exception{ try { WMSUrlValidator validator = new WMSUrlValidator(wmsLink, layerName); String wmsServiceHost = validator.getWmsServiceHost(); String validWMSRequest = validator.parseWMSRequest(true, true); layerName = validator.getLayerName(); String versionWms = validator.getValueOfParsedWMSParameter(WmsParameters.VERSION); String crs = validator.getValueOfParsedWMSParameter(WmsParameters.CRS); // HashMap mapWmsNotStandard = new HashMap(); if(validator.getMapWmsNoStandardParams()!=null){ mapWmsNotStandard.putAll(validator.getMapWmsNoStandardParams()); } // GeoNcWMSMetadataUtility geoGS = new GeoNcWMSMetadataUtility(validWMSRequest, 4000); //STYLES LayerStyles layerStyle = geoGS.loadStyles(); Map mapNcWmsStyles = layerStyle.getMapNcWmsStyles()==null?new HashMap(1):layerStyle.getMapNcWmsStyles(); mapWmsNotStandard.putAll(mapNcWmsStyles); //MAP STYLES INTO GWT-SERIALIZABLE OBJECT Styles styles = new Styles(layerStyle.getGeoStyles(), layerStyle.getMapNcWmsStyles(), layerStyle.isNcWms()); //ZAxis LayerZAxis layerZAxis = geoGS.loadZAxis(); //MAP ZAXIS INTO GWT-SERIALIZABLE OBJECT ZAxis zAxis = layerZAxis!=null?new ZAxis(layerZAxis.getUnits(), layerZAxis.isPositive(), layerZAxis.getValues()):null; return new GeoInformationForWMSRequest(wmsServiceHost, validWMSRequest, layerName, versionWms, crs, mapWmsNotStandard, styles, styles.isNcWms(), zAxis); } catch (Exception e) { String msg = "An error occurred during wms request validation for layer: "+layerName; LOG.error(msg,e); throw new Exception(msg); } } /** * Gets the data result. * * @param layerObjects the layer objects * @param mapSrsName the map srs name * @param selectBBOX the select BBOX * @param maxWFSFeature the max WFS feature * @param zoomLevel the zoom level * @return the data result */ @Override public List getDataResult(List layerObjects, String mapSrsName, BoundsMap selectBBOX, int maxWFSFeature, double zoomLevel) { LOG.info("getDataResult called"); List listDAO = new ArrayList(layerObjects.size()); for (LayerObject layerObject : layerObjects) { GeoNaSpatialQueryResult geoDAO = new GeoNaSpatialQueryResult(); List features = FeatureParser.getWFSFeatures(layerObject.getLayerItem(), mapSrsName, selectBBOX, maxWFSFeature); LOG.debug("For layer name: "+layerObject.getLayerItem().getName() +" got features: "+features); geoDAO.setFeatures(features); for (FeatureRow fRow : features) { if(fRow.getMapProperties()!=null) { List concessioneIds = fRow.getMapProperties().get("product_id"); if(concessioneIds!=null && concessioneIds.size()>0) { String cId = concessioneIds.get(0); try { long theConcessionID = Long.parseLong(cId); List listUI = getUploadedImagesForId("Concessione", theConcessionID, 1); Map> mapImages = new LinkedHashMap>(); mapImages.put(theConcessionID, listUI); geoDAO.setMapImages(mapImages); }catch (Exception e) { LOG.warn("Error on loading uploaded images for concessione: "+cId, e); } } } } geoDAO.setSourceLayerObject(layerObject); LOG.info("Fo layer name: "+layerObject.getLayerItem().getName() +" got "+features.size()+" feature/s"); listDAO.add(geoDAO); } LOG.info("returning "+listDAO+" geona data objects"); return listDAO; } /** * Gets the uploaded images for id. * * @param id the id * @return the uploaded images for id * @throws Exception the exception */ @Override public List getUploadedImagesForId(String itemType, Long id, int maxImages) throws Exception{ LOG.info("getConcessioneForId "+id+ "called"); if(itemType==null) throw new Exception("Invalid parameter. The itemType is null"); if(id==null) throw new Exception("Invalid parameter. The Id is null"); List listUI = null; try { LOG.info("Trying to get record for id "+id); SessionUtil.getCurrentContext(this.getThreadLocalRequest(), true); AbstractRecordManager abmRecord = ManagerFactory.getByRecordID(id); LOG.info("Got record for id "+id); Record record = abmRecord.getRecord(); Concessione concessione = null; if (record != null) { if (itemType.equalsIgnoreCase("Concessione") && record instanceof Concessione) { concessione = (Concessione) record; List images = concessione.getImmaginiRappresentative(); if (images != null) { listUI = new ArrayList(); int max = maxImages < images.size() ? maxImages : images.size(); for (int i = 0; i < max; i++) { UploadedImageDV ui = ConvertToDataViewModel.toUploadedImage(images.get(i)); listUI.add(ui); } } } } return listUI; }catch (Exception e) { String erroMsg = UploadedImage.class.getSimpleName() +" not available for "+Concessione.class.getSimpleName() +" with id "+id; LOG.error(erroMsg,e); //TODO REMOTE THIS listUI = new ArrayList(1); UploadedImageDV img = new UploadedImageDV(); List listWsContent = new ArrayList(); WorkspaceContentDV wcDV = new WorkspaceContentDV(); wcDV.setLink("https://upload.wikimedia.org/wikipedia/commons/thumb/b/b4/Tempio_di_Giove_2.jpg/1280px-Tempio_di_Giove_2.jpg"); listWsContent.add(wcDV); img.setListWsContent(listWsContent); listUI.add(img); LOG.warn("DUMMY UploadedImageDVs: "+listUI); return listUI; //throw new Exception(erroMsg); } } /** * Gets the concessione for id. * * @param id the id * @return the concessione for id * @throws Exception the exception */ @Override public ConcessioneDV getConcessioneForId(Long id) throws Exception{ LOG.info("getConcessioneForId "+id+ "called"); ConcessioneDV concessionDV = null; if(id==null) throw new Exception("Invalid parameter. The Id is null"); try { LOG.info("Trying to get record for id "+id); SessionUtil.getCurrentContext(this.getThreadLocalRequest(), true); AbstractRecordManager abmRecord = ManagerFactory.getByRecordID(id); LOG.info("Got record for id "+id); Record record = abmRecord.getRecord(); Concessione concessione = null; if(record !=null && record instanceof Concessione) { concessione = (Concessione) record; concessionDV = ConvertToDataViewModel.toConcessione(concessione); } if(concessionDV==null) throw new Exception("Concessione not retrieved"); return concessionDV; }catch (Exception e) { String erroMsg = Concessione.class.getSimpleName() +" with id "+id+" not available"; LOG.error(erroMsg,e); //TODO REMOVE THIS Concessione concessione= TestModel.prepareConcessione(); LOG.warn("DUMMY CONCESSIONE: "+concessione); ConcessioneDV theConcessione = ConvertToDataViewModel.toConcessione(concessione); LOG.warn("RETURNING DUMMY CONCESSIONE: "+theConcessione+"!!!!!\n\n\n\n"); return theConcessione; //throw new Exception(erroMsg); } } /** * Gets the parameters from URL. * * @param theURL the the URL * @param parameters the parameters * @return a map with couple (paramKey, paramValue) */ public Map getParametersFromURL(String theURL, List parameters) { if (theURL == null) return null; if (parameters == null || parameters.size() == 0) return null; Map hashParameters = new HashMap(parameters.size()); for (String paramKey : parameters) { String paramValue = URLParserUtil.extractValueOfParameterFromURL(paramKey, theURL); hashParameters.put(paramKey, paramValue); } return hashParameters; } /** * Gets the my login. * * @return the my login */ @Override public String getMyLogin(){ try { GCubeUser user = SessionUtil.getCurrentUser(this.getThreadLocalRequest()); if(user==null) return null; return user.getUsername(); }catch (Exception e) { LOG.warn("Error on getting the login, am I out of portal? Returning null"); return null; } } /** * Gets the layer for type. * * @param layerType the layer type * @return the layer for type * @throws Exception the exception */ @Override public GeoInformationForWMSRequest getLayerForType(String layerType) throws Exception{ LOG.info("Called getLayerForType for:"+layerType); if(layerType==null || layerType.isEmpty()) throw new Exception("The input parameter layerType is null or empty"); SessionUtil.getCurrentContext(this.getThreadLocalRequest(), true); GeoNaDataViewerProfileReader gdvp = new GeoNaDataViewerProfileReader("geoportal-data-viewer-app"); GeoNaDataViewerProfile profile = gdvp.readProfileFromInfrastrucure(); LOG.info("Read profile: "+profile); String lowerLayerType = layerType.toLowerCase(); LOG.info("Reading map layers for type:"+lowerLayerType); LayerItem layer = profile.getMapLayers().get(lowerLayerType); if(layer==null || layer.getWmsLink()==null) throw new Exception("The layer type "+lowerLayerType+" has not been found. Please check your input parameter"); if(layer.getWmsLink()==null) throw new Exception("The layer type "+lowerLayerType+" has not a WMS Link associated. Please check your input parameter"); return parseWmsRequest(layer.getWmsLink(), null); } /** * Gets the geo na data view profile. * * @return the geo na data view profile * @throws Exception the exception */ @Override public GeoNaDataViewerProfile getGeoNaDataViewProfile() throws Exception{ LOG.info("getGeoNaDataViewProfile called"); SessionUtil.getCurrentContext(this.getThreadLocalRequest(), true); GeoNaDataViewerProfileReader gdvp = new GeoNaDataViewerProfileReader("geoportal-data-viewer-app"); GeoNaDataViewerProfile profile = gdvp.readProfileFromInfrastrucure(); LOG.info("Returning profile: "+profile); return profile; } @Override public GeoNaItemRef getPublicLinksFor(GeoNaItemRef item) throws Exception { LOG.info("getPublicLinksFor called for: " + item); try { if (item == null) throw new Exception("Bad request, the item is null"); if(item.getItemId()==null) throw new Exception("Bad request, the item id is null"); if(item.getItemType()==null) throw new Exception("Bad request, the item type is null"); GeoNaDataViewerProfile geonaDataProfile = getGeoNaDataViewProfile(); //Restricted Link String link = String.format("%s?%s=%s&%s=%s", geonaDataProfile.getRestrictedPortletURL(), GeoportalDataViewerConstants.GET_GEONA_ITEM_ID, item.getItemId(), GeoportalDataViewerConstants.GET_GEONA_ITEM_TYPE, item.getItemType()); String shortUrl = getShortUrl(link); item.setRestrictedLink(new PublicLink(link, shortUrl)); //Open Link link = String.format("%s?%s=%s&%s=%s", geonaDataProfile.getOpenPortletURL(), GeoportalDataViewerConstants.GET_GEONA_ITEM_ID, item.getItemId(), GeoportalDataViewerConstants.GET_GEONA_ITEM_TYPE, item.getItemType()); shortUrl = getShortUrl(link); item.setOpenLink(new PublicLink(link, shortUrl)); LOG.info("returning: " + item); return item; } catch (Exception e) { LOG.error("Error on getPublicLinksFor for: " + item, e); throw new Exception("Share link not available for this item. Try later or contact the support. Error: "+e.getMessage()); } } @Override public String getShortUrl(String longUrl) throws Exception { LOG.info("getShortUrl called for " + longUrl); if(longUrl==null) return longUrl; UrlShortener shortener = SessionUtil.getUrlShortener(this.getThreadLocalRequest()); try { if (shortener != null && shortener.isAvailable()) { String toShort = longUrl; String[] splitted = toShort.split("\\?"); LOG.debug("Splitted long URL is: "+Arrays.asList(splitted)); String link = toShort; if (splitted.length > 1) { LOG.debug("Query string detected, encoding it..."); String encodedQuery = splitted[1]; try { encodedQuery = URLEncoder.encode(splitted[1], "UTF-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } LOG.debug("encodedQuery is: "+encodedQuery); link = String.format("%s?%s", splitted[0], encodedQuery); } return shortener.shorten(link); } return longUrl; } catch (Exception e) { LOG.error("Error on shortening the longURL "+longUrl, e); return null; } } public boolean isSessionExpired() throws Exception { return SessionUtil.isSessionExpired(this.getThreadLocalRequest()); } }