From 95da82b9b60f49d763d08bd71b0b143cd32237c3 Mon Sep 17 00:00:00 2001 From: "francesco.mangiacrapa" Date: Wed, 3 Jun 2020 14:39:41 +0200 Subject: [PATCH] on going on migration to gCat --- .../ckan/DirectCkanCaller.java | 140 +++++++++++ .../ckan/ExtendCkanClient.java | 115 +++++---- .../ckan/MarshUnmarshCkanObject.java | 38 +++ .../ckan/SimpleExtendCkanClient.java | 168 ------------- .../ckanutillibrary/db/DBCaller.java | 10 +- .../ckanutillibrary/gcat/GCatCaller.java | 45 ++-- .../ckanutillibrary/server/DataCatalogue.java | 143 ++++++----- .../server/DataCatalogueImpl.java | 235 +++++++++++++++--- src/test/java/TestDataCatalogueLib.java | 15 +- src/test/resources/.gitignore | 9 + target/classes/META-INF/MANIFEST.MF | 2 +- .../catalogue-util-library/pom.properties | 2 +- .../ckan/ExtendCkanClient.class | Bin 8469 -> 8378 bytes .../ckan/ExtendCkanClient.java | 115 +++++---- .../ckan/SimpleExtendCkanClient.class | Bin 7454 -> 0 bytes .../ckan/SimpleExtendCkanClient.java | 168 ------------- .../ckanutillibrary/db/DBCaller.class | Bin 7308 -> 7426 bytes .../ckanutillibrary/db/DBCaller.java | 10 +- .../ckanutillibrary/gcat/GCatCaller.class | Bin 2096 -> 1428 bytes .../ckanutillibrary/gcat/GCatCaller.java | 45 ++-- .../server/DataCatalogue.class | Bin 2655 -> 2745 bytes .../ckanutillibrary/server/DataCatalogue.java | 143 ++++++----- .../server/DataCatalogueImpl.class | Bin 21813 -> 29428 bytes .../server/DataCatalogueImpl.java | 235 +++++++++++++++--- 24 files changed, 941 insertions(+), 697 deletions(-) create mode 100644 src/main/java/org/gcube/datacatalogue/ckanutillibrary/ckan/DirectCkanCaller.java create mode 100644 src/main/java/org/gcube/datacatalogue/ckanutillibrary/ckan/MarshUnmarshCkanObject.java delete mode 100644 src/main/java/org/gcube/datacatalogue/ckanutillibrary/ckan/SimpleExtendCkanClient.java delete mode 100644 target/classes/org/gcube/datacatalogue/ckanutillibrary/ckan/SimpleExtendCkanClient.class delete mode 100644 target/classes/org/gcube/datacatalogue/ckanutillibrary/ckan/SimpleExtendCkanClient.java diff --git a/src/main/java/org/gcube/datacatalogue/ckanutillibrary/ckan/DirectCkanCaller.java b/src/main/java/org/gcube/datacatalogue/ckanutillibrary/ckan/DirectCkanCaller.java new file mode 100644 index 0000000..f01a465 --- /dev/null +++ b/src/main/java/org/gcube/datacatalogue/ckanutillibrary/ckan/DirectCkanCaller.java @@ -0,0 +1,140 @@ +package org.gcube.datacatalogue.ckanutillibrary.ckan; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.trentorise.opendata.jackan.internal.org.apache.http.HttpResponse; +import eu.trentorise.opendata.jackan.internal.org.apache.http.HttpStatus; +import eu.trentorise.opendata.jackan.internal.org.apache.http.client.methods.HttpPost; +import eu.trentorise.opendata.jackan.internal.org.apache.http.entity.StringEntity; +import eu.trentorise.opendata.jackan.internal.org.apache.http.impl.client.CloseableHttpClient; +import eu.trentorise.opendata.jackan.internal.org.apache.http.impl.client.HttpClientBuilder; + + +// TODO: Auto-generated Javadoc +/** + * The Class DirectCkanCaller. + * + * @author Francesco Mangiacrapa at ISTI-CNR Pisa (Italy) + * Jun 3, 2020 + */ +public class DirectCkanCaller { + + private static final String PATH_PACKAGE_PATCH = "/api/3/action/package_patch"; + public final static String PATH_SET_PRIVATE_DATASET = "/api/3/action/bulk_update_private"; + public final static String PATH_SET_PUBLIC_DATASET = "/api/3/action/bulk_update_public"; + private String catalogueURL; + + private static final Logger LOG = LoggerFactory.getLogger(DirectCkanCaller.class); + + + /** + * Instantiates a new direct ckan caller. + * + * @param catalogueURL the catalogue URL + */ + public DirectCkanCaller(String catalogueURL){ + this.catalogueURL = catalogueURL; + } + + /** + * Set dataset private/public. + * + * @param priv the priv + * @param organizationId (NOTE: The ID, not the name!) + * @param datasetId (NOTE: The ID, not the name!) + * @param apiKey the user's api key + * @return true on success, false otherwise + */ + public boolean setDatasetPrivate(boolean priv, String organizationId, + String datasetId, String apiKey) { + + // checks + checkNotNull(organizationId); + checkNotNull(apiKey); + checkNotNull(datasetId); + checkArgument(!apiKey.isEmpty()); + checkArgument(!datasetId.isEmpty()); + checkArgument(!organizationId.isEmpty()); + + JSONObject obj = new JSONObject(); + obj.put("org_id", organizationId); + + JSONArray array = new JSONArray(); + array.add(datasetId); + obj.put("datasets", array); + + try(CloseableHttpClient httpClient = HttpClientBuilder.create().build();) { + HttpPost request; + + if(priv) + request = new HttpPost(catalogueURL + PATH_SET_PRIVATE_DATASET); + else + request = new HttpPost(catalogueURL + PATH_SET_PUBLIC_DATASET); + + LOG.info("Excuting request for making dataset with id " + datasetId + " " + (priv? "private" : "public")); + + request.addHeader("Authorization", apiKey); + StringEntity params = new StringEntity(obj.toJSONString()); + request.setEntity(params); + HttpResponse response = httpClient.execute(request); + + LOG.info("Response code is " + response.getStatusLine().getStatusCode() + " and response message is " + response.getStatusLine().getReasonPhrase()); + + if(response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) + return true; + + }catch (Exception ex) { + LOG.error("Error while trying to set private the dataset ", ex); + } + + + return false; + } + + /** + * Sets the searchable field. + * + * @param datasetId the dataset id + * @param searchable the searchable + * @return true, if successful + */ + public boolean setSearchableField(String datasetId, boolean searchable, String apiKey) { + + // checks + checkNotNull(datasetId); + checkArgument(!datasetId.isEmpty()); + String searchableAsString = searchable ? "True" : "False"; + + // Patch package path + String patchPackage = catalogueURL + PATH_PACKAGE_PATCH; + + JSONObject obj = new JSONObject(); + obj.put("id", datasetId); + obj.put("searchable", searchableAsString); + + try(CloseableHttpClient httpClient = HttpClientBuilder.create().build();) { + HttpPost request = new HttpPost(patchPackage); + request.addHeader("Authorization", apiKey); + StringEntity params = new StringEntity(obj.toJSONString()); + request.setEntity(params); + HttpResponse response = httpClient.execute(request); + LOG.debug("Response code is " + response.getStatusLine().getStatusCode() + " and response message is " + response.getStatusLine().getReasonPhrase()); + + if(response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) + return true; + + }catch (Exception ex) { + LOG.error("Error while trying to set searchable the dataset ", ex); + } + + return false; + } + + +} diff --git a/src/main/java/org/gcube/datacatalogue/ckanutillibrary/ckan/ExtendCkanClient.java b/src/main/java/org/gcube/datacatalogue/ckanutillibrary/ckan/ExtendCkanClient.java index 43a2fce..59fd7b4 100644 --- a/src/main/java/org/gcube/datacatalogue/ckanutillibrary/ckan/ExtendCkanClient.java +++ b/src/main/java/org/gcube/datacatalogue/ckanutillibrary/ckan/ExtendCkanClient.java @@ -1,6 +1,3 @@ -/** - * - */ package org.gcube.datacatalogue.ckanutillibrary.ckan; import static com.google.common.base.Preconditions.checkNotNull; @@ -19,7 +16,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.base.Charsets; import com.google.common.io.CharStreams; -import eu.trentorise.opendata.jackan.CheckedCkanClient; +import eu.trentorise.opendata.jackan.CkanClient; import eu.trentorise.opendata.jackan.exceptions.CkanException; import eu.trentorise.opendata.jackan.exceptions.JackanException; import eu.trentorise.opendata.jackan.internal.org.apache.http.client.fluent.Request; @@ -29,36 +26,34 @@ import eu.trentorise.opendata.jackan.model.CkanOrganization; import eu.trentorise.opendata.jackan.model.CkanResponse; +// TODO: Auto-generated Javadoc /** - * The Class ExtendCkanClient. + * The Class SimpleExtendCkanClient. * * @author Francesco Mangiacrapa at ISTI-CNR (francesco.mangiacrapa@isti.cnr.it) * - * Jun 14, 2019 + * Jun 7, 2019 + * */ -public class ExtendCkanClient extends CheckedCkanClient implements PatchedCkan{ - - private static final Logger logger = LoggerFactory.getLogger(ExtendCkanClient.class); +public class ExtendCkanClient extends CkanClient implements PatchedCkan{ - @Nullable - private static ObjectMapper objectMapper; - private String catalogueURL; private String ckanToken; private int extendTimeout = 120000; //in milliseconds - + @Nullable + private static ObjectMapper objectMapper; + private static final Logger logger = LoggerFactory.getLogger(ExtendCkanClient.class); /** - * Instantiates a new extend ckan client. + * Instantiates a new simple extend ckan client. * - * @param catalogueURL the catalogue url + * @param catalogueURL the catalogue URL */ public ExtendCkanClient(String catalogueURL) { super(catalogueURL); this.catalogueURL = catalogueURL; - } - + /** * Instantiates a new extend ckan client. * @@ -84,7 +79,7 @@ public class ExtendCkanClient extends CheckedCkanClient implements PatchedCkan{ this.ckanToken = ckanToken; this.extendTimeout = timeout; } - + /** * Configures the request. Should work both for GETs and POSTs. @@ -104,38 +99,13 @@ public class ExtendCkanClient extends CheckedCkanClient implements PatchedCkan{ return request; } - /** - * Gets the catalogue url. - * - * @return the catalogueURL - */ - public String getCatalogueURL() { - - return catalogueURL; - } - - - /** - * Gets the ckan token. - * - * @return the ckanToken - */ - @Override - public String getCkanToken() { - - return ckanToken; - } - - /** - * Gets the timeout. - * - * @return the timeout - */ - public int getTimeout() { - return extendTimeout; - } - - /* (non-Javadoc) + /** + * Gets the organization. + * + * @param idOrName the id or name + * @return the organization + */ + /* (non-Javadoc) * @see eu.trentorise.opendata.jackan.CkanClient#getOrganization(java.lang.String) */ public synchronized CkanOrganization getOrganization(String idOrName) { @@ -147,6 +117,12 @@ public class ExtendCkanClient extends CheckedCkanClient implements PatchedCkan{ } + /** + * Gets the group. + * + * @param idOrName the id or name + * @return the group + */ /* (non-Javadoc) * @see eu.trentorise.opendata.jackan.CkanClient#getGroup(java.lang.String) */ @@ -164,7 +140,7 @@ public class ExtendCkanClient extends CheckedCkanClient implements PatchedCkan{ * * @return the object mapper */ - static ObjectMapper getObjectMapper() { + public static ObjectMapper getObjectMapper() { if (objectMapper == null) { objectMapper = new ObjectMapper(); configureObjectMapper(objectMapper); @@ -172,6 +148,15 @@ public class ExtendCkanClient extends CheckedCkanClient implements PatchedCkan{ return objectMapper; } + /** + * Gets the http. + * + * @param the generic type + * @param responseType the response type + * @param path the path + * @param params the params + * @return the http + */ /* (non-Javadoc) * @see org.gcube.datacatalogue.ckanutillibrary.server.patch.PatchedCkan#getHttp(java.lang.Class, java.lang.String, java.lang.Object[]) */ @@ -215,6 +200,13 @@ public class ExtendCkanClient extends CheckedCkanClient implements PatchedCkan{ } + /** + * Calc full url. + * + * @param path the path + * @param params the params + * @return the string + */ /* (non-Javadoc) * @see org.gcube.datacatalogue.ckanutillibrary.server.patch.PatchedCkan#calcFullUrl(java.lang.String, java.lang.Object[]) */ @@ -236,5 +228,26 @@ public class ExtendCkanClient extends CheckedCkanClient implements PatchedCkan{ + Arrays.toString(params), ex); } } + + /** + * Gets the catalogue URL. + * + * @return the catalogue URL + */ + public String getCatalogueURL() { + + return catalogueURL; + } + + /** + * Gets the ckan token. + * + * @return the ckan token + */ + @Override + public String getCkanToken() { + return ckanToken; + } + } diff --git a/src/main/java/org/gcube/datacatalogue/ckanutillibrary/ckan/MarshUnmarshCkanObject.java b/src/main/java/org/gcube/datacatalogue/ckanutillibrary/ckan/MarshUnmarshCkanObject.java new file mode 100644 index 0000000..0767857 --- /dev/null +++ b/src/main/java/org/gcube/datacatalogue/ckanutillibrary/ckan/MarshUnmarshCkanObject.java @@ -0,0 +1,38 @@ +package org.gcube.datacatalogue.ckanutillibrary.ckan; + +import java.io.IOException; + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonMappingException; + +import eu.trentorise.opendata.jackan.model.CkanDataset; + +public class MarshUnmarshCkanObject { + + /** + * To ckan dataset. + * + * @param jsonDataset the json dataset + * @return the ckan dataset + * @throws IOException + * @throws JsonMappingException + * @throws JsonParseException + */ + public static CkanDataset toCkanDataset(String jsonDataset) throws JsonParseException, JsonMappingException, IOException { + return ExtendCkanClient.getObjectMapper().readValue(jsonDataset, CkanDataset.class); + } + + + /** + * To json value dataset. + * + * @param dataset the dataset + * @return the string + * @throws JsonProcessingException + */ + public static String toJsonValueDataset(CkanDataset dataset) throws JsonProcessingException { + return ExtendCkanClient.getObjectMapper().writeValueAsString(dataset); + } + +} diff --git a/src/main/java/org/gcube/datacatalogue/ckanutillibrary/ckan/SimpleExtendCkanClient.java b/src/main/java/org/gcube/datacatalogue/ckanutillibrary/ckan/SimpleExtendCkanClient.java deleted file mode 100644 index 93c59cd..0000000 --- a/src/main/java/org/gcube/datacatalogue/ckanutillibrary/ckan/SimpleExtendCkanClient.java +++ /dev/null @@ -1,168 +0,0 @@ -package org.gcube.datacatalogue.ckanutillibrary.ckan; - -import static com.google.common.base.Preconditions.checkNotNull; - -import java.io.InputStream; -import java.io.InputStreamReader; -import java.net.URLEncoder; -import java.util.Arrays; - -import javax.annotation.Nullable; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.common.base.Charsets; -import com.google.common.io.CharStreams; - -import eu.trentorise.opendata.jackan.CkanClient; -import eu.trentorise.opendata.jackan.exceptions.CkanException; -import eu.trentorise.opendata.jackan.exceptions.JackanException; -import eu.trentorise.opendata.jackan.internal.org.apache.http.client.fluent.Request; -import eu.trentorise.opendata.jackan.internal.org.apache.http.client.fluent.Response; -import eu.trentorise.opendata.jackan.model.CkanGroup; -import eu.trentorise.opendata.jackan.model.CkanOrganization; -import eu.trentorise.opendata.jackan.model.CkanResponse; - - -/** - * The Class SimpleExtendCkanClient. - * - * @author Francesco Mangiacrapa at ISTI-CNR (francesco.mangiacrapa@isti.cnr.it) - * - * Jun 7, 2019 - */ -public class SimpleExtendCkanClient extends CkanClient implements PatchedCkan{ - - - private String catalogueURL; - - @Nullable - private static ObjectMapper objectMapper; - - private static final Logger logger = LoggerFactory.getLogger(SimpleExtendCkanClient.class); - - /** - * Instantiates a new simple extend ckan client. - * - * @param catalogueURL the catalogue URL - */ - public SimpleExtendCkanClient(String catalogueURL) { - super(catalogueURL); - this.catalogueURL = catalogueURL; - } - - /* (non-Javadoc) - * @see eu.trentorise.opendata.jackan.CkanClient#getOrganization(java.lang.String) - */ - public synchronized CkanOrganization getOrganization(String idOrName) { - checkNotNull(idOrName, "Need a valid id or name!"); - logger.info("Patched read organization for id/name: {}", idOrName); - return getHttp(OrganizationResponse.class, "/api/3/action/organization_show", "id", idOrName, - "include_datasets", "false", "include_users", "true").result; - - } - - - /* (non-Javadoc) - * @see eu.trentorise.opendata.jackan.CkanClient#getGroup(java.lang.String) - */ - public synchronized CkanGroup getGroup(String idOrName) { - checkNotNull(idOrName, "Need a valid id or name!"); - logger.info("Patched read group for id/name: {}", idOrName); - return getHttp(GroupResponse.class, "/api/3/action/group_show", "id", idOrName, "include_datasets", - "false", "include_users", "true").result; - } - - - /** - * Retrieves the Jackson object mapper for reading operations. Internally, - * Object mapper is initialized at first call. - * - * @return the object mapper - */ - public static ObjectMapper getObjectMapper() { - if (objectMapper == null) { - objectMapper = new ObjectMapper(); - configureObjectMapper(objectMapper); - } - return objectMapper; - } - - /* (non-Javadoc) - * @see org.gcube.datacatalogue.ckanutillibrary.server.patch.PatchedCkan#getHttp(java.lang.Class, java.lang.String, java.lang.Object[]) - */ - public T getHttp(Class responseType, String path, Object... params) { - - checkNotNull(responseType); - checkNotNull(path); - String fullUrl = calcFullUrl(path, params); - T ckanResponse; - String returnedText; - - try { - - logger.debug("getting {}", fullUrl); - Request request = Request.Get(fullUrl); - configureRequest(request); - Response response = request.execute(); - InputStream stream = response.returnResponse() - .getEntity() - .getContent(); - - try (InputStreamReader reader = new InputStreamReader(stream, Charsets.UTF_8)) { - returnedText = CharStreams.toString(reader); - } - - logger.trace("returnedText {}", returnedText); - } catch (Exception ex) { - throw new CkanException("Error while performing GET. Request url was: " + fullUrl, this, ex); - } - try { - ckanResponse = getObjectMapper().readValue(returnedText, responseType); - } catch (Exception ex) { - throw new CkanException( - "Couldn't interpret json returned by the server! Returned text was: " + returnedText, this, ex); - } - - if (!ckanResponse.isSuccess()) { - throwCkanException("Error while performing GET. Request url was: " + fullUrl, ckanResponse); - } - return ckanResponse; - } - - - /* (non-Javadoc) - * @see org.gcube.datacatalogue.ckanutillibrary.server.patch.PatchedCkan#calcFullUrl(java.lang.String, java.lang.Object[]) - */ - public String calcFullUrl(String path, Object[] params) { - checkNotNull(path); - - try { - StringBuilder sb = new StringBuilder().append(catalogueURL) - .append(path); - for (int i = 0; i < params.length; i += 2) { - sb.append(i == 0 ? "?" : "&") - .append(URLEncoder.encode(params[i].toString(), "UTF-8")) - .append("=") - .append(URLEncoder.encode(params[i + 1].toString(), "UTF-8")); - } - return sb.toString(); - } catch (Exception ex) { - throw new JackanException("Error while building url to perform GET! \n path: " + path + " \n params: " - + Arrays.toString(params), ex); - } - } - - /** - * Gets the catalogue url. - * - * @return the catalogueURL - */ - public String getCatalogueURL() { - - return catalogueURL; - } - -} diff --git a/src/main/java/org/gcube/datacatalogue/ckanutillibrary/db/DBCaller.java b/src/main/java/org/gcube/datacatalogue/ckanutillibrary/db/DBCaller.java index f989172..1e1532d 100644 --- a/src/main/java/org/gcube/datacatalogue/ckanutillibrary/db/DBCaller.java +++ b/src/main/java/org/gcube/datacatalogue/ckanutillibrary/db/DBCaller.java @@ -95,7 +95,7 @@ public class DBCaller { */ public Map getGroupsByUserFromDB(String username){ checkNotNull(username); - LOG.debug("Get groups by user called"); + LOG.debug("Get groups by user called for username: "+username); //couples (groups id, capacity) of the user in the group @@ -129,6 +129,8 @@ public class DBCaller { }finally{ closeConnection(connection); } + + LOG.debug("returning map: "+toReturn); return toReturn; } @@ -140,7 +142,7 @@ public class DBCaller { * @return the user id for username */ private String getUserIdForUsername(String username) { - LOG.debug("Get user id for username called"); + LOG.debug("Get user id for username called for username: "+username); Connection connection = null; String userId = null; @@ -150,7 +152,7 @@ public class DBCaller { String selQuery = "SELECT \"id\" FROM \"public\".\"user\" WHERE \"name\"=?;"; - LOG.info("Performing query: "+selQuery); + LOG.debug("Performing query: "+selQuery); PreparedStatement preparedStatement = connection.prepareStatement(selQuery); preparedStatement.setString(1, username); @@ -213,6 +215,8 @@ public class DBCaller { }finally{ closeConnection(connection); } + + LOG.debug("returning map: "+toReturn); return toReturn; } diff --git a/src/main/java/org/gcube/datacatalogue/ckanutillibrary/gcat/GCatCaller.java b/src/main/java/org/gcube/datacatalogue/ckanutillibrary/gcat/GCatCaller.java index c14eca7..82cf4c6 100644 --- a/src/main/java/org/gcube/datacatalogue/ckanutillibrary/gcat/GCatCaller.java +++ b/src/main/java/org/gcube/datacatalogue/ckanutillibrary/gcat/GCatCaller.java @@ -2,19 +2,11 @@ package org.gcube.datacatalogue.ckanutillibrary.gcat; import java.io.IOException; import java.net.MalformedURLException; -import java.util.List; -import org.gcube.datacatalogue.ckanutillibrary.ckan.SimpleExtendCkanClient; import org.gcube.gcat.client.Item; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.fasterxml.jackson.core.JsonParseException; -import com.fasterxml.jackson.databind.JsonMappingException; - -import eu.trentorise.opendata.jackan.model.CkanDataset; -import eu.trentorise.opendata.jackan.model.CkanLicense; - // TODO: Auto-generated Javadoc /** * The Class GCatCaller. @@ -24,18 +16,17 @@ import eu.trentorise.opendata.jackan.model.CkanLicense; */ public class GCatCaller { - private SimpleExtendCkanClient jackanCkanClient; - private String catalogueURL; private static final Logger LOG = LoggerFactory.getLogger(GCatCaller.class); /** * Instantiates a new g cat caller. + * + * @param catalogueURL the catalogue URL */ public GCatCaller(String catalogueURL) { this.catalogueURL = catalogueURL; - this.jackanCkanClient = new SimpleExtendCkanClient(catalogueURL); } @@ -43,27 +34,27 @@ public class GCatCaller { * Gets the dataset for name. * * @param datasetIdOrName the dataset id or name - * @return the dataset for name - * @throws JsonParseException the json parse exception - * @throws JsonMappingException the json mapping exception + * @return the jsonValue + * @throws MalformedURLException * @throws IOException Signals that an I/O exception has occurred. */ - public CkanDataset getDatasetForName(String datasetIdOrName) throws JsonParseException, JsonMappingException, IOException { + public String getDatasetForName(String datasetIdOrName) throws MalformedURLException { LOG.debug("Get dataset for name "+datasetIdOrName+ "called"); - String json = new Item().read(datasetIdOrName); - return SimpleExtendCkanClient.getObjectMapper().readValue(json, CkanDataset.class); + return new Item().read(datasetIdOrName); } - - - /** - * TODO gCAT missing - * @return - * @throws MalformedURLException - */ - public List getLicenseList() { - LOG.debug("Get linces list called"); - return jackanCkanClient.getLicenseList(); + + /** + * Creates the dataset. + * + * @param jsonDataset the json dataset + * @param socialPost if true sends the social post + * @return the jsonValue + * @throws MalformedURLException the malformed URL exception + */ + public String createDataset(String jsonDataset, boolean socialPost) throws MalformedURLException { + LOG.debug("Create dataset called"); + return new Item().create(jsonDataset,socialPost); } } diff --git a/src/main/java/org/gcube/datacatalogue/ckanutillibrary/server/DataCatalogue.java b/src/main/java/org/gcube/datacatalogue/ckanutillibrary/server/DataCatalogue.java index e8b5494..78cece6 100644 --- a/src/main/java/org/gcube/datacatalogue/ckanutillibrary/server/DataCatalogue.java +++ b/src/main/java/org/gcube/datacatalogue/ckanutillibrary/server/DataCatalogue.java @@ -39,67 +39,6 @@ public interface DataCatalogue { */ String getUnencryptedUrlFromDatasetIdOrName(String datasetIdOrName); - /** - * Create a dataset with those information. The method allows to have multiple - * values for the same custom field key. NOTE: unfortunately java doesn't - * support overload in java interface methods (that's way I cannot use the same - * name for the method) - * - * @param title the title - * @param name (unique identifier) - * @param organizationNameOrId the organization name or id - * @param author the author - * @param authorMail the author mail - * @param maintainer the maintainer - * @param maintainerMail the maintainer mail - * @param version the version - * @param description the description - * @param licenseId the license id - * @param tags the tags - * @param customFields the custom fields - * @param resources the resources - * @param setPublic (manage visibility: Admin role is needed) - * @return the id of the dataset on success, null otherwise - * @throws Exception the exception - */ - String createCKanDatasetMultipleCustomFields(String title, String name, String organizationNameOrId, String author, - String authorMail, String maintainer, String maintainerMail, long version, String description, - String licenseId, List tags, Map> customFields, List resources, - boolean setPublic) throws Exception; - - /** - * Patch a product with product id productId by using the couples in - * customFieldsToChange. NOTE: only the specified custom fields will be changed. - * If a custom field with a given key already exists, and removeOld is set to - * false, the new values are added at the end of the list. Otherwise they are - * lost. - * - * @param productId the product id - * @param customFieldsToChange the custom fields to change - * @param removeOld the remove old - * @return true, if successful - */ - boolean patchProductCustomFields(String productId, Map> customFieldsToChange, - boolean removeOld); - - /** - * Add a resource described by the bean to the dataset id into - * resource.datasetId - * - * @param resource the resource - * @return String the id of the resource on success, null otherwise - * @throws Exception the exception - */ - String addResourceToDataset(ResourceBean resource) throws Exception; - - /** - * Remove the resource with id resourceId from the dataset in which it is. - * - * @param resourceId the resource id - * @return true on success, false otherwise. - */ - boolean deleteResourceFromDataset(String resourceId); - /** * Create a dataset with those information. * @@ -201,4 +140,86 @@ public interface DataCatalogue { */ Map> getUserRoleByOrganization(String username); + + + + + //WRITE OPERATIONS + + + + + + /** + * Set searchable field + * The field, if set to true, allows organization's users to view private products also in groups + * @param datasetId the id of the dataset to update + * @param searchable the value to assign to the field + * @return true if the field is set, false otherwise + */ + boolean setSearchableField(String datasetId, boolean searchable); + + + /** + * Create a dataset with those information. The method allows to have multiple + * values for the same custom field key. NOTE: unfortunately java doesn't + * support overload in java interface methods (that's way I cannot use the same + * name for the method) + * + * @param the username that is submitting the publishing request + * @param title the title + * @param name (unique identifier) + * @param organizationNameOrId the organization name or id + * @param author the author + * @param authorMail the author mail + * @param maintainer the maintainer + * @param maintainerMail the maintainer mail + * @param version the version + * @param description the description + * @param licenseId the license id + * @param tags the tags + * @param customFields the custom fields + * @param resources the resources + * @param setPublic (manage visibility: Admin role is needed) + * @return the id of the dataset on success, null otherwise + * @throws Exception the exception + */ + String createCKanDatasetMultipleCustomFields(String username, String title, String name, String organizationNameOrId, String author, + String authorMail, String maintainer, String maintainerMail, long version, String description, + String licenseId, List tags, Map> customFields, List resources, + boolean setPublic) throws Exception; + + /** + * Patch a product with product id productId by using the couples in + * customFieldsToChange. NOTE: only the specified custom fields will be changed. + * If a custom field with a given key already exists, and removeOld is set to + * false, the new values are added at the end of the list. Otherwise they are + * lost. + * + * @param productId the product id + * @param customFieldsToChange the custom fields to change + * @param removeOld the remove old + * @return true, if successful + */ + boolean patchProductCustomFields(String productId, Map> customFieldsToChange, + boolean removeOld); + + /** + * Add a resource described by the bean to the dataset id into + * resource.datasetId + * + * @param resource the resource + * @return String the id of the resource on success, null otherwise + * @throws Exception the exception + */ + String addResourceToDataset(ResourceBean resource) throws Exception; + + /** + * Remove the resource with id resourceId from the dataset in which it is. + * + * @param resourceId the resource id + * @return true on success, false otherwise. + */ + boolean deleteResourceFromDataset(String resourceId); + } diff --git a/src/main/java/org/gcube/datacatalogue/ckanutillibrary/server/DataCatalogueImpl.java b/src/main/java/org/gcube/datacatalogue/ckanutillibrary/server/DataCatalogueImpl.java index 099f1e9..f635940 100644 --- a/src/main/java/org/gcube/datacatalogue/ckanutillibrary/server/DataCatalogueImpl.java +++ b/src/main/java/org/gcube/datacatalogue/ckanutillibrary/server/DataCatalogueImpl.java @@ -6,15 +6,18 @@ import static com.google.common.base.Preconditions.checkNotNull; import java.net.URLEncoder; import java.util.ArrayList; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; import org.gcube.common.authorization.library.provider.SecurityTokenProvider; import org.gcube.common.scope.impl.ScopeBean; import org.gcube.common.scope.impl.ScopeBean.Type; +import org.gcube.datacatalogue.ckanutillibrary.ckan.DirectCkanCaller; import org.gcube.datacatalogue.ckanutillibrary.ckan.ExtendCkanClient; -import org.gcube.datacatalogue.ckanutillibrary.ckan.SimpleExtendCkanClient; +import org.gcube.datacatalogue.ckanutillibrary.ckan.MarshUnmarshCkanObject; import org.gcube.datacatalogue.ckanutillibrary.db.DBCaller; import org.gcube.datacatalogue.ckanutillibrary.gcat.GCatCaller; import org.gcube.datacatalogue.ckanutillibrary.server.DataCatalogueRunningCluster.ACCESS_LEVEL_TO_CATALOGUE_PORTLET; @@ -38,7 +41,13 @@ import eu.trentorise.opendata.jackan.model.CkanDataset; import eu.trentorise.opendata.jackan.model.CkanGroup; import eu.trentorise.opendata.jackan.model.CkanLicense; import eu.trentorise.opendata.jackan.model.CkanOrganization; +import eu.trentorise.opendata.jackan.model.CkanPair; +import eu.trentorise.opendata.jackan.model.CkanResource; +import eu.trentorise.opendata.jackan.model.CkanTag; import eu.trentorise.opendata.jackan.model.CkanUser; +import net.htmlparser.jericho.Renderer; +import net.htmlparser.jericho.Segment; +import net.htmlparser.jericho.Source; public class DataCatalogueImpl implements DataCatalogue { @@ -63,6 +72,7 @@ public class DataCatalogueImpl implements DataCatalogue { public Map mapAccessURLToCatalogue; + private static final String CATALOGUE_TAB_ENDING_URL = "/catalogue"; // gCat client @@ -72,10 +82,13 @@ public class DataCatalogueImpl implements DataCatalogue { private DBCaller dbCaller; // ckan client - private SimpleExtendCkanClient ckanCaller; + private ExtendCkanClient ckanCaller; // hashmap for ckan api keys private ConcurrentHashMap apiKeysMap; + + //http ckan caller + private DirectCkanCaller directCkanCaller; // apikey bean expires after X minutes in the above map private static final int EXPIRE_KEY_TIME = 60 * 60 * 1000; @@ -97,7 +110,7 @@ public class DataCatalogueImpl implements DataCatalogue { CKAN_DB_USER = runningInstance.getDataBaseUser().trim(); CKAN_DB_PASSWORD = runningInstance.getDataBasePassword().trim(); - //CKAN_TOKEN_SYS = runningInstance.getSysAdminToken().trim(); + CKAN_TOKEN_SYS = runningInstance.getSysAdminToken().trim(); CKAN_EMAIL = runningInstance.getEmailCatalogue().trim(); CKAN_CATALOGUE_URL = runningInstance.getDataCatalogueUrl().get(0).trim(); @@ -113,17 +126,13 @@ public class DataCatalogueImpl implements DataCatalogue { // build the clients gCatCaller = new GCatCaller(CKAN_CATALOGUE_URL); - dbCaller = new DBCaller(CKAN_DB_URL, CKAN_DB_PORT, CKAN_DB_NAME, CKAN_DB_USER, CKAN_DB_PASSWORD); - - ckanCaller = new SimpleExtendCkanClient(CKAN_CATALOGUE_URL); - + ckanCaller = new ExtendCkanClient(CKAN_CATALOGUE_URL); + directCkanCaller = new DirectCkanCaller(CKAN_CATALOGUE_URL); // init map apiKeysMap = new ConcurrentHashMap(); - // save the context CONTEXT = scope; - // extended roles extendRoleInOrganization = runningInstance.getExtendRoleInOrganization(); } @@ -228,7 +237,8 @@ public class DataCatalogueImpl implements DataCatalogue { String authzToken = SecurityTokenProvider.instance.get(); if(authzToken!=null && !authzToken.isEmpty()) { LOG.info("gcube-token found. Calling the gCat client"); - return gCatCaller.getDatasetForName(datasetId); + String jsonDataset = gCatCaller.getDatasetForName(datasetId); + return MarshUnmarshCkanObject.toCkanDataset(jsonDataset); } LOG.info("No api-key or gcube-token found. Calling Ckan Client without API-KEY"); @@ -272,13 +282,7 @@ public class DataCatalogueImpl implements DataCatalogue { return url; } - public String createCKanDatasetMultipleCustomFields(String title, String name, String organizationNameOrId, - String author, String authorMail, String maintainer, String maintainerMail, long version, - String description, String licenseId, List tags, Map> customFields, - List resources, boolean setPublic) throws Exception { - return null; - } - + @Override public Map> getUserRoleByGroup(String username) { LOG.info("Get user role by group called. The username is: "+username); @@ -328,6 +332,7 @@ public class DataCatalogueImpl implements DataCatalogue { HashMap subMap = new HashMap(); subMap.put(org, partialResult.get(orgID)); toReturn.put(orgID, subMap); + LOG.debug("For organisation: " + org.getName() + ", the user "+username+" has role: "+subMap); } LOG.debug("Returning map " + toReturn); @@ -399,10 +404,8 @@ public class DataCatalogueImpl implements DataCatalogue { // checks checkNotNull(username); - // in order to avoid errors, the username is always converted String ckanUsername = CatalogueUtilMethods.fromUsernameToCKanUsername(username); - // list to return List toReturn = new ArrayList(); @@ -413,12 +416,11 @@ public class DataCatalogueImpl implements DataCatalogue { // iterate over them for (CkanOrganization ckanOrganization : organizations) { - // get the list of users in it (if you try ckanOrganization.getUsers() it returns null.. maybe a bug TODO) List users = ckanCaller.getOrganization(ckanOrganization.getName()).getUsers(); - // check if the current user is among them for (CkanUser ckanUser : users) { + if(ckanUser.getName().equals(ckanUsername)){ LOG.debug("User " + ckanUsername + " is into " + ckanOrganization.getName()); @@ -440,10 +442,8 @@ public class DataCatalogueImpl implements DataCatalogue { // checks checkNotNull(username); - // in order to avoid errors, the username is always converted String ckanUsername = CatalogueUtilMethods.fromUsernameToCKanUsername(username); - // list to return List toReturn = new ArrayList(); @@ -459,6 +459,7 @@ public class DataCatalogueImpl implements DataCatalogue { // check if the current user is among them for (CkanUser ckanUser : users) { + if(ckanUser.getName().equals(ckanUsername)){ LOG.debug("User " + ckanUsername + " is into " + ckanGroup.getName()); @@ -513,15 +514,22 @@ public class DataCatalogueImpl implements DataCatalogue { return null; } - - - - - - - - - + @Override + public boolean existProductWithNameOrId(String nameOrId) { + + checkNotNull(nameOrId); + checkArgument(!nameOrId.isEmpty()); + + try{ + ExtendCkanClient client = new ExtendCkanClient(CKAN_CATALOGUE_URL, CKAN_TOKEN_SYS); + CkanDataset product = client.getDataset(nameOrId); + return product != null; + }catch(Exception e){ + LOG.debug("A dataset with name " + nameOrId + " doesn't exist"); + return false; + } + } + /* * @@ -546,6 +554,163 @@ public class DataCatalogueImpl implements DataCatalogue { * */ + @Override + public String createCKanDatasetMultipleCustomFields(String username, String title, String name, String organizationNameOrId, + String author, String authorMail, String maintainer, String maintainerMail, long version, + String description, String licenseId, List tags, Map> customFieldsMultiple, + List resources, boolean setPublic) throws Exception { + + // delegate the private method + return createCkanDatasetBody(username, title, name, organizationNameOrId, author, authorMail, maintainer, maintainerMail, + version, description, licenseId, tags, null, customFieldsMultiple, resources, setPublic); + } + + // the body of the actual dataset creation methods + private String createCkanDatasetBody(String username, String title, String name, String organizationNameOrId, String author, + String authorMail, String maintainer, String maintainerMail, long version, String description, + String licenseId, List tags, Map customFields, + Map> customFieldsMultipleValues, List resources, boolean setPublic) + throws Exception { + + // checks (minimum) + checkNotNull(username); + checkNotNull(organizationNameOrId); + checkArgument(!organizationNameOrId.isEmpty()); + checkArgument(!(title == null && name == null || title.isEmpty() && name.isEmpty()), "Name and Title cannot be empty/null at the same time!"); + + LOG.debug("Request for dataset creation"); + + //ExtendCkanClient client = new ExtendCkanClient(CKAN_CATALOGUE_URL, apiKey); + + //String ckanUsername = getUserFromApiKey(apiKey).getName(); + CkanDataset dataset = new CkanDataset(); + + // in order to avoid errors, the username is always converted + String ckanUsername = CatalogueUtilMethods.fromUsernameToCKanUsername(username); + + String nameToUse = name; + if(nameToUse == null) + nameToUse = CatalogueUtilMethods.fromProductTitleToName(title); + + LOG.debug("Name of the dataset is going to be " + nameToUse + ". Title is going to be " + title); + + dataset.setName(nameToUse); + dataset.setTitle(title); + +// CkanOrganization orgOwner = client.getOrganization(organizationNameOrId); +// dataset.setOwnerOrg(orgOwner.getId()); + dataset.setAuthor(author); + dataset.setAuthorEmail(authorMail); + dataset.setMaintainer(maintainer); + dataset.setMaintainerEmail(maintainerMail); + dataset.setVersion(String.valueOf(version)); + + // description must be escaped + if(description != null && !description.isEmpty()){ + Source descriptionEscaped = new Source(description); + Segment htmlSeg = new Segment(descriptionEscaped, 0, descriptionEscaped.length()); + Renderer htmlRend = new Renderer(htmlSeg); + dataset.setNotes(htmlRend.toString()); + + LOG.debug("Description escaped " + htmlRend.toString()); + } + + dataset.setLicenseId(licenseId); + + // set the tags, if any + if(tags != null && !tags.isEmpty()){ + List ckanTags = new ArrayList(tags.size()); + for (String stringTag : tags) { + ckanTags.add(new CkanTag(stringTag)); + } + dataset.setTags(ckanTags); + } + + // set the custom fields, if any + List extras = new ArrayList(); + + if(customFields != null && !customFields.isEmpty()){ + + Iterator> iterator = customFields.entrySet().iterator(); + + while (iterator.hasNext()) { + Map.Entry entry = iterator.next(); + extras.add(new CkanPair(entry.getKey(), entry.getValue())); + } + + }else if(customFieldsMultipleValues != null && !customFieldsMultipleValues.isEmpty()){ + + Iterator>> iterator = customFieldsMultipleValues.entrySet().iterator(); + while (iterator.hasNext()) { + Map.Entry> entry = iterator.next(); + List valuesForEntry = entry.getValue(); + for (String value : valuesForEntry) { + extras.add(new CkanPair(entry.getKey(), value)); + } + } + } + + dataset.setExtras(extras); + + // check if we need to add the resources + if(resources != null && !resources.isEmpty()){ + + LOG.debug("We need to add resources to the dataset"); + + try{ + List resourcesCkan = new ArrayList(); + for(ResourceBean resource: resources){ + + LOG.debug("Going to add resource described by " + resource); + CkanResource newResource = new CkanResource(); + newResource.setDescription(resource.getDescription()); + newResource.setId(resource.getId()); + newResource.setUrl(resource.getUrl()); + newResource.setName(resource.getName()); + newResource.setMimetype(resource.getMimeType()); + newResource.setFormat(resource.getMimeType()); + newResource.setOwner(ckanUsername); + resourcesCkan.add(newResource); + } + + // add to the dataset + dataset.setResources(resourcesCkan); + + }catch(Exception e){ + LOG.error("Unable to add those resources to the dataset", e); + } + + } + + // try to create + String jsonValueDataset = MarshUnmarshCkanObject.toJsonValueDataset(dataset); + LOG.debug("Marshalling dataset is: " + jsonValueDataset); + jsonValueDataset = gCatCaller.createDataset(jsonValueDataset,true); + LOG.debug("Created dataset is: " + jsonValueDataset); + + if(jsonValueDataset != null){ + CkanDataset toCkanDataset = MarshUnmarshCkanObject.toCkanDataset(jsonValueDataset); + LOG.debug("Dataset with name " + toCkanDataset.getName() + " has been created. Setting visibility"); + + // set visibility + boolean visibilitySet = directCkanCaller.setDatasetPrivate( + !setPublic, // swap to private + toCkanDataset.getOrganization().getId(), + toCkanDataset.getId(), + CKAN_TOKEN_SYS); // use sysadmin api key to be sure it will be set + + LOG.info("Was visibility set to " + (setPublic ? "public" : "private") + "? " + visibilitySet); + + // set searchable to true if dataset visibility is private + if(!setPublic){ // (swap to private) + boolean searchableSet = setSearchableField(toCkanDataset.getId(), true); + LOG.info("Was searchable set to True? " + searchableSet); + } + return toCkanDataset.getId(); + } + + return null; + } public boolean patchProductCustomFields(String productId, Map> customFieldsToChange, boolean removeOld) { @@ -560,9 +725,11 @@ public class DataCatalogueImpl implements DataCatalogue { return false; } - public boolean existProductWithNameOrId(String nameOrId) { - return false; + @Override + public boolean setSearchableField(String datasetId, boolean searchable) { + return directCkanCaller.setSearchableField(datasetId, searchable, CKAN_TOKEN_SYS); } + } diff --git a/src/test/java/TestDataCatalogueLib.java b/src/test/java/TestDataCatalogueLib.java index cb00cbe..8c58717 100644 --- a/src/test/java/TestDataCatalogueLib.java +++ b/src/test/java/TestDataCatalogueLib.java @@ -5,7 +5,6 @@ import org.gcube.datacatalogue.ckanutillibrary.server.ApplicationProfileScopePer import org.gcube.datacatalogue.ckanutillibrary.server.DataCatalogueFactory; import org.gcube.datacatalogue.ckanutillibrary.server.DataCatalogueImpl; import org.junit.Before; -import org.junit.Test; import org.slf4j.LoggerFactory; /** @@ -19,7 +18,9 @@ public class TestDataCatalogueLib { private static final org.slf4j.Logger logger = LoggerFactory.getLogger(TestDataCatalogueLib.class); private DataCatalogueFactory factory; - private String scope = "/gcube/devsec/devVRE"; + //private String scope = "/gcube/devsec/devVRE"; + private String scope = "/d4science.research-infrastructures.eu/SoBigData/Catalogue-TerritoriAperti"; + //private String scope = "/d4science.research-infrastructures.eu/gCubeApps/BiodiversityLab"; //private String testUser = "costantino_perciante"; private String testUser = "francesco_mangiacrapa"; String subjectId = "aa_father4"; @@ -46,15 +47,15 @@ public class TestDataCatalogueLib { DataCatalogueFactory factory = DataCatalogueFactory.getFactory(); while(true){ - factory.getUtilsPerScope("/gcube"); + factory.getUtilsPerScope(scope); Thread.sleep(60* 1000 * 3); - factory.getUtilsPerScope("/gcube"); + factory.getUtilsPerScope(scope); break; } for (int i = 0; i < 5; i++) { Thread.sleep(1000); - factory.getUtilsPerScope("/gcube"); + factory.getUtilsPerScope(scope); } } @@ -68,7 +69,7 @@ public class TestDataCatalogueLib { //@Test public void getScopePerUrl(){ - ScopeProvider.instance.set("/gcube"); + ScopeProvider.instance.set(scope); String url = "https://dev4.d4science.org/group/devvre/ckan"; String scopeToUse = ApplicationProfileScopePerUrlReader.getScopePerUrl(url); logger.debug("Retrieved scope is " + scopeToUse); @@ -86,7 +87,7 @@ public class TestDataCatalogueLib { * @return the user role by group * @throws Exception the exception */ - @Test + //@Test public void getUserRoleByGroup() throws Exception{ DataCatalogueImpl instance = factory.getUtilsPerScope(scope); String username = testUser; diff --git a/src/test/resources/.gitignore b/src/test/resources/.gitignore index 8f08e73..602005e 100644 --- a/src/test/resources/.gitignore +++ b/src/test/resources/.gitignore @@ -5,3 +5,12 @@ /log4j.properties /pred4s.gcubekey /preprod.gcubekey +/D4OS.gcubekey +/D4Research.gcubekey +/FARM.gcubekey +/OpenAIRE.gcubekey +/ParthenosVO.gcubekey +/SmartArea.gcubekey +/SoBigData.gcubekey +/d4science.research-infrastructures.eu.gcubekey +/gCubeApps.gcubekey diff --git a/target/classes/META-INF/MANIFEST.MF b/target/classes/META-INF/MANIFEST.MF index e5cf844..6eaf68d 100644 --- a/target/classes/META-INF/MANIFEST.MF +++ b/target/classes/META-INF/MANIFEST.MF @@ -6,7 +6,7 @@ Specification-Version: 0.1.0-SNAPSHOT Implementation-Title: CKan utility library Implementation-Version: 0.1.0-SNAPSHOT Implementation-Vendor-Id: org.gcube.datacatalogue -Build-Time: 20200601-145428 +Build-Time: 20200603-095004 Created-By: Maven Integration for Eclipse SCM-Branch: SCM-Revision: diff --git a/target/classes/META-INF/maven/org.gcube.datacatalogue/catalogue-util-library/pom.properties b/target/classes/META-INF/maven/org.gcube.datacatalogue/catalogue-util-library/pom.properties index bff563c..1f12d60 100644 --- a/target/classes/META-INF/maven/org.gcube.datacatalogue/catalogue-util-library/pom.properties +++ b/target/classes/META-INF/maven/org.gcube.datacatalogue/catalogue-util-library/pom.properties @@ -1,5 +1,5 @@ #Generated by Maven Integration for Eclipse -#Mon Jun 01 16:54:29 CEST 2020 +#Wed Jun 03 11:50:06 CEST 2020 version=0.1.0-SNAPSHOT groupId=org.gcube.datacatalogue m2e.projectName=catalogue-util-library diff --git a/target/classes/org/gcube/datacatalogue/ckanutillibrary/ckan/ExtendCkanClient.class b/target/classes/org/gcube/datacatalogue/ckanutillibrary/ckan/ExtendCkanClient.class index 91f6d884263958f9f875190eddac5b9bc74f9a28..9de95dbba44851435c55249e90774844f1a0e126 100644 GIT binary patch delta 3204 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 MfaSb^?I_s(10Bz#b^rhX delta 3254 zcma)933yc175>j`ZA5cfj9tFYH{U&XIp^H} zp7Y;xXF4Z5G|_eFv(CK$MpBsq1EI8eO;K}c3KffxHA^X9tc90q)y=nlO{}D>=AKo} zU6aHHT4_{Z6>h^VP8ZxZ5OP&GktA+6Y_%jKiI6AUZm)PG)gjiVD6KP%3B%;_P%Kp6 zSlgt{shCC>ke5GgNoYl=xIWZSTU;57)HT$OBdE1ntbA#xVRqwEt$|?Y;q1C)T4Pg; zV9d+^sxVkWIr9j<>6%s@2nAMz>g%cl{B4W`8bZsoY&)v(4Fxxfdo20Jn{cyewM?T0 z4=N?DkcvepCz$FQY8n+(i|dsNsu4oTsa{NQT?I2^(Go2jvtkLsP*-h5J+Ia^gzKBC zwFT9Dh^Q8eTEXbdHKF>bX2o)X^RhxyREzLxg!hR>nlwAdCZ?hZD@2BMl{Ji&DpuiJ zVzYG%#YL$t*R+N(rFqR5vBl=1?}%NtfsWO$}k^dYp4@PorHy8({*kPcW-UphG;Kluupaa8j1# zS#&GdE6yk7828~h;ZM$WcH)=vU@s6x zb>i15UWS)55w35Ha58GEzIt5DaUbE z#X-!p<4wFT;r^a5TPJo>DZ%PTBM&g$A>UzCnW)E9PrD zxgp$GtwmJIp&a8QRz<`0= z+F1hmtUe4``Yc#^5CVOsvmo9{%PkuVGfH^pAY8akS4`Cn-N<8O`Elz=I5ccrz-xs( zXOq4esF>s%b?syZUBaNJuRdY-gk1;L0q4FNO?ke`nczggLw_ zv$Kx#D+5(t=$V_q{CT^P;kl)-0}G8P@Ps{@i)%)0mC;jIS!F7$tTKC+R#sU&%POlB zPh(}3)pKiQ8>0IV-h*%M1cvtQoyA^(wcM^_CamX!He)Qy@hm4|y*Qbk7Qc;yL&(PM zxZ{6dx$`oX)t+zvpIBD!!Cj1{AC!#@WfMc$%uIWjp=^dSo;wq{K3~ORm1U$4%M3j# zK>BXndjQ@p+*j3(2U>A2j}utOt=z(>)7Ya^;0aFcR%YmvOpon))MZ?Su0^R>BcCO9 z`U4%=Lo)crk(^&AlQixtOkl&jVX`S0R@8zW8D8%T15^Egg8nh!$iAl`gzl)rI3#p10faj^EUVciV7=akS&T z?gT#YTMFCo(LS6Dn)|E&Nvd1=sr$`s`13}j7yO$)x$-yhKxStAA`aknekv|-SR z3b$Z)lND@LC{@7`{oBbJIPxhR6InQ&Jxoph#Y0N`^Jdb)WkcxkFn`fAd%4)d$x^_#zpN@ar>|%6S@=g1w|pOH8J{9<=3}ha?}H>tJNXLsU??+*nfC5<<0w-LCKRQZ zHp1p5e+w*L%HV}zDW(x^G|)>~2@3GoOVWgAO$+MZ4-123sx#>r;*)^(9F;HVy0&Ar7z>^4knWsC;6#6#WnpTd^pWi zI>Rr`SzM3z__cYTe;}XcivIyyeuz4J#5DLA_p_8`xs1uehrRN4tmhENWmV)!opT0u zIg>`wXx=mfQ)vu8KPGmQt5d|Nr+ggDmyo64IDMTPnaAE7>8a;g7d(fr2!SrH74^SHn!#F(<<;OJVyLsL8Es diff --git a/target/classes/org/gcube/datacatalogue/ckanutillibrary/ckan/ExtendCkanClient.java b/target/classes/org/gcube/datacatalogue/ckanutillibrary/ckan/ExtendCkanClient.java index 43a2fce..59fd7b4 100644 --- a/target/classes/org/gcube/datacatalogue/ckanutillibrary/ckan/ExtendCkanClient.java +++ b/target/classes/org/gcube/datacatalogue/ckanutillibrary/ckan/ExtendCkanClient.java @@ -1,6 +1,3 @@ -/** - * - */ package org.gcube.datacatalogue.ckanutillibrary.ckan; import static com.google.common.base.Preconditions.checkNotNull; @@ -19,7 +16,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.base.Charsets; import com.google.common.io.CharStreams; -import eu.trentorise.opendata.jackan.CheckedCkanClient; +import eu.trentorise.opendata.jackan.CkanClient; import eu.trentorise.opendata.jackan.exceptions.CkanException; import eu.trentorise.opendata.jackan.exceptions.JackanException; import eu.trentorise.opendata.jackan.internal.org.apache.http.client.fluent.Request; @@ -29,36 +26,34 @@ import eu.trentorise.opendata.jackan.model.CkanOrganization; import eu.trentorise.opendata.jackan.model.CkanResponse; +// TODO: Auto-generated Javadoc /** - * The Class ExtendCkanClient. + * The Class SimpleExtendCkanClient. * * @author Francesco Mangiacrapa at ISTI-CNR (francesco.mangiacrapa@isti.cnr.it) * - * Jun 14, 2019 + * Jun 7, 2019 + * */ -public class ExtendCkanClient extends CheckedCkanClient implements PatchedCkan{ - - private static final Logger logger = LoggerFactory.getLogger(ExtendCkanClient.class); +public class ExtendCkanClient extends CkanClient implements PatchedCkan{ - @Nullable - private static ObjectMapper objectMapper; - private String catalogueURL; private String ckanToken; private int extendTimeout = 120000; //in milliseconds - + @Nullable + private static ObjectMapper objectMapper; + private static final Logger logger = LoggerFactory.getLogger(ExtendCkanClient.class); /** - * Instantiates a new extend ckan client. + * Instantiates a new simple extend ckan client. * - * @param catalogueURL the catalogue url + * @param catalogueURL the catalogue URL */ public ExtendCkanClient(String catalogueURL) { super(catalogueURL); this.catalogueURL = catalogueURL; - } - + /** * Instantiates a new extend ckan client. * @@ -84,7 +79,7 @@ public class ExtendCkanClient extends CheckedCkanClient implements PatchedCkan{ this.ckanToken = ckanToken; this.extendTimeout = timeout; } - + /** * Configures the request. Should work both for GETs and POSTs. @@ -104,38 +99,13 @@ public class ExtendCkanClient extends CheckedCkanClient implements PatchedCkan{ return request; } - /** - * Gets the catalogue url. - * - * @return the catalogueURL - */ - public String getCatalogueURL() { - - return catalogueURL; - } - - - /** - * Gets the ckan token. - * - * @return the ckanToken - */ - @Override - public String getCkanToken() { - - return ckanToken; - } - - /** - * Gets the timeout. - * - * @return the timeout - */ - public int getTimeout() { - return extendTimeout; - } - - /* (non-Javadoc) + /** + * Gets the organization. + * + * @param idOrName the id or name + * @return the organization + */ + /* (non-Javadoc) * @see eu.trentorise.opendata.jackan.CkanClient#getOrganization(java.lang.String) */ public synchronized CkanOrganization getOrganization(String idOrName) { @@ -147,6 +117,12 @@ public class ExtendCkanClient extends CheckedCkanClient implements PatchedCkan{ } + /** + * Gets the group. + * + * @param idOrName the id or name + * @return the group + */ /* (non-Javadoc) * @see eu.trentorise.opendata.jackan.CkanClient#getGroup(java.lang.String) */ @@ -164,7 +140,7 @@ public class ExtendCkanClient extends CheckedCkanClient implements PatchedCkan{ * * @return the object mapper */ - static ObjectMapper getObjectMapper() { + public static ObjectMapper getObjectMapper() { if (objectMapper == null) { objectMapper = new ObjectMapper(); configureObjectMapper(objectMapper); @@ -172,6 +148,15 @@ public class ExtendCkanClient extends CheckedCkanClient implements PatchedCkan{ return objectMapper; } + /** + * Gets the http. + * + * @param the generic type + * @param responseType the response type + * @param path the path + * @param params the params + * @return the http + */ /* (non-Javadoc) * @see org.gcube.datacatalogue.ckanutillibrary.server.patch.PatchedCkan#getHttp(java.lang.Class, java.lang.String, java.lang.Object[]) */ @@ -215,6 +200,13 @@ public class ExtendCkanClient extends CheckedCkanClient implements PatchedCkan{ } + /** + * Calc full url. + * + * @param path the path + * @param params the params + * @return the string + */ /* (non-Javadoc) * @see org.gcube.datacatalogue.ckanutillibrary.server.patch.PatchedCkan#calcFullUrl(java.lang.String, java.lang.Object[]) */ @@ -236,5 +228,26 @@ public class ExtendCkanClient extends CheckedCkanClient implements PatchedCkan{ + Arrays.toString(params), ex); } } + + /** + * Gets the catalogue URL. + * + * @return the catalogue URL + */ + public String getCatalogueURL() { + + return catalogueURL; + } + + /** + * Gets the ckan token. + * + * @return the ckan token + */ + @Override + public String getCkanToken() { + return ckanToken; + } + } diff --git a/target/classes/org/gcube/datacatalogue/ckanutillibrary/ckan/SimpleExtendCkanClient.class b/target/classes/org/gcube/datacatalogue/ckanutillibrary/ckan/SimpleExtendCkanClient.class deleted file mode 100644 index bd71c39c33c511db3dd1dab5ed81011b398658f1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7454 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 T getHttp(Class responseType, String path, Object... params) { - - checkNotNull(responseType); - checkNotNull(path); - String fullUrl = calcFullUrl(path, params); - T ckanResponse; - String returnedText; - - try { - - logger.debug("getting {}", fullUrl); - Request request = Request.Get(fullUrl); - configureRequest(request); - Response response = request.execute(); - InputStream stream = response.returnResponse() - .getEntity() - .getContent(); - - try (InputStreamReader reader = new InputStreamReader(stream, Charsets.UTF_8)) { - returnedText = CharStreams.toString(reader); - } - - logger.trace("returnedText {}", returnedText); - } catch (Exception ex) { - throw new CkanException("Error while performing GET. Request url was: " + fullUrl, this, ex); - } - try { - ckanResponse = getObjectMapper().readValue(returnedText, responseType); - } catch (Exception ex) { - throw new CkanException( - "Couldn't interpret json returned by the server! Returned text was: " + returnedText, this, ex); - } - - if (!ckanResponse.isSuccess()) { - throwCkanException("Error while performing GET. Request url was: " + fullUrl, ckanResponse); - } - return ckanResponse; - } - - - /* (non-Javadoc) - * @see org.gcube.datacatalogue.ckanutillibrary.server.patch.PatchedCkan#calcFullUrl(java.lang.String, java.lang.Object[]) - */ - public String calcFullUrl(String path, Object[] params) { - checkNotNull(path); - - try { - StringBuilder sb = new StringBuilder().append(catalogueURL) - .append(path); - for (int i = 0; i < params.length; i += 2) { - sb.append(i == 0 ? "?" : "&") - .append(URLEncoder.encode(params[i].toString(), "UTF-8")) - .append("=") - .append(URLEncoder.encode(params[i + 1].toString(), "UTF-8")); - } - return sb.toString(); - } catch (Exception ex) { - throw new JackanException("Error while building url to perform GET! \n path: " + path + " \n params: " - + Arrays.toString(params), ex); - } - } - - /** - * Gets the catalogue url. - * - * @return the catalogueURL - */ - public String getCatalogueURL() { - - return catalogueURL; - } - -} diff --git a/target/classes/org/gcube/datacatalogue/ckanutillibrary/db/DBCaller.class b/target/classes/org/gcube/datacatalogue/ckanutillibrary/db/DBCaller.class index 6147ada7816a6bbeb1435194f9bf016cc98ea7e2..5cb155fb49e81f2bb9510d7d935869362dc70db3 100644 GIT binary patch delta 1820 zcmaKtdu)?c7{;IT_4chRYgyg8c2hnWFfNme5S1pNWDJ40RuK^viI!2e!q$zhgH0n- z6#YXJgGZvE$jyLUMTmo;5Y&K-yC~Zbyeo>12`X|Cm`}g94E)1<$vHWv@Atg#_j{jn z`qHp@UhBSV+jjyOBAoA8-?xZ9a+k$z*QQrSw3_N*Bpj#+dbKUbEr*R6Dw+iBkzlkY z5)Oq+wTeI$e|pDuyYRINIA;WA2L_f0!leTzltn7%1g4e;ReUKh;J#o~*V01MZqn6C z0_EkwoAM45v8O;C`BrC5O-oOj_vx8<1R$-0HP>H z4W?l>Dlms*9iJz$kmFL!#oMT-<~-Ez#?zF322ETX!n62{b2H|n9nZtVWRJ$b0k@$W zSNt06g9^c<`}rKui)_LyrZljCSvbgFjVz&zYAQ=CMj;O42+S;@FV&C2!sNO59A7Z* zST-eX*X5ciSIwQ_Fm<3#E^s^L_Ke&KEh*fe&w>OTfM`pAJ(^^9ypyTUP811WzpZ$o zDE)-jm<)Q6L2hH5Jfmc8W`FlrjaaF`mkjwPp_BfdEY0j`{UN#hNiNLHtIxqJSj=X` z=DjR(F+S2~gWir}WO8o-vLMOrRYtvr?pQ=lZ(szLU<}^EgG679$_p-Kv=%+x}#?c0sq2R74`}o=frR;#suyrVoEJ@8SeaeDVgvHeKh`l;GsT=7eG0*px7=hDiy- z`V;0farW!hHM5+!buCPO-LU)!o0Xj6a?SENcY#WO3jBsPdDxvb=*)l2sGokG_}>@7 zVpt8MaU1>+KH)XS9O_H|Te>_$dtB6w*lE_wx>*elYXh#(vQ7b6;py#AIG6PdxaqV4_&<+g-pO|I66>cW?%(qRCY0ot|pQxru6KxY|Zq~_nve1-S_gG-+4Es z*Uq#Yy}JJ(fHWD?V0qUhZgt4yZtOF4>W#;&*GWQ;z`4q^&NHpZQ=C8Tu7a|XD$nvF zuNfx=Uy|8#?i5XuDw8Hz$_*O7_Zb?}} zWx2Pk*t5o)V8&^+%{Ep)BS=+OM!D2+n@fIFeYSM@MNPD?m$Pc8J#of4EBfIRmWbO3<*@OBS|!MzhjE%YL_D^EX;~FF{utmPK4DeqhS{qR}__$d(C23 zQzN1!qA@d~Npl*ZBb>S&O=-dUd-lNk9^3{@y#tE=$&lVo(_I801D5ue~w`hCWT)=;!AMl0vZEEtDasTzp7ac*}w4T06B{yw>0B!x88(BO~~`%3$-CS#eK?$*ED30 zxO_vG6naE{rw&I?vV1?X{Xw0LPO7m{fLhA#xBFRBE&KIbLqPt;i01k!SSX|wPt)sJ zIPpAH*^cY+0bdt)JfJ-!dwWoJE8YEKYfRY`5Zl0{mFNq|o{rpr*nZh>35XrWG^s(c{nFkH!w~XR zzw3rc-IVkv{#7F$;I}Fua9>d12EV{RtNAf|l*Juavy@ptQY_4GXSpuY;>JN<`62Sw z#;ZMoGy*Y;NX%tjIjkd>6%^C1=T&duRc}WRUP2e;=*FvD*Wm=)?!ntQ8EASKwT4j7 z4I$Ka6aSyJ9gNnc2HkTekS@Wm_-&Xj%|T!- z?6Y@-k>AzQSXay++hH=)LDySwUa}=!_v4lw`ImYkc1Gf*09F5zcR4_w!C`5_71HGt zQKw_4I1E9&$fMin6Qgp+&8j)WSKNoOyoOX(F_m>p$2r`D^8{!Bw{a?E;Q|4=$oG2* zg&5?EzD%r!uuF8jNxNGF^`hYe?mNVQ zvQq=+17|6s*lcU?{lsz}Kq8^b7+53o diff --git a/target/classes/org/gcube/datacatalogue/ckanutillibrary/db/DBCaller.java b/target/classes/org/gcube/datacatalogue/ckanutillibrary/db/DBCaller.java index f989172..1e1532d 100644 --- a/target/classes/org/gcube/datacatalogue/ckanutillibrary/db/DBCaller.java +++ b/target/classes/org/gcube/datacatalogue/ckanutillibrary/db/DBCaller.java @@ -95,7 +95,7 @@ public class DBCaller { */ public Map getGroupsByUserFromDB(String username){ checkNotNull(username); - LOG.debug("Get groups by user called"); + LOG.debug("Get groups by user called for username: "+username); //couples (groups id, capacity) of the user in the group @@ -129,6 +129,8 @@ public class DBCaller { }finally{ closeConnection(connection); } + + LOG.debug("returning map: "+toReturn); return toReturn; } @@ -140,7 +142,7 @@ public class DBCaller { * @return the user id for username */ private String getUserIdForUsername(String username) { - LOG.debug("Get user id for username called"); + LOG.debug("Get user id for username called for username: "+username); Connection connection = null; String userId = null; @@ -150,7 +152,7 @@ public class DBCaller { String selQuery = "SELECT \"id\" FROM \"public\".\"user\" WHERE \"name\"=?;"; - LOG.info("Performing query: "+selQuery); + LOG.debug("Performing query: "+selQuery); PreparedStatement preparedStatement = connection.prepareStatement(selQuery); preparedStatement.setString(1, username); @@ -213,6 +215,8 @@ public class DBCaller { }finally{ closeConnection(connection); } + + LOG.debug("returning map: "+toReturn); return toReturn; } diff --git a/target/classes/org/gcube/datacatalogue/ckanutillibrary/gcat/GCatCaller.class b/target/classes/org/gcube/datacatalogue/ckanutillibrary/gcat/GCatCaller.class index 19c51a32b26b39273687881e5a13d43ce6eb69fa..1cda543d5e091053548845b689918194d3cbca96 100644 GIT binary patch literal 1428 zcmbVLYg5xe6g|tUC4^TMD~M7=9sxBfs73HuD54b{QD*SlHeF+CnlQ=M(SPM*1eFhrFh&O@_8YSP=%g(VIdKL-ue?kvlSs z-kaz{KSQT04g3sf4!8!`r35F9UQb;rOmb^f$)oW!DJ?CX#XpRo|H+kf# zeR9~bm@ph@Mo83In+94jXyOzMmHUi|c65*q`Pz#a<~4)=s5jN7pTsRue_|nvVYJ3; zL~!Cb3Qf8jH8+;uIbvISVGyTqp5dJCOCY5Eg!`|;s3t1Zu!d6#7pT~Wd-tI3`4thR zF~KmfB4kdD4AIF^f?Pm^at6jQrNn2|*R+WlTx96r+uI_jFkJd4x(Uoe8kZ@S8sLkH zN_WM?Ra~PXk>S2BhLcm)QMFx|!;KWK(|{fx7ZW#;WoWO6a@|c~o?+n9P2&MovY>+-#rz{U zk0le!xTk8MJs7&GaTqjEj5u^W?mrDk*~SD2rX`AC}?35$(ODbqMl~r;-^$@vF>htBv% z`6^VIas1gos?&2f3&|jkbjHl&KE8Xu^S#df_U{*e{0U$hRRbx3IX|ddb-P(rR!v6I z=HK<}O=a2NORpI@uIp3-89e138Cfeu85O1Ls=z?E!1-fq(XsL8s8(PyUJB=MzE$v3itF>VY0_Kr(Pac&7vZc25auhgTop-uQ8!P%qTMXT; znQg1&*Xt_aQSZF%I-V0P@YY1WBG6s*Ybt|&TrhB6;L>rOWobu#@YF;W7X{LF6}7Mg z#wI#!7hM^Kh5SEFrXetBB8`kdf64LGdb3eg!DCrToWk%4;jv21fv@KvIc*{#2NH3Nzr#sC~)W0H9W=>CjJ65 zcb~ipRkZ8}>$1VqAgb)uNJGV$(}N-~P^Q$QLIjdf`JVxy&|bH_ylDGj|8S(!Ip`~c)}*3qpe7{Ns7;% z5OPQ258Fn&k}cm!>i&cttF?{fxpZ%ny8?Z>2RXL#LRE4?w$|)nEp?~1w2bQMvQzhD z)C}TxmK6Kw!u+XUSz@WMKvsPvFr}>V&G?PQW)ac z6CYi}rC0*)*tQb23Sm-|4^8f4cyj6)UY|U`$mY~Oa?fzRjgjR&;7yKWG(V0(ycOdO zwX}IM#&hDtP70!r^F|62l=U)*Jf?6ncJxPL=)h)w!N38m&Fnk-n4a3hO!hqvdwBnM zETnLN;^sbw9?k7uJ8GW-F?`7-a@mahvF~u{XIE@{u>QsL;CL`8j;b zRf=oop7ZB1&KI#qcVjt_rAOH>WAl^0;rbrFZd=Rn4sef&UyLp3v{NIoB=BvFCtm`T Cd@0lb diff --git a/target/classes/org/gcube/datacatalogue/ckanutillibrary/gcat/GCatCaller.java b/target/classes/org/gcube/datacatalogue/ckanutillibrary/gcat/GCatCaller.java index c14eca7..82cf4c6 100644 --- a/target/classes/org/gcube/datacatalogue/ckanutillibrary/gcat/GCatCaller.java +++ b/target/classes/org/gcube/datacatalogue/ckanutillibrary/gcat/GCatCaller.java @@ -2,19 +2,11 @@ package org.gcube.datacatalogue.ckanutillibrary.gcat; import java.io.IOException; import java.net.MalformedURLException; -import java.util.List; -import org.gcube.datacatalogue.ckanutillibrary.ckan.SimpleExtendCkanClient; import org.gcube.gcat.client.Item; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.fasterxml.jackson.core.JsonParseException; -import com.fasterxml.jackson.databind.JsonMappingException; - -import eu.trentorise.opendata.jackan.model.CkanDataset; -import eu.trentorise.opendata.jackan.model.CkanLicense; - // TODO: Auto-generated Javadoc /** * The Class GCatCaller. @@ -24,18 +16,17 @@ import eu.trentorise.opendata.jackan.model.CkanLicense; */ public class GCatCaller { - private SimpleExtendCkanClient jackanCkanClient; - private String catalogueURL; private static final Logger LOG = LoggerFactory.getLogger(GCatCaller.class); /** * Instantiates a new g cat caller. + * + * @param catalogueURL the catalogue URL */ public GCatCaller(String catalogueURL) { this.catalogueURL = catalogueURL; - this.jackanCkanClient = new SimpleExtendCkanClient(catalogueURL); } @@ -43,27 +34,27 @@ public class GCatCaller { * Gets the dataset for name. * * @param datasetIdOrName the dataset id or name - * @return the dataset for name - * @throws JsonParseException the json parse exception - * @throws JsonMappingException the json mapping exception + * @return the jsonValue + * @throws MalformedURLException * @throws IOException Signals that an I/O exception has occurred. */ - public CkanDataset getDatasetForName(String datasetIdOrName) throws JsonParseException, JsonMappingException, IOException { + public String getDatasetForName(String datasetIdOrName) throws MalformedURLException { LOG.debug("Get dataset for name "+datasetIdOrName+ "called"); - String json = new Item().read(datasetIdOrName); - return SimpleExtendCkanClient.getObjectMapper().readValue(json, CkanDataset.class); + return new Item().read(datasetIdOrName); } - - - /** - * TODO gCAT missing - * @return - * @throws MalformedURLException - */ - public List getLicenseList() { - LOG.debug("Get linces list called"); - return jackanCkanClient.getLicenseList(); + + /** + * Creates the dataset. + * + * @param jsonDataset the json dataset + * @param socialPost if true sends the social post + * @return the jsonValue + * @throws MalformedURLException the malformed URL exception + */ + public String createDataset(String jsonDataset, boolean socialPost) throws MalformedURLException { + LOG.debug("Create dataset called"); + return new Item().create(jsonDataset,socialPost); } } diff --git a/target/classes/org/gcube/datacatalogue/ckanutillibrary/server/DataCatalogue.class b/target/classes/org/gcube/datacatalogue/ckanutillibrary/server/DataCatalogue.class index 8b83f3594d2282cc92399b545f9ed573e9833c60..02fc08f595baa3e30552392b7bf031eaa857958f 100644 GIT binary patch delta 389 zcmcaFvQw1n)W2Q(7#J9g8H^@!otS)Qr$9Bb5a-?#DE%vnWHqLCSK5D{0ZVrRsiZ(U{sl0#aJ$- z!N?$-l~|UjpOcuEuJ2lroLW$lnV-kV*n+0iWHLXq=;r%O*BB?ea%wXQPcGyXuV-Lk zWZ+`pW?*FC0Xmb3ffvZs|1SZGjIa+F)|o{y<-Rfc2_y4 delta 342 zcmdlfdS8U=)W2Q(7#J9g84M}HU9- cS7*=w>(gY=f~(U8it8Zpb%8Q^U{B}+00QbL)&Kwi diff --git a/target/classes/org/gcube/datacatalogue/ckanutillibrary/server/DataCatalogue.java b/target/classes/org/gcube/datacatalogue/ckanutillibrary/server/DataCatalogue.java index e8b5494..78cece6 100644 --- a/target/classes/org/gcube/datacatalogue/ckanutillibrary/server/DataCatalogue.java +++ b/target/classes/org/gcube/datacatalogue/ckanutillibrary/server/DataCatalogue.java @@ -39,67 +39,6 @@ public interface DataCatalogue { */ String getUnencryptedUrlFromDatasetIdOrName(String datasetIdOrName); - /** - * Create a dataset with those information. The method allows to have multiple - * values for the same custom field key. NOTE: unfortunately java doesn't - * support overload in java interface methods (that's way I cannot use the same - * name for the method) - * - * @param title the title - * @param name (unique identifier) - * @param organizationNameOrId the organization name or id - * @param author the author - * @param authorMail the author mail - * @param maintainer the maintainer - * @param maintainerMail the maintainer mail - * @param version the version - * @param description the description - * @param licenseId the license id - * @param tags the tags - * @param customFields the custom fields - * @param resources the resources - * @param setPublic (manage visibility: Admin role is needed) - * @return the id of the dataset on success, null otherwise - * @throws Exception the exception - */ - String createCKanDatasetMultipleCustomFields(String title, String name, String organizationNameOrId, String author, - String authorMail, String maintainer, String maintainerMail, long version, String description, - String licenseId, List tags, Map> customFields, List resources, - boolean setPublic) throws Exception; - - /** - * Patch a product with product id productId by using the couples in - * customFieldsToChange. NOTE: only the specified custom fields will be changed. - * If a custom field with a given key already exists, and removeOld is set to - * false, the new values are added at the end of the list. Otherwise they are - * lost. - * - * @param productId the product id - * @param customFieldsToChange the custom fields to change - * @param removeOld the remove old - * @return true, if successful - */ - boolean patchProductCustomFields(String productId, Map> customFieldsToChange, - boolean removeOld); - - /** - * Add a resource described by the bean to the dataset id into - * resource.datasetId - * - * @param resource the resource - * @return String the id of the resource on success, null otherwise - * @throws Exception the exception - */ - String addResourceToDataset(ResourceBean resource) throws Exception; - - /** - * Remove the resource with id resourceId from the dataset in which it is. - * - * @param resourceId the resource id - * @return true on success, false otherwise. - */ - boolean deleteResourceFromDataset(String resourceId); - /** * Create a dataset with those information. * @@ -201,4 +140,86 @@ public interface DataCatalogue { */ Map> getUserRoleByOrganization(String username); + + + + + //WRITE OPERATIONS + + + + + + /** + * Set searchable field + * The field, if set to true, allows organization's users to view private products also in groups + * @param datasetId the id of the dataset to update + * @param searchable the value to assign to the field + * @return true if the field is set, false otherwise + */ + boolean setSearchableField(String datasetId, boolean searchable); + + + /** + * Create a dataset with those information. The method allows to have multiple + * values for the same custom field key. NOTE: unfortunately java doesn't + * support overload in java interface methods (that's way I cannot use the same + * name for the method) + * + * @param the username that is submitting the publishing request + * @param title the title + * @param name (unique identifier) + * @param organizationNameOrId the organization name or id + * @param author the author + * @param authorMail the author mail + * @param maintainer the maintainer + * @param maintainerMail the maintainer mail + * @param version the version + * @param description the description + * @param licenseId the license id + * @param tags the tags + * @param customFields the custom fields + * @param resources the resources + * @param setPublic (manage visibility: Admin role is needed) + * @return the id of the dataset on success, null otherwise + * @throws Exception the exception + */ + String createCKanDatasetMultipleCustomFields(String username, String title, String name, String organizationNameOrId, String author, + String authorMail, String maintainer, String maintainerMail, long version, String description, + String licenseId, List tags, Map> customFields, List resources, + boolean setPublic) throws Exception; + + /** + * Patch a product with product id productId by using the couples in + * customFieldsToChange. NOTE: only the specified custom fields will be changed. + * If a custom field with a given key already exists, and removeOld is set to + * false, the new values are added at the end of the list. Otherwise they are + * lost. + * + * @param productId the product id + * @param customFieldsToChange the custom fields to change + * @param removeOld the remove old + * @return true, if successful + */ + boolean patchProductCustomFields(String productId, Map> customFieldsToChange, + boolean removeOld); + + /** + * Add a resource described by the bean to the dataset id into + * resource.datasetId + * + * @param resource the resource + * @return String the id of the resource on success, null otherwise + * @throws Exception the exception + */ + String addResourceToDataset(ResourceBean resource) throws Exception; + + /** + * Remove the resource with id resourceId from the dataset in which it is. + * + * @param resourceId the resource id + * @return true on success, false otherwise. + */ + boolean deleteResourceFromDataset(String resourceId); + } diff --git a/target/classes/org/gcube/datacatalogue/ckanutillibrary/server/DataCatalogueImpl.class b/target/classes/org/gcube/datacatalogue/ckanutillibrary/server/DataCatalogueImpl.class index 8f19b4d0e023f7cca4cffac9bafc6edf7125c77c..66e6004a1c4c66932e9b858147cf8a8cae0a23e5 100644 GIT binary patch literal 29428 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

