diff --git a/.classpath b/.classpath
index 06c0510..2ae7ba7 100644
--- a/.classpath
+++ b/.classpath
@@ -24,16 +24,16 @@
+
+
+
+
+
-
-
-
-
-
diff --git a/.settings/org.eclipse.wst.common.component b/.settings/org.eclipse.wst.common.component
index 068f0a5..74e2995 100644
--- a/.settings/org.eclipse.wst.common.component
+++ b/.settings/org.eclipse.wst.common.component
@@ -1,5 +1,7 @@
-
+
+
+
@@ -12,7 +14,9 @@
-
+
+
+
@@ -25,7 +29,9 @@
-
+
+
+
@@ -38,7 +44,9 @@
-
+
+
+
@@ -51,7 +59,9 @@
-
+
+
+
@@ -64,7 +74,12 @@
-
+
+ uses
+
+
+
+
@@ -77,7 +92,9 @@
-
+
+
+
@@ -90,7 +107,9 @@
-
+
+
+
@@ -103,7 +122,9 @@
-
+
+
+
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 79b0ac6..849df58 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,10 @@
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## [v2.9.0-SNAPSHOT]
+
+- GeoPortal-Resolver implemented [#24792]
+
## [v2.8.1] - 2022-06-13
**New**
diff --git a/pom.xml b/pom.xml
index 24dc8d2..6341e37 100644
--- a/pom.xml
+++ b/pom.xml
@@ -9,7 +9,7 @@
org.gcube.data.transfer
uri-resolver
- 2.8.1
+ 2.9.0-SNAPSHOT
war
The URI Resolver is an HTTP URI resolver implemented as a REST service which gives access trough HTTP to different gcube Resolvers and gCube Applications.
@@ -193,6 +193,22 @@
1.14.8
+
+
+ javax.xml.bind
+ jaxb-api
+ 2.3.0
+ provided
+
+
+
+
+ org.projectlombok
+ lombok
+ 1.18.4
+ provided
+
+
@@ -202,6 +218,15 @@
compile
+
+
+ org.opengis
+ geoapi
+ 3.0.1
+ provided
+
+
commons-lang
commons-lang
@@ -249,7 +274,7 @@
4.8.2
test
-
+
diff --git a/src/main/java/org/gcube/datatransfer/resolver/catalogue/ResourceCatalogueCodes.java b/src/main/java/org/gcube/datatransfer/resolver/catalogue/ResourceCatalogueCodes.java
index 57fb069..ce3051c 100644
--- a/src/main/java/org/gcube/datatransfer/resolver/catalogue/ResourceCatalogueCodes.java
+++ b/src/main/java/org/gcube/datatransfer/resolver/catalogue/ResourceCatalogueCodes.java
@@ -3,35 +3,34 @@
*/
package org.gcube.datatransfer.resolver.catalogue;
-import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
-
+import java.util.stream.Collectors;
/**
* The Enum ResourceCatalogueCodes.
*
- * @author Francesco Mangiacrapa francesco.mangiacrapa@isti.cnr.it
- * Jan 31, 2017
+ * @author Francesco Mangiacrapa francesco.mangiacrapa@isti.cnr.it Jan 31, 2017
*
- * see wiki page: https://wiki.gcube-system.org/gcube/URI_Resolver#CATALOGUE_Resolver
+ * see wiki page:
+ * https://wiki.gcube-system.org/gcube/URI_Resolver#CATALOGUE_Resolver
*/
public enum ResourceCatalogueCodes {
- CTLG("ctlg","dataset", "Catalogue Product/Dataset"),
- //CTLGP("ctlg-p","product", "Catalogue Product"),
- CTLGD("ctlg-d","dataset", "Catalogue Dataset"),
- CTLGO("ctlg-o","organization", "Catalogue Organization"),
- CTLGG("ctlg-g","group", "Catalogue Group");
+ CTLG("ctlg", "dataset", "Catalogue Product/Dataset"),
+ // CTLGP("ctlg-p","product", "Catalogue Product"),
+ CTLGD("ctlg-d", "dataset", "Catalogue Dataset"), CTLGO("ctlg-o", "organization", "Catalogue Organization"),
+ CTLGG("ctlg-g", "group", "Catalogue Group");
- private String id; //the code id
- private String value; //the code value
+ private String id; // the code id
+ private String value; // the code value
private String description;
/**
* Instantiates a new resource catalogue codes.
*
- * @param id the id
- * @param value the value
+ * @param id the id
+ * @param value the value
* @param description the description
*/
private ResourceCatalogueCodes(String id, String value, String description) {
@@ -50,7 +49,6 @@ public enum ResourceCatalogueCodes {
return id;
}
-
/**
* Gets the value.
*
@@ -61,7 +59,6 @@ public enum ResourceCatalogueCodes {
return value;
}
-
/**
* Gets the description.
*
@@ -72,40 +69,37 @@ public enum ResourceCatalogueCodes {
return description;
}
-
/**
* Codes.
*
* @return the list
*/
- public static List codes(){
+ public static List codes() {
- List codes = new ArrayList(ResourceCatalogueCodes.values().length);
- for (ResourceCatalogueCodes value : ResourceCatalogueCodes.values()) {
- codes.add(value.getId());
- }
-
- return codes;
+ return Arrays.asList(ResourceCatalogueCodes.values()).stream().map(ResourceCatalogueCodes::getId)
+ .collect(Collectors.toList());
}
-
/**
* Value of code id.
*
* @param id the id
* @return the resource catalogue codes
*/
- public static ResourceCatalogueCodes valueOfCodeId(String id){
- if(id==null || id.isEmpty())
+ public static ResourceCatalogueCodes valueOfCodeId(String id) {
+ if (id == null || id.isEmpty())
return null;
- for (ResourceCatalogueCodes value : ResourceCatalogueCodes.values()) {
- if(value.id.compareTo(id)==0)
- return value;
- }
- return null;
- }
+ List codes = Arrays.asList(ResourceCatalogueCodes.values()).stream()
+ .filter(r -> r.getId().compareTo(id) == 0)
+ .collect(Collectors.toList());
+ if (codes == null || codes.isEmpty())
+ return null;
+
+ return codes.get(0);
+
+ }
/**
* Value of code value.
@@ -113,14 +107,17 @@ public enum ResourceCatalogueCodes {
* @param codeValue the code value
* @return the resource catalogue codes
*/
- public static ResourceCatalogueCodes valueOfCodeValue(String codeValue){
- if(codeValue==null || codeValue.isEmpty())
+ public static ResourceCatalogueCodes valueOfCodeValue(String codeValue) {
+ if (codeValue == null || codeValue.isEmpty())
return null;
- for (ResourceCatalogueCodes rcc : ResourceCatalogueCodes.values()) {
- if(rcc.value.compareTo(codeValue)==0)
- return rcc;
- }
- return null;
+ List codes = Arrays.asList(ResourceCatalogueCodes.values()).stream()
+ .filter(r -> r.getValue().compareTo(codeValue) == 0)
+ .collect(Collectors.toList());
+
+ if (codes == null || codes.isEmpty())
+ return null;
+
+ return codes.get(0);
}
}
diff --git a/src/main/java/org/gcube/datatransfer/resolver/geoportal/GeoportalCommonConstants.java b/src/main/java/org/gcube/datatransfer/resolver/geoportal/GeoportalCommonConstants.java
new file mode 100644
index 0000000..b2ff4d5
--- /dev/null
+++ b/src/main/java/org/gcube/datatransfer/resolver/geoportal/GeoportalCommonConstants.java
@@ -0,0 +1,17 @@
+package org.gcube.datatransfer.resolver.geoportal;
+
+/**
+ * The Class GeoportalCommonConstants.
+ *
+ * @author Francesco Mangiacrapa at ISTI-CNR (francesco.mangiacrapa@isti.cnr.it)
+ *
+ * Dec 1, 2020
+ */
+public class GeoportalCommonConstants {
+
+ public static final String GET_GEONA_ITEM_TYPE = "git";
+ public static final String GET_GEONA_ITEM_ID = "gid";
+
+ public static final String GEOPORTAL_DATA_VIEWER_APP = "geoportal-data-viewer-app";
+
+}
diff --git a/src/main/java/org/gcube/datatransfer/resolver/geoportal/GeoportalDataViewerConfigProfile.java b/src/main/java/org/gcube/datatransfer/resolver/geoportal/GeoportalDataViewerConfigProfile.java
new file mode 100644
index 0000000..b3c0c73
--- /dev/null
+++ b/src/main/java/org/gcube/datatransfer/resolver/geoportal/GeoportalDataViewerConfigProfile.java
@@ -0,0 +1,75 @@
+package org.gcube.datatransfer.resolver.geoportal;
+
+import java.io.Serializable;
+
+/**
+ * The Class GeoportalDataViewerConfigProfile.
+ *
+ * @author Francesco Mangiacrapa at ISTI-CNR francesco.mangiacrapa@isti.cnr.it
+ *
+ * Dec 21, 2021
+ */
+public class GeoportalDataViewerConfigProfile implements Serializable {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 2968334957258327191L;
+ private String restrictedPortletURL;
+ private String openPortletURL;
+
+ /**
+ * Instantiates a new geo na data viewer profile.
+ */
+ public GeoportalDataViewerConfigProfile() {
+
+ }
+
+ /**
+ * Gets the restricted portlet URL.
+ *
+ * @return the restricted portlet URL
+ */
+ public String getRestrictedPortletURL() {
+ return restrictedPortletURL;
+ }
+
+ /**
+ * Sets the restricted portlet URL.
+ *
+ * @param restrictedPortletURL the new restricted portlet URL
+ */
+ public void setRestrictedPortletURL(String restrictedPortletURL) {
+ this.restrictedPortletURL = restrictedPortletURL;
+ }
+
+ /**
+ * Gets the open portlet URL.
+ *
+ * @return the open portlet URL
+ */
+ public String getOpenPortletURL() {
+ return openPortletURL;
+ }
+
+ /**
+ * Sets the open portlet URL.
+ *
+ * @param openPortletURL the new open portlet URL
+ */
+ public void setOpenPortletURL(String openPortletURL) {
+ this.openPortletURL = openPortletURL;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("GeoportalDataViewerConfigProfile [restrictedPortletURL=");
+ builder.append(restrictedPortletURL);
+ builder.append(", openPortletURL=");
+ builder.append(openPortletURL);
+ builder.append("]");
+ return builder.toString();
+ }
+
+}
diff --git a/src/main/java/org/gcube/datatransfer/resolver/geoportal/GeoportalDataViewerConfigProfileReader.java b/src/main/java/org/gcube/datatransfer/resolver/geoportal/GeoportalDataViewerConfigProfileReader.java
new file mode 100644
index 0000000..5b8fb8b
--- /dev/null
+++ b/src/main/java/org/gcube/datatransfer/resolver/geoportal/GeoportalDataViewerConfigProfileReader.java
@@ -0,0 +1,170 @@
+package org.gcube.datatransfer.resolver.geoportal;
+
+import static org.gcube.resources.discovery.icclient.ICFactory.client;
+
+import java.io.StringReader;
+import java.util.List;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import org.gcube.common.resources.gcore.utils.XPathHelper;
+import org.gcube.common.scope.api.ScopeProvider;
+import org.gcube.datatransfer.resolver.applicationprofile.ApplicationProfileNotFoundException;
+import org.gcube.resources.discovery.client.api.DiscoveryClient;
+import org.gcube.resources.discovery.client.queries.api.Query;
+import org.gcube.resources.discovery.client.queries.impl.QueryBox;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.xml.sax.InputSource;
+
+/**
+ * The Class GeoportalDataViewerConfigProfileReader.
+ *
+ * @author Francesco Mangiacrapa at ISTI-CNR francesco.mangiacrapa@isti.cnr.it
+ *
+ * Mar 23, 2023
+ */
+public class GeoportalDataViewerConfigProfileReader {
+
+ private static final String RESOURCE_PROFILE_BODY = "/Resource/Profile/Body";
+ public static final String SECONDARY_TYPE = "ApplicationProfile";
+ public static final String GENERIC_RESOURCE_NAME = "Geoportal-DataViewer-Configs";
+
+ private static Logger LOG = LoggerFactory.getLogger(GeoportalDataViewerConfigProfileReader.class);
+ private String secondaryType;
+ private String scope;
+ private String appID;
+ private GeoportalDataViewerConfigProfile geoportalDataViewerConfigProfile;
+
+ /**
+ * Instantiates a new geoportal data viewer config profile reader.
+ *
+ * @param appID the app ID
+ * @throws Exception the exception
+ */
+ public GeoportalDataViewerConfigProfileReader(String appID) throws Exception {
+
+ this.appID = appID;
+ this.secondaryType = SECONDARY_TYPE;
+ this.scope = ScopeProvider.instance.get();
+ this.geoportalDataViewerConfigProfile = readProfileFromInfrastructure();
+ }
+
+ /**
+ * Read profile from infrastrucure.
+ *
+ * @return the map
+ * @throws Exception the exception
+ */
+ private GeoportalDataViewerConfigProfile readProfileFromInfrastructure() throws Exception {
+
+ String queryString = getGcubeGenericQueryString(secondaryType, appID);
+ LOG.info("Scope " + scope + ", trying to perform query: " + queryString);
+
+ try {
+
+ if (scope == null)
+ throw new Exception("Scope is null, set scope into ScopeProvider");
+
+ GeoportalDataViewerConfigProfile profile = new GeoportalDataViewerConfigProfile();
+
+ LOG.info("Trying to fetch ApplicationProfile in the scope: " + scope + ", SecondaryType: " + secondaryType
+ + ", AppId: " + appID);
+ Query q = new QueryBox(queryString);
+ DiscoveryClient client = client();
+ List appProfile = client.submit(q);
+// String item_fields = "";
+
+ if (appProfile == null || appProfile.size() == 0)
+ throw new ApplicationProfileNotFoundException("ApplicationProfile with SecondaryType: " + secondaryType
+ + ", AppId: " + appID + " is not registered in the scope: " + scope);
+ else {
+ String elem = appProfile.get(0);
+ DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+ Document doc = docBuilder.parse(new InputSource(new StringReader(elem)));
+
+ XPathHelper helper = new XPathHelper(doc.getDocumentElement());
+
+ List currValue = null;
+ String xPathExp = RESOURCE_PROFILE_BODY + "/RestrictedPortletURL/text()";
+ currValue = helper.evaluate(xPathExp);
+ if (currValue != null && currValue.size() > 0) {
+ profile.setRestrictedPortletURL(currValue.get(0));
+ } else
+ throw new Exception("I'm not able to read the path: " + xPathExp);
+
+ xPathExp = RESOURCE_PROFILE_BODY + "/OpenPortletURL/text()";
+ currValue = helper.evaluate(xPathExp);
+ if (currValue != null && currValue.size() > 0) {
+ profile.setOpenPortletURL(currValue.get(0));
+ } else
+ throw new Exception("I'm not able to read the path: " + xPathExp);
+
+ LOG.info("returning: " + profile);
+ return profile;
+ }
+
+ } catch (Exception e) {
+ LOG.error("Error while trying to read the " + SECONDARY_TYPE + " with SecondaryType "
+ + GENERIC_RESOURCE_NAME + " from scope " + scope, e);
+ return null;
+ } finally {
+
+ }
+
+ }
+
+ public GeoportalDataViewerConfigProfile getGeoportalDataViewerConfigProfile() {
+ return geoportalDataViewerConfigProfile;
+ }
+
+ /**
+ * Gets the gcube generic query string.
+ *
+ * @param secondaryType the secondary type
+ * @param appId the app id
+ * @return the gcube generic query string
+ */
+ public static String getGcubeGenericQueryString(String secondaryType, String appId) {
+
+ return "for $profile in collection('/db/Profiles/GenericResource')//Resource "
+ + "where $profile/Profile/SecondaryType/string() eq '" + secondaryType
+ + "' and $profile/Profile/Body/AppId/string() " + " eq '" + appId + "'" + "return $profile";
+ }
+
+ /**
+ * Gets the secondary type.
+ *
+ * @return the secondary type
+ */
+ public String getSecondaryType() {
+ return secondaryType;
+ }
+
+ /**
+ * Gets the scope.
+ *
+ * @return the scope
+ */
+ public String getScope() {
+ return scope;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("GeoportalDataViewerConfigProfileReader [secondaryType=");
+ builder.append(secondaryType);
+ builder.append(", scope=");
+ builder.append(scope);
+ builder.append(", appID=");
+ builder.append(appID);
+ builder.append(", geoportalDataViewerConfigProfile=");
+ builder.append(geoportalDataViewerConfigProfile);
+ builder.append("]");
+ return builder.toString();
+ }
+
+}
diff --git a/src/main/java/org/gcube/datatransfer/resolver/geoportal/GeoportalRequest.java b/src/main/java/org/gcube/datatransfer/resolver/geoportal/GeoportalRequest.java
new file mode 100644
index 0000000..3bf4206
--- /dev/null
+++ b/src/main/java/org/gcube/datatransfer/resolver/geoportal/GeoportalRequest.java
@@ -0,0 +1,40 @@
+package org.gcube.datatransfer.resolver.geoportal;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+
+
+/**
+ * The Class GeoportalRequest.
+ *
+ * @author Francesco Mangiacrapa at ISTI-CNR francesco.mangiacrapa@isti.cnr.it
+ *
+ * Mar 23, 2023
+ */
+@Slf4j
+@Data
+public class GeoportalRequest {
+
+ public static final String P_GCUBE_SCOPE = "gcube_scope";
+ public static final String P_ITEM_TYPE = "item_type";
+ public static final String P_ITEM_ID = "item_id";
+ public static final String P_QUERY_STRING = "query_string";
+
+ @JsonProperty(P_GCUBE_SCOPE)
+ private String gcubeScope;
+ /**
+ * It is the UCD ID {usecase_id}
+ */
+ @JsonProperty(P_ITEM_TYPE)
+ private String itemType;
+ /**
+ * It is the Project ID {project_id}
+ */
+ @JsonProperty(P_ITEM_ID)
+ private String itemID;
+ @JsonProperty(P_QUERY_STRING)
+ private String queryString;
+
+}
diff --git a/src/main/java/org/gcube/datatransfer/resolver/geoportal/TargetAppGeoportalCodes.java b/src/main/java/org/gcube/datatransfer/resolver/geoportal/TargetAppGeoportalCodes.java
new file mode 100644
index 0000000..2e074ca
--- /dev/null
+++ b/src/main/java/org/gcube/datatransfer/resolver/geoportal/TargetAppGeoportalCodes.java
@@ -0,0 +1,121 @@
+/**
+ *
+ */
+package org.gcube.datatransfer.resolver.geoportal;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.gcube.datatransfer.resolver.services.GeoportalResolver;
+
+/**
+ * The Enum TargetAppGeoportalCodes.
+ *
+ * @author Francesco Mangiacrapa at ISTI-CNR francesco.mangiacrapa@isti.cnr.it
+ *
+ * Mar 24, 2023
+ */
+public enum TargetAppGeoportalCodes {
+
+ GEO_DV(GeoportalResolver.GEO_DV, "data-viewer", "Geoportal Viewer"),
+ GEO_DE(GeoportalResolver.GEO_DE, "data-entry", "Geoportal Entry");
+
+ private String id; // the code id
+ private String name; // the code value
+ private String description;
+
+ /**
+ * Instantiates a new resource catalogue codes.
+ *
+ * @param id the id
+ * @param name the target app
+ * @param description the description
+ */
+ private TargetAppGeoportalCodes(String id, String name, String description) {
+ this.id = id;
+ this.name = name;
+ this.description = description;
+ }
+
+ /**
+ * Gets the id.
+ *
+ * @return the id
+ */
+ public String getId() {
+
+ return id;
+ }
+
+ /**
+ * Gets the target app.
+ *
+ * @return the target app
+ */
+ public String getTarget_app() {
+ return name;
+ }
+
+ /**
+ * Gets the description.
+ *
+ * @return the description
+ */
+ public String getDescription() {
+
+ return description;
+ }
+
+ /**
+ * Codes.
+ *
+ * @return the list
+ */
+ public static List codes() {
+
+ return Arrays.asList(TargetAppGeoportalCodes.values()).stream().map(TargetAppGeoportalCodes::getId)
+ .collect(Collectors.toList());
+ }
+
+ /**
+ * Value of id.
+ *
+ * @param id the id
+ * @return the target app geoportal codes
+ */
+ public static TargetAppGeoportalCodes valueOfId(String id) {
+ if (id == null || id.isEmpty())
+ return null;
+
+ List codes = Arrays.asList(TargetAppGeoportalCodes.values()).stream()
+ .filter(value -> value.getId().compareTo(id) == 0).collect(Collectors.toList());
+
+ if (codes == null || codes.isEmpty())
+ return null;
+
+ return codes.get(0);
+
+ }
+
+ /**
+ * Value of name.
+ *
+ * @param name the name
+ * @return the target app geoportal codes
+ */
+ public static TargetAppGeoportalCodes valueOfName(String name) {
+ if (name == null || name.isEmpty())
+ return null;
+
+ List codes = Arrays.asList(TargetAppGeoportalCodes.values()).stream()
+ .filter(value -> value.getTarget_app().compareTo(name) == 0).collect(Collectors.toList());
+
+ if (codes == null || codes.isEmpty())
+ return null;
+
+ return codes.get(0);
+
+ }
+
+}
diff --git a/src/main/java/org/gcube/datatransfer/resolver/services/CatalogueResolver.java b/src/main/java/org/gcube/datatransfer/resolver/services/CatalogueResolver.java
index 05bb132..06baae6 100644
--- a/src/main/java/org/gcube/datatransfer/resolver/services/CatalogueResolver.java
+++ b/src/main/java/org/gcube/datatransfer/resolver/services/CatalogueResolver.java
@@ -132,7 +132,8 @@ public class CatalogueResolver {
if (!(e instanceof WebApplicationException)) {
// UNEXPECTED EXCEPTION managing it as WebApplicationException
- String error = "Error occurred on resolving the Catalgoue URL. Please, contact the support!";
+ String error = "Error occurred on resolving the " + CatalogueResolver.class.getSimpleName()
+ + " URL. Please, contact the support!";
if (e.getCause() != null)
error += "\n\nCaused: " + e.getCause().getMessage();
throw ExceptionManager.internalErrorException(req, error, this.getClass(), helpURI);
@@ -207,14 +208,15 @@ public class CatalogueResolver {
linkURL += "?" + jsonRequest.getQuery_string();
}
- logger.info("Returining Catalogue URL: " + linkURL);
+ logger.info("Returning " + CatalogueResolver.class.getSimpleName() + " URL: " + linkURL);
return Response.ok(linkURL).header("Location", linkURL).build();
} catch (Exception e) {
if (!(e instanceof WebApplicationException)) {
// UNEXPECTED EXCEPTION managing it as WebApplicationException
- String error = "Error occurred on resolving the Analytics URL. Please, contact the support!";
+ String error = "Error occurred on creating the " + CatalogueResolver.class.getSimpleName()
+ + " URL. Please, contact the support!";
throw ExceptionManager.internalErrorException(req, error, this.getClass(), helpURI);
}
// ALREADY MANAGED AS WebApplicationExceptiongetItemCatalogueURLs
diff --git a/src/main/java/org/gcube/datatransfer/resolver/services/GeoportalResolver.java b/src/main/java/org/gcube/datatransfer/resolver/services/GeoportalResolver.java
new file mode 100644
index 0000000..eab1704
--- /dev/null
+++ b/src/main/java/org/gcube/datatransfer/resolver/services/GeoportalResolver.java
@@ -0,0 +1,497 @@
+package org.gcube.datatransfer.resolver.services;
+
+import java.net.URL;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+import java.util.stream.Collectors;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.gcube.common.scope.api.ScopeProvider;
+import org.gcube.common.scope.impl.ScopeBean;
+import org.gcube.datatransfer.resolver.ConstantsResolver;
+import org.gcube.datatransfer.resolver.caches.LoadingMapOfScopeCache;
+import org.gcube.datatransfer.resolver.geoportal.GeoportalCommonConstants;
+import org.gcube.datatransfer.resolver.geoportal.GeoportalDataViewerConfigProfile;
+import org.gcube.datatransfer.resolver.geoportal.GeoportalDataViewerConfigProfileReader;
+import org.gcube.datatransfer.resolver.geoportal.GeoportalRequest;
+import org.gcube.datatransfer.resolver.geoportal.TargetAppGeoportalCodes;
+import org.gcube.datatransfer.resolver.services.error.ExceptionManager;
+import org.gcube.datatransfer.resolver.util.Util;
+import org.gcube.smartgears.utils.InnerMethodName;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.cache.CacheLoader.InvalidCacheLoadException;
+
+/**
+ * The GeoportalResolver is able to get/resolve a link to "Geoportal Viewer" or
+ * "Geoportal Entry" Application.
+ *
+ * See more at
+ * https://gcube.wiki.gcube-system.org/gcube/URI_Resolver#Geoportal_Resolver
+ *
+ * @author Francesco Mangiacrapa at ISTI-CNR francesco.mangiacrapa@isti.cnr.it
+ *
+ * Mar 23, 2023
+ */
+@Path("/geo")
+public class GeoportalResolver {
+
+ public static final String GEO_DE = "de"; // data-entry
+ public static final String GEO = "geo"; // geoportal
+ public static final String GEO_DV = "dv"; // data-viewer
+
+ private static final String QP_RESOLVE_AS = "res";
+ private static final String PATH_PROJECT_ID = "project_id";
+ private static final String PATH_USECASE_ID = "usecase_id";
+ private static final String PATH_VRE_NAME = "vre_name";
+ private static final String PATH_TARGET_APP = "targetAppId";
+
+ private static final Logger LOG = LoggerFactory.getLogger(GeoportalResolver.class);
+ private static String helpURI = "https://wiki.gcube-system.org/gcube/URI_Resolver#Geoportal_Resolver";
+
+ /**
+ * The Enum RESOLVE_AS_PARAMETER.
+ *
+ * @author Francesco Mangiacrapa at ISTI-CNR francesco.mangiacrapa@isti.cnr.it
+ *
+ * Mar 24, 2023
+ */
+ private static enum RESOLVE_AS {
+ PUBLIC, PRIVATE
+ }
+
+ /**
+ * Resolve geoportal. Resolve a Geoportal Link to "Data-Viewer" App
+ *
+ * @param req the req
+ * @param vreName the vre name
+ * @param ucdID the ucd ID
+ * @param projectID the project ID
+ * @param resolveAs the resolve as
+ * @return the response
+ * @throws WebApplicationException the web application exception
+ */
+ @GET
+ @Path("/{vre_name}/{usecase_id}/{project_id}")
+ public Response resolveGeoportalNoAppDef(@Context HttpServletRequest req, @PathParam(PATH_VRE_NAME) String vreName,
+ @PathParam(PATH_USECASE_ID) String ucdID, @PathParam(PATH_PROJECT_ID) String projectID,
+ @QueryParam(QP_RESOLVE_AS) String resolveAs) throws WebApplicationException {
+
+ LOG.info(this.getClass().getSimpleName() + " resolveGeoportalNoAppDef - GET starts...");
+ TargetAppGeoportalCodes targetAppGeoportalCodes = checkTargetApplictionID(req, null);
+ LOG.info("The target app is: " + targetAppGeoportalCodes);
+ return genericResolveLink(req, targetAppGeoportalCodes, vreName, ucdID, projectID, resolveAs);
+
+ }
+
+ /**
+ * Resolve geoportal. Resolve a Geoportal Link to "Data-Viewer" or "Data-Entry"
+ * App
+ *
+ * @param req the req
+ * @param targetAppId the target app id
+ * @param vreName the vre name
+ * @param ucdID the ucd ID
+ * @param projectID the project ID
+ * @param resolveAs the resolve as
+ * @return the response
+ * @throws WebApplicationException the web application exception
+ */
+ @GET
+ @Path("/{targetAppId}/{vre_name}/{usecase_id}/{project_id}")
+ public Response resolveGeoportal(@Context HttpServletRequest req, @PathParam(PATH_TARGET_APP) String targetAppId,
+ @PathParam(PATH_VRE_NAME) String vreName, @PathParam(PATH_USECASE_ID) String ucdID,
+ @PathParam(PATH_PROJECT_ID) String projectID, @QueryParam(QP_RESOLVE_AS) String resolveAs)
+ throws WebApplicationException {
+
+ LOG.info(this.getClass().getSimpleName() + " resolveGeoportal - GET starts...");
+ TargetAppGeoportalCodes targetAppGeoportalCodes = checkTargetApplictionID(req, targetAppId);
+ LOG.info("The target app is: " + targetAppGeoportalCodes);
+ return genericResolveLink(req, targetAppGeoportalCodes, vreName, ucdID, projectID, resolveAs);
+
+ }
+
+ /**
+ * Resolve data viewer link.
+ *
+ * @param req the req
+ * @param gcubeScope the gcube scope
+ * @param itemId the item id
+ * @param itemType the item type
+ * @param resolveAs the resolve as
+ * @return the response
+ * @throws WebApplicationException the web application exception
+ */
+ @GET
+ @Path("/")
+ public Response resolveDataViewerLink(@Context HttpServletRequest req,
+ @QueryParam(GeoportalRequest.P_GCUBE_SCOPE) String gcubeScope,
+ @QueryParam(GeoportalRequest.P_ITEM_ID) String itemId,
+ @QueryParam(GeoportalRequest.P_ITEM_TYPE) String itemType,
+ @QueryParam(QP_RESOLVE_AS) String resolveAs)
+ throws WebApplicationException {
+
+ LOG.info(this.getClass().getSimpleName() + " resolveDataViewerLink - GET starts...");
+ TargetAppGeoportalCodes targetAppGeoportalCodes = checkTargetApplictionID(req, null);
+ LOG.info("The target app is: " + targetAppGeoportalCodes);
+
+ if (gcubeScope == null || gcubeScope.isEmpty()) {
+
+ LOG.error("The query parameter '" + GeoportalRequest.P_GCUBE_SCOPE + "' not found or empty");
+ throw ExceptionManager.badRequestException(req,
+ "Mandatory query parameter '" + GeoportalRequest.P_GCUBE_SCOPE + "' not found or empty",
+ this.getClass(), helpURI);
+
+ }
+
+ String scope = gcubeScope.substring(gcubeScope.lastIndexOf("/") + 1, gcubeScope.length());
+ return genericResolveLink(req, targetAppGeoportalCodes, scope, itemType, itemId, resolveAs);
+
+ }
+
+ /**
+ * Post geoportal. Create a Geoportal Link to "Data-Viewer" App
+ *
+ * @param req the req
+ * @param jsonRequest the json request
+ * @return the response
+ * @throws WebApplicationException the web application exception
+ */
+ @POST
+ @Path("")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.TEXT_PLAIN)
+ public Response postGeoportalNoAppDef(@Context HttpServletRequest req, GeoportalRequest jsonRequest)
+ throws WebApplicationException {
+
+ LOG.info(this.getClass().getSimpleName() + " postGeoportalNoAppDef - POST starts...");
+ TargetAppGeoportalCodes targetAppGeoportalCodes = checkTargetApplictionID(req, null);
+ LOG.info("The target app is: " + targetAppGeoportalCodes);
+ String linkURL = genericCreateLink(req, jsonRequest, targetAppGeoportalCodes);
+ return Response.ok(linkURL).header("Location", linkURL).build();
+ }
+
+ /**
+ * Post geoportal. Create a Geoportal Link to "Data-Viewer" or "Data-Entry" App
+ *
+ * @param req the req
+ * @param targetAppId the target app id
+ * @param jsonRequest the json request
+ * @return the response
+ * @throws WebApplicationException the web application exception
+ */
+ @POST
+ @Path("/{targetAppId}")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.TEXT_PLAIN)
+ public Response postGeoportal(@Context HttpServletRequest req, @PathParam(PATH_TARGET_APP) String targetAppId,
+ GeoportalRequest jsonRequest) throws WebApplicationException {
+
+ LOG.info(this.getClass().getSimpleName() + " postGeoportal - POST starts...");
+ TargetAppGeoportalCodes targetAppGeoportalCodes = checkTargetApplictionID(req, targetAppId);
+ LOG.info("The target app is: " + targetAppGeoportalCodes);
+ String linkURL = genericCreateLink(req, jsonRequest, targetAppGeoportalCodes);
+ return Response.ok(linkURL).header("Location", linkURL).build();
+ }
+
+ /**
+ * Check target appliction ID.
+ *
+ * @param req the req
+ * @param targetAppId the target app id
+ * @return the target app geoportal codes
+ */
+ private TargetAppGeoportalCodes checkTargetApplictionID(@Context HttpServletRequest req, String targetAppId) {
+
+ TargetAppGeoportalCodes targetAppGeoportalCodes = null;
+
+ if (targetAppId == null) {
+ targetAppGeoportalCodes = TargetAppGeoportalCodes.GEO_DV;
+ LOG.warn("Target application parameter is null, using default: " + targetAppGeoportalCodes);
+ } else {
+
+ // IF the target application passed in the request. It must be proper.
+ targetAppGeoportalCodes = TargetAppGeoportalCodes.valueOfId(targetAppId);
+
+ if (targetAppGeoportalCodes == null) {
+ LOG.error("Target application parameter is malformed");
+ List targetApps = Arrays.asList(TargetAppGeoportalCodes.values()).stream()
+ .map(TargetAppGeoportalCodes::getTarget_app).collect(Collectors.toList());
+ throw ExceptionManager.badRequestException(req,
+ "Target application is wrong. It must be one value of: " + targetApps, this.getClass(),
+ helpURI);
+ }
+ }
+
+ return targetAppGeoportalCodes;
+
+ }
+
+ /**
+ * Generic resolve link.
+ *
+ * @param req the req
+ * @param resoruceGeoportalCodes the resoruce geoportal codes
+ * @param vreName the vre name
+ * @param ucdID the ucd ID
+ * @param projectID the project ID
+ * @param resolveAs the resolve as
+ * @return the response
+ * @throws WebApplicationException the web application exception
+ */
+ public Response genericResolveLink(@Context HttpServletRequest req, TargetAppGeoportalCodes resoruceGeoportalCodes,
+ @PathParam(PATH_VRE_NAME) String vreName, @PathParam(PATH_USECASE_ID) String ucdID,
+ @PathParam(PATH_PROJECT_ID) String projectID, @QueryParam(QP_RESOLVE_AS) String resolveAs)
+ throws WebApplicationException {
+
+ LOG.info(this.getClass().getSimpleName() + " genericResolveLink starts...");
+
+ try {
+ InnerMethodName.instance.set("resolveGeoportalPublicLink");
+
+ LOG.info("Found target app: " + resoruceGeoportalCodes);
+
+ if (resoruceGeoportalCodes == null) {
+ LOG.error("The path parameter '" + PATH_TARGET_APP + "' not found or empty in the path");
+ throw ExceptionManager.badRequestException(req,
+ "Mandatory path parameter '" + PATH_TARGET_APP + "' not found or empty", this.getClass(),
+ helpURI);
+ }
+
+ if (vreName == null || vreName.isEmpty()) {
+ LOG.error("The path parameter '" + PATH_VRE_NAME + "' not found or empty in the path");
+ throw ExceptionManager.badRequestException(req,
+ "Mandatory path parameter '" + PATH_VRE_NAME + "' not found or empty", this.getClass(),
+ helpURI);
+ }
+
+ if (ucdID == null) {
+ LOG.error("The path parameter '" + PATH_USECASE_ID + "' not found or empty in the path");
+ throw ExceptionManager.badRequestException(req,
+ "Mandatory path parameter '" + PATH_USECASE_ID + "' not found or empty", this.getClass(),
+ helpURI);
+ }
+
+ if (projectID == null) {
+ LOG.error("The path parameter '" + PATH_PROJECT_ID + "' not found or empty in the path");
+ throw ExceptionManager.badRequestException(req,
+ "Mandatory path parameter '" + PATH_PROJECT_ID + "' not found or empty", this.getClass(),
+ helpURI);
+ }
+
+ ScopeBean fullScopeBean = null;
+
+ // CHECKING IF THE INPUT VRE NAME IS REGISTRED IN THE INFRASTRUCTURE...
+ try {
+ fullScopeBean = LoadingMapOfScopeCache.get(vreName);
+ } catch (ExecutionException | InvalidCacheLoadException e) {
+ LOG.error("Error on getting the fullscope from cache for vreName " + vreName, e);
+ throw ExceptionManager.wrongParameterException(req,
+ "Error on getting full scope for the VRE name " + vreName
+ + ". Is it registered as VRE in the D4Science Infrastructure System?",
+ this.getClass(), helpURI);
+ }
+
+ RESOLVE_AS resolveTO = RESOLVE_AS.PUBLIC;
+ if (resolveAs != null) {
+ switch (resolveAs.toLowerCase()) {
+ case "public":
+ resolveTO = RESOLVE_AS.PUBLIC;
+ break;
+ case "private":
+ resolveTO = RESOLVE_AS.PRIVATE;
+ break;
+ }
+ }
+
+ LOG.info("Found RESOLVE_AS_PARAMETER: " + resolveAs);
+
+ String originalScope = ScopeProvider.instance.get();
+ GeoportalDataViewerConfigProfileReader reader;
+ try {
+ String theScope = fullScopeBean.toString();
+ LOG.info("Full scope is: " + theScope);
+ ScopeProvider.instance.set(theScope);
+ reader = new GeoportalDataViewerConfigProfileReader(
+ org.gcube.datatransfer.resolver.geoportal.GeoportalCommonConstants.GEOPORTAL_DATA_VIEWER_APP);
+ } catch (Exception e) {
+ LOG.error("Error on reading the " + GeoportalDataViewerConfigProfileReader.SECONDARY_TYPE
+ + " with generic resource name: "
+ + GeoportalDataViewerConfigProfileReader.GENERIC_RESOURCE_NAME, e);
+ throw ExceptionManager.internalErrorException(req,
+ "Error on reading the " + GeoportalDataViewerConfigProfileReader.SECONDARY_TYPE + " for name "
+ + GeoportalDataViewerConfigProfileReader.GENERIC_RESOURCE_NAME
+ + ". Please contact the support",
+ this.getClass(), helpURI);
+ } finally {
+ if (originalScope != null && !originalScope.isEmpty()) {
+ ScopeProvider.instance.set(originalScope);
+ LOG.info("scope provider set to orginal scope: " + originalScope);
+ } else {
+ ScopeProvider.instance.reset();
+ LOG.info("scope provider reset");
+ }
+ }
+
+ // Resolving towards Data-Viewer or Data-Entry Application
+ String itemLink = null;
+
+ switch (resoruceGeoportalCodes) {
+ case GEO_DV: {
+
+ GeoportalDataViewerConfigProfile geonaDataProfile = reader.getGeoportalDataViewerConfigProfile();
+
+ switch (resolveTO) {
+ case PUBLIC:
+ // Open Link
+ itemLink = String.format("%s?%s=%s&%s=%s", geonaDataProfile.getOpenPortletURL(),
+ GeoportalCommonConstants.GET_GEONA_ITEM_ID, projectID,
+ GeoportalCommonConstants.GET_GEONA_ITEM_TYPE, ucdID);
+ break;
+ case PRIVATE:
+
+ // Restricted Link
+ itemLink = String.format("%s?%s=%s&%s=%s", geonaDataProfile.getRestrictedPortletURL(),
+ GeoportalCommonConstants.GET_GEONA_ITEM_ID, projectID,
+ GeoportalCommonConstants.GET_GEONA_ITEM_TYPE, ucdID);
+
+ break;
+
+ default:
+ break;
+ }
+
+ break;
+ }
+
+ case GEO_DE: {
+
+ LOG.error("The Resolver towards '" + resoruceGeoportalCodes + "' not implemented yet");
+ throw ExceptionManager.internalErrorException(req,
+ "The Resolver towards '" + resoruceGeoportalCodes + "' not implemented yet", this.getClass(),
+ helpURI);
+
+ }
+ default:
+ break;
+ }
+
+ LOG.info("Returning link: " + itemLink);
+ return Response.seeOther(new URL(itemLink).toURI()).build();
+ } catch (Exception e) {
+
+ if (!(e instanceof WebApplicationException)) {
+ // UNEXPECTED EXCEPTION managing it as WebApplicationException
+ String error = "Error occurred on resolving the " + GeoportalResolver.class.getSimpleName()
+ + " URL. Please, contact the support!";
+ if (e.getCause() != null)
+ error += "\n\nCaused: " + e.getCause().getMessage();
+ throw ExceptionManager.internalErrorException(req, error, this.getClass(), helpURI);
+ }
+ // ALREADY MANAGED AS WebApplicationException
+ LOG.error("Exception:", e);
+ throw (WebApplicationException) e;
+ }
+ }
+
+ /**
+ * Generic create link.
+ *
+ * @param req the req
+ * @param jsonRequest the json request
+ * @param targetAppGeoportalCodes the target app geoportal codes
+ * @return the URL
+ */
+ protected String genericCreateLink(@Context HttpServletRequest req, GeoportalRequest jsonRequest,
+ TargetAppGeoportalCodes targetAppGeoportalCodes) {
+
+ LOG.info(this.getClass().getSimpleName() + " genericCreateLink starts...");
+
+ try {
+
+ InnerMethodName.instance.set("postGeoportalPublicLink");
+ LOG.info("The body contains the request: " + jsonRequest.toString());
+
+ if (jsonRequest.getGcubeScope() == null) {
+ throw ExceptionManager.badRequestException(req, "Missing parameter " + GeoportalRequest.P_GCUBE_SCOPE,
+ this.getClass(), helpURI);
+ }
+
+ if (jsonRequest.getItemID() == null) {
+ throw ExceptionManager.badRequestException(req, "Missing parameter " + GeoportalRequest.P_ITEM_ID,
+ this.getClass(), helpURI);
+ }
+
+ if (jsonRequest.getItemType() == null) {
+ throw ExceptionManager.badRequestException(req, "Missing parameter " + GeoportalRequest.P_ITEM_TYPE,
+ this.getClass(), helpURI);
+ }
+
+ // CHECK IF INPUT SCOPE IS VALID
+ String scope = jsonRequest.getGcubeScope();
+ if (!scope.startsWith(ConstantsResolver.SCOPE_SEPARATOR)) {
+ LOG.info("Scope not start with char '{}' adding it", ConstantsResolver.SCOPE_SEPARATOR);
+ scope += ConstantsResolver.SCOPE_SEPARATOR + scope;
+ }
+
+ String serverUrl = Util.getServerURL(req);
+ final String vreName = scope.substring(scope.lastIndexOf(ConstantsResolver.SCOPE_SEPARATOR) + 1,
+ scope.length());
+ ScopeBean fullScope = null;
+
+ // CHECK IF THE vreName has a valid scope, so it is a valid VRE
+ try {
+ fullScope = LoadingMapOfScopeCache.get(vreName);
+ } catch (ExecutionException e) {
+ LOG.error("Error on getting the fullscope from cache for vreName " + vreName, e);
+ throw ExceptionManager.wrongParameterException(req,
+ "Error on getting full scope for the VRE name " + vreName
+ + ". Is it registered as VRE in the D4Science Infrastructure System?",
+ this.getClass(), helpURI);
+ }
+
+ if (fullScope == null)
+ throw ExceptionManager.notFoundException(req,
+ "The scope '" + scope + "' does not matching any scope in the infrastructure. Is it valid?",
+ this.getClass(), helpURI);
+
+ String linkURL = String.format("%s/%s/%s/%s/%s/%s", serverUrl, GEO, targetAppGeoportalCodes.getId(),
+ vreName, jsonRequest.getItemType(), jsonRequest.getItemID());
+
+ if (jsonRequest.getQueryString() != null) {
+ linkURL += "?" + jsonRequest.getQueryString();
+ }
+
+ LOG.info("Returning " + GeoportalResolver.class.getSimpleName() + " URL: " + linkURL);
+ return linkURL;
+
+ } catch (Exception e) {
+
+ if (!(e instanceof WebApplicationException)) {
+ // UNEXPECTED EXCEPTION managing it as WebApplicationException
+ String error = "Error occurred on creating the " + GeoportalResolver.class.getSimpleName()
+ + " URL. Please, contact the support!";
+ throw ExceptionManager.internalErrorException(req, error, this.getClass(), helpURI);
+ }
+ // ALREADY MANAGED AS WebApplicationExceptiongetItemCatalogueURLs
+ LOG.error("Exception:", e);
+ throw (WebApplicationException) e;
+ }
+
+ }
+
+}
diff --git a/src/main/java/org/gcube/datatransfer/resolver/services/error/ErrorReport.java b/src/main/java/org/gcube/datatransfer/resolver/services/error/ErrorReport.java
index 280a96b..ce509c3 100644
--- a/src/main/java/org/gcube/datatransfer/resolver/services/error/ErrorReport.java
+++ b/src/main/java/org/gcube/datatransfer/resolver/services/error/ErrorReport.java
@@ -9,10 +9,10 @@ import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import lombok.AllArgsConstructor;
+import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
-import lombok.experimental.Builder;
@XmlRootElement(name="error")
diff --git a/src/main/java/org/gcube/datatransfer/resolver/services/error/ExceptionReport.java b/src/main/java/org/gcube/datatransfer/resolver/services/error/ExceptionReport.java
index 0f4088d..45cb9a0 100644
--- a/src/main/java/org/gcube/datatransfer/resolver/services/error/ExceptionReport.java
+++ b/src/main/java/org/gcube/datatransfer/resolver/services/error/ExceptionReport.java
@@ -10,10 +10,10 @@ import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import lombok.AllArgsConstructor;
+import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
-import lombok.experimental.Builder;
/**