lpzAN?k*mm?O8s`w9 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 Peq~UAJW;2t3q1HH=xg-OVnK(0Hty^1L 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 mapAccessURLToCatalogue; + private static final String CATALOGUE_TAB_ENDING_URL = "/catalogue"; // gCat client @@ -72,10 +82,13 @@ public class DataCatalogueImpl implements DataCatalogue { private DBCaller dbCaller; // ckan client - private SimpleExtendCkanClient ckanCaller; + private ExtendCkanClient ckanCaller; // hashmap for ckan api keys private ConcurrentHashMap apiKeysMap; + + //http ckan caller + private DirectCkanCaller directCkanCaller; // apikey bean expires after X minutes in the above map private static final int EXPIRE_KEY_TIME = 60 * 60 * 1000; @@ -97,7 +110,7 @@ public class DataCatalogueImpl implements DataCatalogue { CKAN_DB_USER = runningInstance.getDataBaseUser().trim(); CKAN_DB_PASSWORD = runningInstance.getDataBasePassword().trim(); - //CKAN_TOKEN_SYS = runningInstance.getSysAdminToken().trim(); + CKAN_TOKEN_SYS = runningInstance.getSysAdminToken().trim(); CKAN_EMAIL = runningInstance.getEmailCatalogue().trim(); CKAN_CATALOGUE_URL = runningInstance.getDataCatalogueUrl().get(0).trim(); @@ -113,17 +126,13 @@ public class DataCatalogueImpl implements DataCatalogue { // build the clients gCatCaller = new GCatCaller(CKAN_CATALOGUE_URL); - dbCaller = new DBCaller(CKAN_DB_URL, CKAN_DB_PORT, CKAN_DB_NAME, CKAN_DB_USER, CKAN_DB_PASSWORD); - - ckanCaller = new SimpleExtendCkanClient(CKAN_CATALOGUE_URL); - + ckanCaller = new ExtendCkanClient(CKAN_CATALOGUE_URL); + directCkanCaller = new DirectCkanCaller(CKAN_CATALOGUE_URL); // init map apiKeysMap = new ConcurrentHashMap(); - // save the context CONTEXT = scope; - // extended roles extendRoleInOrganization = runningInstance.getExtendRoleInOrganization(); } @@ -228,7 +237,8 @@ public class DataCatalogueImpl implements DataCatalogue { String authzToken = SecurityTokenProvider.instance.get(); if(authzToken!=null && !authzToken.isEmpty()) { LOG.info("gcube-token found. Calling the gCat client"); - return gCatCaller.getDatasetForName(datasetId); + String jsonDataset = gCatCaller.getDatasetForName(datasetId); + return MarshUnmarshCkanObject.toCkanDataset(jsonDataset); } LOG.info("No api-key or gcube-token found. Calling Ckan Client without API-KEY"); @@ -272,13 +282,7 @@ public class DataCatalogueImpl implements DataCatalogue { return url; } - public String createCKanDatasetMultipleCustomFields(String title, String name, String organizationNameOrId, - String author, String authorMail, String maintainer, String maintainerMail, long version, - String description, String licenseId, List tags, Map> customFields, - List resources, boolean setPublic) throws Exception { - return null; - } - + @Override public Map> getUserRoleByGroup(String username) { LOG.info("Get user role by group called. The username is: "+username); @@ -328,6 +332,7 @@ public class DataCatalogueImpl implements DataCatalogue { HashMap subMap = new HashMap(); subMap.put(org, partialResult.get(orgID)); toReturn.put(orgID, subMap); + LOG.debug("For organisation: " + org.getName() + ", the user "+username+" has role: "+subMap); } LOG.debug("Returning map " + toReturn); @@ -399,10 +404,8 @@ public class DataCatalogueImpl implements DataCatalogue { // checks checkNotNull(username); - // in order to avoid errors, the username is always converted String ckanUsername = CatalogueUtilMethods.fromUsernameToCKanUsername(username); - // list to return List toReturn = new ArrayList(); @@ -413,12 +416,11 @@ public class DataCatalogueImpl implements DataCatalogue { // iterate over them for (CkanOrganization ckanOrganization : organizations) { - // get the list of users in it (if you try ckanOrganization.getUsers() it returns null.. maybe a bug TODO) List users = ckanCaller.getOrganization(ckanOrganization.getName()).getUsers(); - // check if the current user is among them for (CkanUser ckanUser : users) { + if(ckanUser.getName().equals(ckanUsername)){ LOG.debug("User " + ckanUsername + " is into " + ckanOrganization.getName()); @@ -440,10 +442,8 @@ public class DataCatalogueImpl implements DataCatalogue { // checks checkNotNull(username); - // in order to avoid errors, the username is always converted String ckanUsername = CatalogueUtilMethods.fromUsernameToCKanUsername(username); - // list to return List toReturn = new ArrayList(); @@ -459,6 +459,7 @@ public class DataCatalogueImpl implements DataCatalogue { // check if the current user is among them for (CkanUser ckanUser : users) { + if(ckanUser.getName().equals(ckanUsername)){ LOG.debug("User " + ckanUsername + " is into " + ckanGroup.getName()); @@ -513,15 +514,22 @@ public class DataCatalogueImpl implements DataCatalogue { return null; } - - - - - - - - - + @Override + public boolean existProductWithNameOrId(String nameOrId) { + + checkNotNull(nameOrId); + checkArgument(!nameOrId.isEmpty()); + + try{ + ExtendCkanClient client = new ExtendCkanClient(CKAN_CATALOGUE_URL, CKAN_TOKEN_SYS); + CkanDataset product = client.getDataset(nameOrId); + return product != null; + }catch(Exception e){ + LOG.debug("A dataset with name " + nameOrId + " doesn't exist"); + return false; + } + } + /* * @@ -546,6 +554,163 @@ public class DataCatalogueImpl implements DataCatalogue { * */ + @Override + public String createCKanDatasetMultipleCustomFields(String username, String title, String name, String organizationNameOrId, + String author, String authorMail, String maintainer, String maintainerMail, long version, + String description, String licenseId, List tags, Map> customFieldsMultiple, + List resources, boolean setPublic) throws Exception { + + // delegate the private method + return createCkanDatasetBody(username, title, name, organizationNameOrId, author, authorMail, maintainer, maintainerMail, + version, description, licenseId, tags, null, customFieldsMultiple, resources, setPublic); + } + + // the body of the actual dataset creation methods + private String createCkanDatasetBody(String username, String title, String name, String organizationNameOrId, String author, + String authorMail, String maintainer, String maintainerMail, long version, String description, + String licenseId, List tags, Map customFields, + Map> customFieldsMultipleValues, List resources, boolean setPublic) + throws Exception { + + // checks (minimum) + checkNotNull(username); + checkNotNull(organizationNameOrId); + checkArgument(!organizationNameOrId.isEmpty()); + checkArgument(!(title == null && name == null || title.isEmpty() && name.isEmpty()), "Name and Title cannot be empty/null at the same time!"); + + LOG.debug("Request for dataset creation"); + + //ExtendCkanClient client = new ExtendCkanClient(CKAN_CATALOGUE_URL, apiKey); + + //String ckanUsername = getUserFromApiKey(apiKey).getName(); + CkanDataset dataset = new CkanDataset(); + + // in order to avoid errors, the username is always converted + String ckanUsername = CatalogueUtilMethods.fromUsernameToCKanUsername(username); + + String nameToUse = name; + if(nameToUse == null) + nameToUse = CatalogueUtilMethods.fromProductTitleToName(title); + + LOG.debug("Name of the dataset is going to be " + nameToUse + ". Title is going to be " + title); + + dataset.setName(nameToUse); + dataset.setTitle(title); + +// CkanOrganization orgOwner = client.getOrganization(organizationNameOrId); +// dataset.setOwnerOrg(orgOwner.getId()); + dataset.setAuthor(author); + dataset.setAuthorEmail(authorMail); + dataset.setMaintainer(maintainer); + dataset.setMaintainerEmail(maintainerMail); + dataset.setVersion(String.valueOf(version)); + + // description must be escaped + if(description != null && !description.isEmpty()){ + Source descriptionEscaped = new Source(description); + Segment htmlSeg = new Segment(descriptionEscaped, 0, descriptionEscaped.length()); + Renderer htmlRend = new Renderer(htmlSeg); + dataset.setNotes(htmlRend.toString()); + + LOG.debug("Description escaped " + htmlRend.toString()); + } + + dataset.setLicenseId(licenseId); + + // set the tags, if any + if(tags != null && !tags.isEmpty()){ + List ckanTags = new ArrayList(tags.size()); + for (String stringTag : tags) { + ckanTags.add(new CkanTag(stringTag)); + } + dataset.setTags(ckanTags); + } + + // set the custom fields, if any + List extras = new ArrayList(); + + if(customFields != null && !customFields.isEmpty()){ + + Iterator> iterator = customFields.entrySet().iterator(); + + while (iterator.hasNext()) { + Map.Entry entry = iterator.next(); + extras.add(new CkanPair(entry.getKey(), entry.getValue())); + } + + }else if(customFieldsMultipleValues != null && !customFieldsMultipleValues.isEmpty()){ + + Iterator>> iterator = customFieldsMultipleValues.entrySet().iterator(); + while (iterator.hasNext()) { + Map.Entry> entry = iterator.next(); + List valuesForEntry = entry.getValue(); + for (String value : valuesForEntry) { + extras.add(new CkanPair(entry.getKey(), value)); + } + } + } + + dataset.setExtras(extras); + + // check if we need to add the resources + if(resources != null && !resources.isEmpty()){ + + LOG.debug("We need to add resources to the dataset"); + + try{ + List resourcesCkan = new ArrayList(); + for(ResourceBean resource: resources){ + + LOG.debug("Going to add resource described by " + resource); + CkanResource newResource = new CkanResource(); + newResource.setDescription(resource.getDescription()); + newResource.setId(resource.getId()); + newResource.setUrl(resource.getUrl()); + newResource.setName(resource.getName()); + newResource.setMimetype(resource.getMimeType()); + newResource.setFormat(resource.getMimeType()); + newResource.setOwner(ckanUsername); + resourcesCkan.add(newResource); + } + + // add to the dataset + dataset.setResources(resourcesCkan); + + }catch(Exception e){ + LOG.error("Unable to add those resources to the dataset", e); + } + + } + + // try to create + String jsonValueDataset = MarshUnmarshCkanObject.toJsonValueDataset(dataset); + LOG.debug("Marshalling dataset is: " + jsonValueDataset); + jsonValueDataset = gCatCaller.createDataset(jsonValueDataset,true); + LOG.debug("Created dataset is: " + jsonValueDataset); + + if(jsonValueDataset != null){ + CkanDataset toCkanDataset = MarshUnmarshCkanObject.toCkanDataset(jsonValueDataset); + LOG.debug("Dataset with name " + toCkanDataset.getName() + " has been created. Setting visibility"); + + // set visibility + boolean visibilitySet = directCkanCaller.setDatasetPrivate( + !setPublic, // swap to private + toCkanDataset.getOrganization().getId(), + toCkanDataset.getId(), + CKAN_TOKEN_SYS); // use sysadmin api key to be sure it will be set + + LOG.info("Was visibility set to " + (setPublic ? "public" : "private") + "? " + visibilitySet); + + // set searchable to true if dataset visibility is private + if(!setPublic){ // (swap to private) + boolean searchableSet = setSearchableField(toCkanDataset.getId(), true); + LOG.info("Was searchable set to True? " + searchableSet); + } + return toCkanDataset.getId(); + } + + return null; + } public boolean patchProductCustomFields(String productId, Map> customFieldsToChange, boolean removeOld) { @@ -560,9 +725,11 @@ public class DataCatalogueImpl implements DataCatalogue { return false; } - public boolean existProductWithNameOrId(String nameOrId) { - return false; + @Override + public boolean setSearchableField(String datasetId, boolean searchable) { + return directCkanCaller.setSearchableField(datasetId, searchable, CKAN_TOKEN_SYS); } + }