From a881355db7b470f00cc24a691f79fea1df82034b Mon Sep 17 00:00:00 2001 From: Luca Frosini Date: Thu, 12 Apr 2018 15:56:38 +0000 Subject: [PATCH] Merged from private branch git-svn-id: https://svn.d4science.research-infrastructures.eu/gcube/trunk/data-catalogue/catalogue-ws@166966 82a268e6-3cf1-43bd-a215-b396298e98cf --- .classpath | 1 + pom.xml | 26 +- .../catalogue/beans/resource/CustomField.java | 134 ++-- .../catalogue/entities/CatalogueItem.java | 73 ++ .../catalogue/utils/CachesManager.java | 65 +- .../catalogue/utils/CatalogueUtils.java | 282 ++++--- .../catalogue/utils/Constants.java | 3 +- .../catalogue/utils/ContextUtils.java | 39 + .../catalogue/utils/Delegator.java | 233 +++--- .../utils/GcoreEndpointReaderSNL.java | 53 +- .../utils/PackageCreatePostActions.java | 101 +-- .../catalogue/utils/Validator.java | 703 +++++++++--------- .../WritePostCatalogueManagerThread.java | 225 +++--- .../datacatalogue/catalogue/ws/Group.java | 91 +-- .../datacatalogue/catalogue/ws/Item.java | 486 ++++++------ .../catalogue/ws/ItemProfile.java | 50 +- .../datacatalogue/catalogue/ws/License.java | 14 +- .../catalogue/ws/Organization.java | 153 ++-- .../datacatalogue/catalogue/ws/Resource.java | 350 +++------ .../datacatalogue/catalogue/ws/User.java | 32 +- src/main/resources/ehcache.xml | 21 - src/test/java/CataloguePublishExample.java | 178 +++-- src/test/java/JavaTests.java | 123 ++- src/test/java/TestJersey.java | 82 +- .../datacatalogue/catalogue/ScopedTest.java | 121 +++ .../catalogue/entities/CatalogueItemTest.java | 23 + src/test/resources/logback-test.xml | 19 + 27 files changed, 1825 insertions(+), 1856 deletions(-) create mode 100644 src/main/java/org/gcube/datacatalogue/catalogue/entities/CatalogueItem.java create mode 100644 src/main/java/org/gcube/datacatalogue/catalogue/utils/ContextUtils.java delete mode 100644 src/main/resources/ehcache.xml create mode 100644 src/test/java/org/gcube/datacatalogue/catalogue/ScopedTest.java create mode 100644 src/test/java/org/gcube/datacatalogue/catalogue/entities/CatalogueItemTest.java create mode 100644 src/test/resources/logback-test.xml diff --git a/.classpath b/.classpath index ee58b3d..2a15c0b 100644 --- a/.classpath +++ b/.classpath @@ -6,6 +6,7 @@ + diff --git a/pom.xml b/pom.xml index eba8e34..3672644 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ org.gcube.data-catalogue catalogue-ws war - 1.2.0-SNAPSHOT + 1.3.0-SNAPSHOT catalogue-ws @@ -22,7 +22,14 @@ org.gcube.distribution - maven-smartgears-bom + gcube-bom + LATEST + pom + import + + + org.gcube.distribution + gcube-smartgears-bom LATEST pom import @@ -40,11 +47,19 @@ + - net.sf.ehcache - ehcache - 2.10.0 + javax.cache + cache-api + 1.0.0 + + org.ehcache + ehcache + 3.5.2 + runtime + + org.gcube.resources.discovery ic-client @@ -103,6 +118,7 @@ jersey-media-multipart ${version.jersey} + org.glassfish.jersey.media jersey-media-sse diff --git a/src/main/java/org/gcube/datacatalogue/catalogue/beans/resource/CustomField.java b/src/main/java/org/gcube/datacatalogue/catalogue/beans/resource/CustomField.java index 9ff0330..07d32b2 100644 --- a/src/main/java/org/gcube/datacatalogue/catalogue/beans/resource/CustomField.java +++ b/src/main/java/org/gcube/datacatalogue/catalogue/beans/resource/CustomField.java @@ -6,36 +6,56 @@ import org.json.simple.JSONObject; * A custom field bean. It also stores index of the category and of the metadata field associated. * These are used to sort them before pushing the content to CKAN. * If they are missing, indexes are set to Integer.MAX_VALUE. - * @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it) + * @author Costantino Perciante (ISTI - CNR) + * @author Luca Frosini (ISTI - CNR) */ -public class CustomField implements Comparable{ - +public class CustomField implements Comparable { + private String key; private String qualifiedKey; private String value; - private int indexMetadataField = Integer.MAX_VALUE; + private int indexCategory = Integer.MAX_VALUE; + private int indexMetadataField = Integer.MAX_VALUE; + + private void init(String key, String value, int indexCategory, int indexMetadataField) { + if(key == null || value == null || key.isEmpty()) { + throw new IllegalArgumentException( + "A custom field must have a key and a value! Provided values are " + key + "=" + value); + } + + this.key = key; + this.qualifiedKey = key; + this.value = value; + + this.indexMetadataField = indexMetadataField; + this.indexCategory = indexCategory; + + if(this.indexCategory < 0) { + this.indexCategory = Integer.MAX_VALUE; + } + + if(this.indexMetadataField < 0) { + this.indexMetadataField = Integer.MAX_VALUE; + } + } + + public CustomField(JSONObject object) { super(); - this.key = (String)object.get("key"); - this.qualifiedKey = key; - this.value = (String)object.get("value"); - if(key == null || value == null || key.isEmpty()) - throw new IllegalArgumentException("A custom field must have a key and a value! Provided object is " + object.toString()); + init((String) object.get("key"), (String) object.get("value"), -1, -1); } - + /** * @param key * @param value */ public CustomField(String key, String value) { super(); - this.key = key; - this.qualifiedKey = key; - this.value = value; + init(key, value, -1, -1); } - + /** * @param key * @param value @@ -44,79 +64,71 @@ public class CustomField implements Comparable{ */ public CustomField(String key, String value, int indexCategory, int indexMetadataField) { super(); + init(key, value, indexCategory, indexMetadataField); + } + + public String getKey() { + return key; + } + + public void setKey(String key) { this.key = key; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { this.value = value; - this.indexMetadataField = indexMetadataField; - this.indexCategory = indexCategory; - this.qualifiedKey = key; - - if(this.indexCategory < 0) - this.indexCategory = Integer.MAX_VALUE; - - if(this.indexMetadataField < 0) - this.indexMetadataField = Integer.MAX_VALUE; } - - public int getIndexMetadataField() { - return indexMetadataField; - } - + public String getQualifiedKey() { return qualifiedKey; } - + public void setQualifiedKey(String qualifiedKey) { this.qualifiedKey = qualifiedKey; } - - public void setIndexMetadataField(int indexMetadataField) { - this.indexMetadataField = indexMetadataField; - if(this.indexMetadataField < 0) - this.indexMetadataField = Integer.MAX_VALUE; - } - + + public int getIndexCategory() { return indexCategory; } - + public void setIndexCategory(int indexCategory) { this.indexCategory = indexCategory; if(this.indexCategory < 0) this.indexCategory = Integer.MAX_VALUE; } - - public String getKey() { - return key; + + public int getIndexMetadataField() { + return indexMetadataField; } - - public void setKey(String key) { - this.key = key; + + public void setIndexMetadataField(int indexMetadataField) { + this.indexMetadataField = indexMetadataField; + if(this.indexMetadataField < 0) { + this.indexMetadataField = Integer.MAX_VALUE; + } } - - public String getValue() { - return value; - } - - public void setValue(String value) { - this.value = value; - } - + @Override public String toString() { - return "CustomField [key=" + key + ", qualifiedKey=" + qualifiedKey - + ", value=" + value + ", indexMetadataField=" - + indexMetadataField + ", indexCategory=" + indexCategory + "]"; + return "CustomField [key=" + key + ", qualifiedKey=" + qualifiedKey + ", value=" + value + + ", indexMetadataField=" + indexMetadataField + ", indexCategory=" + indexCategory + "]"; } - + @Override public int compareTo(CustomField o) { - if(this.indexCategory == o.indexCategory){ - if(this.indexMetadataField == o.indexMetadataField) + if(this.indexCategory == o.indexCategory) { + if(this.indexMetadataField == o.indexMetadataField) { return 0; - else + } else { return this.indexMetadataField > o.indexMetadataField ? 1 : -1; - } - else + } + } else { return this.indexCategory > o.indexCategory ? 1 : -1; + } } } diff --git a/src/main/java/org/gcube/datacatalogue/catalogue/entities/CatalogueItem.java b/src/main/java/org/gcube/datacatalogue/catalogue/entities/CatalogueItem.java new file mode 100644 index 0000000..e5f930b --- /dev/null +++ b/src/main/java/org/gcube/datacatalogue/catalogue/entities/CatalogueItem.java @@ -0,0 +1,73 @@ +package org.gcube.datacatalogue.catalogue.entities; + +import javax.ws.rs.core.MultivaluedMap; + +import org.gcube.datacatalogue.catalogue.utils.CatalogueUtils; +import org.gcube.datacatalogue.catalogue.utils.Constants; +import org.gcube.datacatalogue.catalogue.utils.ContextUtils; +import org.gcube.datacatalogue.catalogue.utils.Delegator; +import org.gcube.datacatalogue.ckanutillibrary.server.DataCatalogue; +import org.gcube.datacatalogue.ckanutillibrary.server.utils.CatalogueUtilMethods; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.trentorise.opendata.jackan.model.CkanDataset; + +public class CatalogueItem { + + private static final Logger logger = LoggerFactory.getLogger(CatalogueItem.class); + + protected String id; + protected JSONObject item; + + public CatalogueItem() {} + + public CatalogueItem(String jsonString) throws ParseException { + JSONParser parser = new JSONParser(); + this.item = (JSONObject) parser.parse(jsonString); + } + + private void applicationChecks(String authorizationErroMessage) throws Exception { + if(ContextUtils.isApplication()) { + logger.debug("Application Token Request"); + DataCatalogue dataCatalogue = CatalogueUtils.getCatalogue(); + CkanDataset dataset = dataCatalogue.getDataset(id, CatalogueUtils.fetchSysAPI()); + + String organization = CatalogueUtilMethods.getCKANOrganization(); + if(organization.equalsIgnoreCase(dataset.getOrganization().getName()) + && ContextUtils.getUsername().equals(dataset.getAuthor())) { + return; + } + throw new Exception(authorizationErroMessage); + } + } + + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String create() { + return null; + } + + public String read() { + return Delegator.delegateGet(Constants.ITEM_SHOW, (MultivaluedMap) null); + } + + public String update() { + return null; + } + + public String delete() { + return null; + } + +} diff --git a/src/main/java/org/gcube/datacatalogue/catalogue/utils/CachesManager.java b/src/main/java/org/gcube/datacatalogue/catalogue/utils/CachesManager.java index 36877c4..7f6bb8a 100644 --- a/src/main/java/org/gcube/datacatalogue/catalogue/utils/CachesManager.java +++ b/src/main/java/org/gcube/datacatalogue/catalogue/utils/CachesManager.java @@ -1,33 +1,66 @@ package org.gcube.datacatalogue.catalogue.utils; -import net.sf.ehcache.Cache; -import net.sf.ehcache.CacheManager; +import javax.cache.Cache; +import javax.cache.CacheManager; +import javax.cache.Caching; +import javax.cache.configuration.MutableConfiguration; +import javax.cache.expiry.CreatedExpiryPolicy; +import javax.cache.expiry.Duration; +import javax.cache.spi.CachingProvider; + +import org.gcube.datacatalogue.metadatadiscovery.DataCalogueMetadataFormatReader; +import org.json.simple.JSONObject; /** * Handle caches via Ehcache stuff. - * @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it) + * @author Costantino Perciante (ISTI - CNR) + * @author Luca Frosini (ISTI - CNR) */ public class CachesManager { - - private static CacheManager cacheManager; - public static final CachesManager singleton = new CachesManager(); - + // the following caches are declared within the ehcache.xml (no default is available, so pay attention) public static final String PROFILES_READERS_CACHE = "profile_readers"; public static final String PROFILES_USERS_CACHE = "profile_users"; - - private CachesManager(){ - cacheManager = CacheManager.newInstance(); + + private static final CacheManager cacheManager; + private static final Cache readerCache; + private static final Cache userCache; + + static { + CachingProvider provider = Caching.getCachingProvider(); + cacheManager = provider.getCacheManager(); + + MutableConfiguration readerConfiguration = + new MutableConfiguration() + .setTypes(String.class, DataCalogueMetadataFormatReader.class) + .setStoreByValue(false) + .setExpiryPolicyFactory(CreatedExpiryPolicy.factoryOf(Duration.ONE_MINUTE)); + readerCache = cacheManager.createCache(PROFILES_READERS_CACHE, readerConfiguration); + + + + MutableConfiguration userConfiguration = + new MutableConfiguration() + .setTypes(String.class, JSONObject.class) + .setStoreByValue(false) + .setExpiryPolicyFactory(CreatedExpiryPolicy.factoryOf(Duration.ONE_MINUTE)); + userCache = cacheManager.createCache(PROFILES_USERS_CACHE, userConfiguration); } - - public static Cache getCache(String name){ - return cacheManager.getCache(name); + + private CachesManager() {} + + public static Cache getReaderCache() { + return readerCache; } - + + public static Cache getUserCache() { + return userCache; + } + @Override protected void finalize() throws Throwable { super.finalize(); - cacheManager.shutdown(); + cacheManager.close(); } - + } diff --git a/src/main/java/org/gcube/datacatalogue/catalogue/utils/CatalogueUtils.java b/src/main/java/org/gcube/datacatalogue/catalogue/utils/CatalogueUtils.java index 0bf99ea..fb9a5d0 100644 --- a/src/main/java/org/gcube/datacatalogue/catalogue/utils/CatalogueUtils.java +++ b/src/main/java/org/gcube/datacatalogue/catalogue/utils/CatalogueUtils.java @@ -4,17 +4,18 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; -import net.sf.ehcache.Cache; -import net.sf.ehcache.Element; +import javax.cache.Cache; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.UriInfo; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.util.EntityUtils; -import org.gcube.common.authorization.library.ClientType; +import org.gcube.common.authorization.library.provider.AuthorizationProvider; +import org.gcube.common.authorization.library.provider.ClientInfo; import org.gcube.common.authorization.library.provider.SecurityTokenProvider; -import org.gcube.common.authorization.library.utils.Caller; import org.gcube.common.scope.api.ScopeProvider; import org.gcube.datacatalogue.ckanutillibrary.server.DataCatalogue; import org.gcube.datacatalogue.ckanutillibrary.server.DataCatalogueFactory; @@ -26,6 +27,7 @@ import org.gcube.datacatalogue.metadatadiscovery.bean.jaxb.MetadataFormat; import org.gcube.datacatalogue.metadatadiscovery.bean.jaxb.NamespaceCategory; import org.json.simple.JSONObject; import org.json.simple.parser.JSONParser; +import org.slf4j.Logger; import org.slf4j.LoggerFactory; import eu.trentorise.opendata.jackan.model.CkanGroup; @@ -33,35 +35,25 @@ import eu.trentorise.opendata.jackan.model.CkanOrganization; /** * Utils methods. - * @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it) + * @author Costantino Perciante (ISTI - CNR) + * @author Luca Frosini (ISTI - CNR) */ @SuppressWarnings("unchecked") public class CatalogueUtils { - - private static final org.slf4j.Logger logger = LoggerFactory.getLogger(CatalogueUtils.class); - + + private static final Logger logger = LoggerFactory.getLogger(CatalogueUtils.class); + /** * Retrieve an instance of the library for the current scope * @return * @throws Exception */ - public static DataCatalogue getCatalogue() throws Exception{ - + public static DataCatalogue getCatalogue() throws Exception { String context = ScopeProvider.instance.get(); - logger.debug("Discovering ckan instance into scope " + context); + logger.debug("Discovering ckan instance in context {}", context); return DataCatalogueFactory.getFactory().getUtilsPerScope(context); } - - /** - * Retrieve an instance of the library for the scope - * @param scope if it is null it is evaluated from the session - * @return - * @throws Exception - */ - public static CkanGroup createGroupAsSysAdmin(String title, String groupName, String description) throws Exception{ - return getCatalogue().createGroup(groupName, title, description); - } - + /** * Get the group hierarchy * @param groupName @@ -69,238 +61,228 @@ public class CatalogueUtils { * @return * @throws Exception */ - public static List getGroupHierarchyNames(String groupName, String username, boolean isApplication) throws Exception{ - + public static List getGroupHierarchyNames(String groupName) throws Exception { List toReturn = new ArrayList(); - String apiKey = isApplication ? fetchSysAPI(ScopeProvider.instance.get()): getCatalogue().getApiKeyFromUsername(username); + String apiKey = CatalogueUtils.getApiKey(); List ckanGroups = getCatalogue().getParentGroups(groupName, apiKey); - if(ckanGroups != null && !ckanGroups.isEmpty()){ - for (CkanGroup ckanGroup : ckanGroups) { + if(ckanGroups != null && !ckanGroups.isEmpty()) { + for(CkanGroup ckanGroup : ckanGroups) { toReturn.add(ckanGroup.getName()); } } - return toReturn; - } - + + private static DataCalogueMetadataFormatReader getDataCalogueMetadataFormatReader() throws Exception { + Cache readerCache = CachesManager.getReaderCache(); + String context = ScopeProvider.instance.get(); + DataCalogueMetadataFormatReader reader; + if(readerCache.containsKey(context)) + reader = (DataCalogueMetadataFormatReader) readerCache.get(context); + else { + reader = new DataCalogueMetadataFormatReader(); + readerCache.put(context, reader); + } + return reader; + } + /** * Returns the names of the metadata profiles in a given context * @param context * @return * @throws Exception */ - public static List getProfilesNames() throws Exception{ - - Cache profilesCache = CachesManager.getCache(CachesManager.PROFILES_READERS_CACHE); - String context = ScopeProvider.instance.get(); + public static List getProfilesNames() throws Exception { + + DataCalogueMetadataFormatReader reader = getDataCalogueMetadataFormatReader(); + List toReturn = new ArrayList(); - - DataCalogueMetadataFormatReader reader; - if(profilesCache.isKeyInCache(context)) - reader = (DataCalogueMetadataFormatReader) profilesCache.get(context).getObjectValue(); - else{ - reader = new DataCalogueMetadataFormatReader(); - profilesCache.put(new Element(context, reader)); - } - List listProfiles = reader.getListOfMetadataProfiles(); - - if(listProfiles != null && !listProfiles.isEmpty()){ - for (MetadataProfile profile : listProfiles) { + + if(listProfiles != null && !listProfiles.isEmpty()) { + for(MetadataProfile profile : listProfiles) { toReturn.add(profile.getName()); } } - + return toReturn; } - + /** * Returns the source xml of the metadata profile (specified via name) in a given context * @param context * @return * @throws Exception */ - public static String getProfileSource(String profileName) throws Exception{ - - Cache profilesCache = CachesManager.getCache(CachesManager.PROFILES_READERS_CACHE); - String context = ScopeProvider.instance.get(); - - DataCalogueMetadataFormatReader reader; - if(profilesCache.isKeyInCache(context)) - reader = (DataCalogueMetadataFormatReader) profilesCache.get(context).getObjectValue(); - else{ - reader = new DataCalogueMetadataFormatReader(); - profilesCache.put(new Element(context, reader)); - } - + public static String getProfileSource(String profileName) throws Exception { + + DataCalogueMetadataFormatReader reader = getDataCalogueMetadataFormatReader(); + List listProfiles = reader.getListOfMetadataProfiles(); String xmlToReturn = null; - - if(listProfiles != null && !listProfiles.isEmpty()){ - for (MetadataProfile profile : listProfiles) { - if(profile.getName().equals(profileName)){ + + if(listProfiles != null && !listProfiles.isEmpty()) { + for(MetadataProfile profile : listProfiles) { + if(profile.getName().equals(profileName)) { xmlToReturn = reader.getMetadataFormatForMetadataProfile(profile).getMetadataSource(); break; } } } - + return xmlToReturn; } - + /** * Returns the categories. * @param context * @return * @throws Exception */ - public static List getNamespaceCategories() throws Exception{ - - Cache profilesCache = CachesManager.getCache(CachesManager.PROFILES_READERS_CACHE); - String context = ScopeProvider.instance.get(); - - DataCalogueMetadataFormatReader reader; - if(profilesCache.isKeyInCache(context)) - reader = (DataCalogueMetadataFormatReader) profilesCache.get(context).getObjectValue(); - else{ - reader = new DataCalogueMetadataFormatReader(); - profilesCache.put(new Element(context, reader)); - } - + public static List getNamespaceCategories() throws Exception { + DataCalogueMetadataFormatReader reader = getDataCalogueMetadataFormatReader(); return reader.getListOfNamespaceCategories(); - + } - + /** * Returns the metadataform of the metadata profile (specified via name) in a given context * @param context * @return * @throws Exception */ - public static MetadataFormat getMetadataProfile(String profileName) throws Exception{ - - Cache profilesCache = CachesManager.getCache(CachesManager.PROFILES_READERS_CACHE); - String context = ScopeProvider.instance.get(); - - DataCalogueMetadataFormatReader reader; - if(profilesCache.isKeyInCache(context)) - reader = (DataCalogueMetadataFormatReader) profilesCache.get(context).getObjectValue(); - else{ - reader = new DataCalogueMetadataFormatReader(); - profilesCache.put(new Element(context, reader)); - } - + public static MetadataFormat getMetadataProfile(String profileName) throws Exception { + + DataCalogueMetadataFormatReader reader = getDataCalogueMetadataFormatReader(); List listProfiles = reader.getListOfMetadataProfiles(); - - if(listProfiles != null && !listProfiles.isEmpty()){ - for (MetadataProfile profile : listProfiles) { - if(profile.getName().equals(profileName)){ + + if(listProfiles != null && !listProfiles.isEmpty()) { + for(MetadataProfile profile : listProfiles) { + if(profile.getName().equals(profileName)) { return reader.getMetadataFormatForMetadataProfile(profile); } } } - + return null; } - + /** * Create a string representing an error message on failure * @param errorMessage * @return */ - public static String createJSONOnFailure(String errorMessage){ + public static String createJSONOnFailure(String errorMessage) { return createJSONObjectMin(false, errorMessage).toJSONString(); } - + /** * JSONObject containing minimum information to be set * @return */ - public static JSONObject createJSONObjectMin(boolean success, String errorMessage){ - + public static JSONObject createJSONObjectMin(boolean success, String errorMessage) { JSONObject obj = new JSONObject(); obj.put(Constants.HELP_KEY, Constants.HELP_URL_GCUBE_CATALOGUE); obj.put(Constants.SUCCESS_KEY, success); - if(errorMessage != null) + if(errorMessage != null) { obj.put(Constants.MESSAGE_ERROR_KEY, errorMessage); + } return obj; - } - + /** * Check if the create-item request can be executed * @param username * @param organization * @throws Exception */ - public static void checkRole(String username, String organization) throws Exception { - - DataCatalogue catalogue = getCatalogue(); - + public static void checkRole(String organization) throws Exception { + DataCatalogue dataCatalogue = getCatalogue(); + // check organization exists - CkanOrganization org = catalogue.getOrganizationByName(organization); - - if(org == null) - throw new Exception("It seems that an organization with name " + organization + " doesn't exist!"); - - Map> rolesPerOrganization = catalogue.getUserRoleByOrganization(username, catalogue.getApiKeyFromUsername(username)); - - if(rolesPerOrganization.get(org.getName()).values().contains(RolesCkanGroupOrOrg.MEMBER)) - throw new Exception("It seems you are neither Catalogue-Admin nor Catalogue-Editor in organization " + organization + "!"); + CkanOrganization org = dataCatalogue.getOrganizationByName(organization); + + if(org == null) { + throw new Exception("It seems that an organization with name " + organization + " doesn't exist!"); + } + + Map> rolesPerOrganization = dataCatalogue + .getUserRoleByOrganization(ContextUtils.getUsername(), + dataCatalogue.getApiKeyFromUsername(ContextUtils.getUsername())); + + if(rolesPerOrganization.get(org.getName()).values().contains(RolesCkanGroupOrOrg.MEMBER)) { + throw new Exception("It seems you are neither Catalogue-Admin nor Catalogue-Editor in organization " + + organization + "!"); + } } - - + /** * Execute the GET http request at this url, and return the result as string * @return * @throws Exception */ - public static JSONObject getUserProfile(String userId) throws Exception{ - - Cache profilesCache = CachesManager.getCache(CachesManager.PROFILES_USERS_CACHE); - - if(profilesCache.isKeyInCache(userId)) - return (JSONObject) profilesCache.get(userId).getObjectValue(); - else{ + public static JSONObject getUserProfile() throws Exception { + + ClientInfo clientInfo = AuthorizationProvider.instance.get().getClient(); + String username = clientInfo.getId(); + + Cache userCache = CachesManager.getUserCache(); + + if(userCache.containsKey(username)) + return userCache.get(username); + else { GcoreEndpointReaderSNL socialService = new GcoreEndpointReaderSNL(); String socialServiceUrl = socialService.getServiceBasePath(); String url = socialServiceUrl + "2/users/get-profile"; - try(CloseableHttpClient client = HttpClientBuilder.create().build();){ + try(CloseableHttpClient client = HttpClientBuilder.create().build();) { HttpGet getRequest = new HttpGet(url + "?gcube-token=" + SecurityTokenProvider.instance.get()); HttpResponse response = client.execute(getRequest); JSONParser parser = new JSONParser(); - JSONObject profile = (JSONObject)parser.parse(EntityUtils.toString(response.getEntity())); - profilesCache.put(new Element(userId, profile)); + JSONObject profile = (JSONObject) parser.parse(EntityUtils.toString(response.getEntity())); + userCache.put(username, profile); return profile; - }catch(Exception e){ + } catch(Exception e) { logger.error("error while performing get method " + e.toString()); throw e; } } } - + /** * Fetch the sysadmin key from the IS * @return * @throws Exception */ - public static String fetchSysAPI(String context) throws Exception{ - - DataCatalogueRunningCluster catalogueRunningInstance = new DataCatalogueRunningCluster(context); + public static String fetchSysAPI() throws Exception { + DataCatalogueRunningCluster catalogueRunningInstance = new DataCatalogueRunningCluster( + ContextUtils.getContext()); return catalogueRunningInstance.getSysAdminToken(); - } - - /** - * Check if the token belongs to an application token - * @param caller - * @return - */ - public static boolean isApplicationToken(Caller caller){ - - return caller.getClient().getType().equals(ClientType.EXTERNALSERVICE); - + + public static String getApiKey() throws Exception { + return ContextUtils.isApplication() ? fetchSysAPI() + : getCatalogue().getApiKeyFromUsername(ContextUtils.getUsername()); } - + + public static String getIdFromUriInfo(String idName, UriInfo uriInfo) throws Exception { + MultivaluedMap queryParams = uriInfo.getQueryParameters(false); + List ids = queryParams.get(idName); + if(ids == null || ids.isEmpty()) { + throw new Exception("'" + idName + "' field is missing!"); + }else if(ids.size()>1) { + throw new Exception("More than one '\" + idName + \"' has been provided!"); + } + return ids.get(0); + } + + public static String getIdFromJSONString(String idName, String jsonString) throws Exception { + JSONParser parser = new JSONParser(); + JSONObject jsonObject = (JSONObject) parser.parse(jsonString); + String id = (String) jsonObject.get(idName); + if(id == null || id.isEmpty()) { + throw new Exception("'" + idName + "' field is missing!"); + } + return id; + } + } diff --git a/src/main/java/org/gcube/datacatalogue/catalogue/utils/Constants.java b/src/main/java/org/gcube/datacatalogue/catalogue/utils/Constants.java index 570c0bc..31721f2 100644 --- a/src/main/java/org/gcube/datacatalogue/catalogue/utils/Constants.java +++ b/src/main/java/org/gcube/datacatalogue/catalogue/utils/Constants.java @@ -2,7 +2,8 @@ package org.gcube.datacatalogue.catalogue.utils; /** * Constants used within this service. - * @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it) + * @author Costantino Perciante (ISTI - CNR) + * @author Luca Frosini (ISTI - CNR) */ public class Constants { diff --git a/src/main/java/org/gcube/datacatalogue/catalogue/utils/ContextUtils.java b/src/main/java/org/gcube/datacatalogue/catalogue/utils/ContextUtils.java new file mode 100644 index 0000000..c2aa568 --- /dev/null +++ b/src/main/java/org/gcube/datacatalogue/catalogue/utils/ContextUtils.java @@ -0,0 +1,39 @@ +package org.gcube.datacatalogue.catalogue.utils; + +import org.gcube.common.authorization.client.exceptions.ObjectNotFound; +import org.gcube.common.authorization.library.ClientType; +import org.gcube.common.authorization.library.provider.AuthorizationProvider; +import org.gcube.common.authorization.library.provider.SecurityTokenProvider; +import org.gcube.common.scope.api.ScopeProvider; + +/** + * @author Luca Frosini (ISTI - CNR) + */ +public class ContextUtils { + + private ContextUtils(){} + + public static String getContext() throws ObjectNotFound, Exception { + String context = ScopeProvider.instance.get(); + if (context == null) { + String token = SecurityTokenProvider.instance.get(); + try { + return org.gcube.common.authorization.client.Constants.authorizationService().get(token).getContext(); + }catch (Exception e) { + new RuntimeException(e); + } + } + return context; + } + + public static String getUsername() { + return AuthorizationProvider.instance.get().getClient().getId(); + + } + + public static boolean isApplication() { + return AuthorizationProvider.instance.get().getClient().getType().equals(ClientType.EXTERNALSERVICE); + } + + +} diff --git a/src/main/java/org/gcube/datacatalogue/catalogue/utils/Delegator.java b/src/main/java/org/gcube/datacatalogue/catalogue/utils/Delegator.java index d621066..9613738 100644 --- a/src/main/java/org/gcube/datacatalogue/catalogue/utils/Delegator.java +++ b/src/main/java/org/gcube/datacatalogue/catalogue/utils/Delegator.java @@ -22,8 +22,6 @@ import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.util.EntityUtils; -import org.gcube.common.authorization.library.utils.Caller; -import org.gcube.common.scope.api.ScopeProvider; import org.gcube.datacatalogue.ckanutillibrary.server.DataCatalogue; import org.glassfish.jersey.media.multipart.FormDataBodyPart; import org.glassfish.jersey.media.multipart.FormDataMultiPart; @@ -32,77 +30,79 @@ import org.json.simple.JSONObject; import org.json.simple.parser.JSONParser; import org.slf4j.LoggerFactory; - /** * As the name says, it just delegates GET/POST operations to CKAN - * @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it) + * @author Costantino Perciante (ISTI - CNR) + * @author Luca Frosini (ISTI - CNR) */ @SuppressWarnings("unchecked") public class Delegator { - + private static final org.slf4j.Logger logger = LoggerFactory.getLogger(Delegator.class); - + + public static String delegateGet(String method, UriInfo uriInfo) { + return delegateGet(method, uriInfo.getQueryParameters(false)); + } + /** - * Execute the get - * @param caller - * @param context * @param method * @param uriInfo * @return - * @throws Exception */ - public static String delegateGet(Caller caller, String context, String method, UriInfo uriInfo, boolean isAppRequest){ - String username = caller.getClient().getId(); - - try(CloseableHttpClient client = HttpClientBuilder.create().build();){ - + public static String delegateGet(String method, MultivaluedMap undecodedParams) { + + try(CloseableHttpClient client = HttpClientBuilder.create().build();) { + DataCatalogue catalogue = CatalogueUtils.getCatalogue(); - String authorization = isAppRequest ? CatalogueUtils.fetchSysAPI(ScopeProvider.instance.get()) : catalogue.getApiKeyFromUsername(username); - String requestPath = catalogue.getCatalogueUrl().endsWith("/") ? catalogue.getCatalogueUrl() : catalogue.getCatalogueUrl() + "/"; + String authorization = CatalogueUtils.getApiKey(); + + String requestPath = catalogue.getCatalogueUrl().endsWith("/") ? catalogue.getCatalogueUrl() + : catalogue.getCatalogueUrl() + "/"; requestPath += method; - MultivaluedMap undecodedParams = uriInfo.getQueryParameters(false); - Iterator>> iterator = undecodedParams.entrySet().iterator(); - - while (iterator.hasNext()) { - Map.Entry> entry = (Map.Entry>) iterator - .next(); - - if(entry.getKey().equals(Constants.GCUBE_TOKEN_PARAMETER)) - continue; - else{ - - List values = entry.getValue(); - for (String value : values) { - requestPath += entry.getKey() + "=" + value + "&"; + + if(undecodedParams !=null) { + Iterator>> iterator = undecodedParams.entrySet().iterator(); + while(iterator.hasNext()) { + Map.Entry> entry = (Map.Entry>) iterator + .next(); + + if(entry.getKey().equals(Constants.GCUBE_TOKEN_PARAMETER)) { + continue; + } else { + List values = entry.getValue(); + for(String value : values) { + requestPath += entry.getKey() + "=" + value + "&"; + } } } } - - if(requestPath.endsWith("&")) - requestPath = requestPath.substring(0, requestPath.length() - 1); + + if(requestPath.endsWith("&")) { + requestPath = requestPath.substring(0, requestPath.length() - 1); + } HttpGet request = new HttpGet(requestPath); - if(authorization != null) + if(authorization != null) { request.addHeader(Constants.AUTH_CKAN_HEADER, authorization); - + } + logger.debug("******* REQUEST URL IS " + requestPath); - + HttpEntity entityRes = client.execute(request).getEntity(); String json = EntityUtils.toString(entityRes); - + // substitute "help" field JSONParser parser = new JSONParser(); JSONObject obj = (JSONObject) parser.parse(json); obj.put(Constants.HELP_KEY, Constants.HELP_URL_GCUBE_CATALOGUE); return obj.toJSONString(); - - }catch(Exception e){ + + } catch(Exception e) { logger.error("Failed to serve the request", e); return CatalogueUtils.createJSONOnFailure("Failed to serve the request: " + e); } - - + } - + /** * Execute the post * @param caller @@ -112,42 +112,40 @@ public class Delegator { * @param uriInfo * @throws Exception */ - public static String delegatePost(Caller caller, String context, - String method, String json, UriInfo uriInfo, boolean isAppRequest){ - - String username = caller.getClient().getId(); - - try(CloseableHttpClient client = HttpClientBuilder.create().build();){ - - DataCatalogue catalogue = CatalogueUtils.getCatalogue(); - - String authorization = isAppRequest ? CatalogueUtils.fetchSysAPI(ScopeProvider.instance.get()) : catalogue.getApiKeyFromUsername(username); - String requestPath = catalogue.getCatalogueUrl().endsWith("/") ? catalogue.getCatalogueUrl() : catalogue.getCatalogueUrl() + "/"; + public static String delegatePost(String method, String json, UriInfo uriInfo) { + try(CloseableHttpClient client = HttpClientBuilder.create().build();) { + + DataCatalogue dataCatalogue = CatalogueUtils.getCatalogue(); + + String authorization = CatalogueUtils.getApiKey(); + String requestPath = dataCatalogue.getCatalogueUrl().endsWith("/") ? dataCatalogue.getCatalogueUrl() + : dataCatalogue.getCatalogueUrl() + "/"; requestPath += method + "?"; - - MultivaluedMap undecodedParams = uriInfo.getQueryParameters(false); - Iterator>> iterator = undecodedParams.entrySet().iterator(); - - while (iterator.hasNext()) { - Map.Entry> entry = (Map.Entry>) iterator - .next(); - + + MultivaluedMap undecodedParams = uriInfo.getQueryParameters(false); + Iterator>> iterator = undecodedParams.entrySet().iterator(); + + while(iterator.hasNext()) { + Map.Entry> entry = + (Map.Entry>) iterator.next(); + if(entry.getKey().equals(Constants.GCUBE_TOKEN_PARAMETER)) continue; - else{ - + else { + List values = entry.getValue(); - for (String value : values) { + for(String value : values) { requestPath += entry.getKey() + "=" + value + "&"; } } } - - if(requestPath.endsWith("&")) - requestPath = requestPath.substring(0, requestPath.length() - 1); - + + if(requestPath.endsWith("&")) { + requestPath = requestPath.substring(0, requestPath.length() - 1); + } + logger.debug("POST request url is going to be " + requestPath); - + HttpPost request = new HttpPost(requestPath); request.addHeader(Constants.AUTH_CKAN_HEADER, authorization); logger.debug("Sending json to CKAN is " + json); @@ -155,105 +153,96 @@ public class Delegator { request.setEntity(params); HttpEntity entityRes = client.execute(request).getEntity(); String jsonRes = EntityUtils.toString(entityRes); - + logger.debug("Result from CKAN is " + jsonRes); - + // substitute "help" field JSONParser parser = new JSONParser(); JSONObject obj = (JSONObject) parser.parse(jsonRes); obj.put(Constants.HELP_KEY, Constants.HELP_URL_GCUBE_CATALOGUE); - + logger.debug("replaced information " + obj); return obj.toJSONString(); - - }catch(Exception e){ + + } catch(Exception e) { logger.error("Failed to serve the request", e); return CatalogueUtils.createJSONOnFailure("Failed to serve the request: " + e); } - - + } - + /** * Execute post with multipart (e.g. for resource upload) - * @param caller - * @param context - * @param resourceCreate + * @param method * @param multiPart * @param uriInfo * @return */ - public static String delegatePost(Caller caller, String context, - String method, FormDataMultiPart multiPart, UriInfo uriInfo, boolean isAppRequest) { - - String username = caller.getClient().getId(); - - try{ + public static String delegatePost(String method, FormDataMultiPart multiPart, UriInfo uriInfo) { + try { DataCatalogue catalogue = CatalogueUtils.getCatalogue(); - String authorization = isAppRequest ? CatalogueUtils.fetchSysAPI(ScopeProvider.instance.get()) : catalogue.getApiKeyFromUsername(username); - String requestPath = catalogue.getCatalogueUrl().endsWith("/") ? catalogue.getCatalogueUrl() : catalogue.getCatalogueUrl() + "/"; + String authorization = CatalogueUtils.getApiKey(); + String requestPath = catalogue.getCatalogueUrl().endsWith("/") ? catalogue.getCatalogueUrl() + : catalogue.getCatalogueUrl() + "/"; requestPath += method + "?"; - - MultivaluedMap undecodedParams = uriInfo.getQueryParameters(false); - Iterator>> iterator = undecodedParams.entrySet().iterator(); - - while (iterator.hasNext()) { - Map.Entry> entry = (Map.Entry>) iterator - .next(); - - if(entry.getKey().equals("Constants.AUTH_CKAN_HEADER")) + + MultivaluedMap undecodedParams = uriInfo.getQueryParameters(false); + Iterator>> iterator = undecodedParams.entrySet().iterator(); + + while(iterator.hasNext()) { + Map.Entry> entry = + (Map.Entry>) iterator.next(); + + if(entry.getKey().equals(Constants.AUTH_CKAN_HEADER)) { continue; - else{ - + }else { List values = entry.getValue(); - for (String value : values) { + for(String value : values) { requestPath += entry.getKey() + "=" + value + "&"; } } } - - if(requestPath.endsWith("&")) - requestPath = requestPath.substring(0, requestPath.length() - 1); - + + if(requestPath.endsWith("&")) { + requestPath = requestPath.substring(0, requestPath.length() - 1); + } + logger.debug("POST request url is going to be " + requestPath); - + // use jersey client logger.debug("Sending multipart to CKAN " + multiPart); - + FormDataBodyPart upload = multiPart.getField("upload"); - if(upload != null){ + if(upload != null) { File file = upload.getValueAs(File.class); long fileLenghtBytes = file.length(); long fileLenghtMegaByte = fileLenghtBytes >> 20; logger.debug("File lenght in MegaByte is " + fileLenghtMegaByte); - + if(fileLenghtMegaByte > Constants.MAX_UPLOADABLE_FILE_SIZE_MB) throw new Exception("Exceeding maximum uploadable file size!"); - - }else + + } else { throw new Exception("No 'upload' field has been provided!"); - + } + Client client = ClientBuilder.newClient(); client.register(MultiPartFeature.class); WebTarget webResource = client.target(requestPath); - JSONObject jsonRes = - webResource - .request(MediaType.APPLICATION_JSON) + JSONObject jsonRes = webResource.request(MediaType.APPLICATION_JSON) .header(Constants.AUTH_CKAN_HEADER, authorization) .post(Entity.entity(multiPart, multiPart.getMediaType()), JSONObject.class); - + logger.debug("Result from CKAN is " + jsonRes); - + // substitute "help" field jsonRes.put(Constants.HELP_KEY, Constants.HELP_URL_GCUBE_CATALOGUE); return jsonRes.toJSONString(); - - }catch(Exception e){ + + } catch(Exception e) { logger.error("Failed to serve the request", e); return CatalogueUtils.createJSONOnFailure("Failed to serve the request: " + e); } } - - - + } diff --git a/src/main/java/org/gcube/datacatalogue/catalogue/utils/GcoreEndpointReaderSNL.java b/src/main/java/org/gcube/datacatalogue/catalogue/utils/GcoreEndpointReaderSNL.java index 8e5a303..fc27b52 100644 --- a/src/main/java/org/gcube/datacatalogue/catalogue/utils/GcoreEndpointReaderSNL.java +++ b/src/main/java/org/gcube/datacatalogue/catalogue/utils/GcoreEndpointReaderSNL.java @@ -1,6 +1,3 @@ -/** - * - */ package org.gcube.datacatalogue.catalogue.utils; import static org.gcube.resources.discovery.icclient.ICFactory.client; @@ -9,7 +6,6 @@ import static org.gcube.resources.discovery.icclient.ICFactory.queryFor; import java.util.List; import org.gcube.common.resources.gcore.GCoreEndpoint; -import org.gcube.common.scope.api.ScopeProvider; import org.gcube.resources.discovery.client.api.DiscoveryClient; import org.gcube.resources.discovery.client.queries.api.SimpleQuery; import org.slf4j.Logger; @@ -17,56 +13,61 @@ import org.slf4j.LoggerFactory; /** * Discover the Social Networking Service in the Infrastructure. - * @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it) + * @author Costantino Perciante (ISTI - CNR) + * @author Luca Frosini (ISTI - CNR) */ public class GcoreEndpointReaderSNL { - + private static final String RESOURCE = "jersey-servlet"; private static final String SERVICE_NAME = "SocialNetworking"; private static final String SERVICE_CLASSE = "Portal"; - + private static Logger logger = LoggerFactory.getLogger(GcoreEndpointReaderSNL.class); private String serviceBasePath; - + /** * Discover the gcore endpoint for the social networking service. - * @param scope the scope * @throws Exception the exception */ public GcoreEndpointReaderSNL() throws Exception { - - String currentScope = ScopeProvider.instance.get(); - - try{ + + try { SimpleQuery query = queryFor(GCoreEndpoint.class); - query.addCondition(String.format("$resource/Profile/ServiceClass/text() eq '%s'",SERVICE_CLASSE)); + query.addCondition(String.format("$resource/Profile/ServiceClass/text() eq '%s'", SERVICE_CLASSE)); query.addCondition("$resource/Profile/DeploymentData/Status/text() eq 'ready'"); - query.addCondition(String.format("$resource/Profile/ServiceName/text() eq '%s'",SERVICE_NAME)); - query.setResult("$resource/Profile/AccessPoint/RunningInstanceInterfaces//Endpoint[@EntryName/string() eq \""+RESOURCE+"\"]/text()"); - + query.addCondition(String.format("$resource/Profile/ServiceName/text() eq '%s'", SERVICE_NAME)); + query.setResult( + "$resource/Profile/AccessPoint/RunningInstanceInterfaces//Endpoint[@EntryName/string() eq \"" + + RESOURCE + "\"]/text()"); + DiscoveryClient client = client(); List endpoints = client.submit(query); - if (endpoints == null || endpoints.isEmpty()) - throw new Exception("Cannot retrieve the GCoreEndpoint SERVICE_NAME: "+SERVICE_NAME +", SERVICE_CLASSE: " +SERVICE_CLASSE +", in scope: "+currentScope); - + if(endpoints == null || endpoints.isEmpty()) { + throw new Exception("Cannot retrieve the GCoreEndpoint SERVICE_NAME: " + SERVICE_NAME + + ", SERVICE_CLASSE: " + SERVICE_CLASSE + ", in scope: " + ContextUtils.getContext()); + } + this.serviceBasePath = endpoints.get(0); - if(serviceBasePath==null) - throw new Exception("Endpoint:"+RESOURCE+", is null for SERVICE_NAME: "+SERVICE_NAME +", SERVICE_CLASSE: " +SERVICE_CLASSE +", in scope: "+currentScope); - + if(serviceBasePath == null) + throw new Exception("Endpoint:" + RESOURCE + ", is null for SERVICE_NAME: " + SERVICE_NAME + + ", SERVICE_CLASSE: " + SERVICE_CLASSE + ", in scope: " + ContextUtils.getContext()); + serviceBasePath = serviceBasePath.endsWith("/") ? serviceBasePath : serviceBasePath + "/"; - }catch(Exception e){ - String error = "An error occurred during GCoreEndpoint discovery, SERVICE_NAME: "+SERVICE_NAME +", SERVICE_CLASSE: " +SERVICE_CLASSE +", in scope: "+currentScope +"."; + } catch(Exception e) { + String error = "An error occurred during GCoreEndpoint discovery, SERVICE_NAME: " + SERVICE_NAME + + ", SERVICE_CLASSE: " + SERVICE_CLASSE + ", in scope: " + ContextUtils.getContext() + "."; logger.error(error, e); throw new Exception(error); } } - + /** * @return the base path of the service */ public String getServiceBasePath() { return serviceBasePath; } + } diff --git a/src/main/java/org/gcube/datacatalogue/catalogue/utils/PackageCreatePostActions.java b/src/main/java/org/gcube/datacatalogue/catalogue/utils/PackageCreatePostActions.java index ddac5db..b2c5787 100644 --- a/src/main/java/org/gcube/datacatalogue/catalogue/utils/PackageCreatePostActions.java +++ b/src/main/java/org/gcube/datacatalogue/catalogue/utils/PackageCreatePostActions.java @@ -6,32 +6,26 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import org.gcube.common.authorization.library.provider.SecurityTokenProvider; -import org.gcube.common.scope.api.ScopeProvider; import org.gcube.datacatalogue.ckanutillibrary.server.DataCatalogue; import org.json.simple.JSONArray; import org.json.simple.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - /** - * Actions to performa after a package has been correctly created on ckan. - * @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it) + * Actions to perform after a package has been correctly created on ckan. + * @author Costantino Perciante (ISTI - CNR) + * @author Luca Frosini (ISTI - CNR) */ public class PackageCreatePostActions extends Thread { - + private String packageId; - private String context; private String datasetUrl; - private String token; - private String username; - private boolean isApplication; private JSONArray tags; private String title; public static final String ITEM_URL = "Item URL"; private static Logger logger = LoggerFactory.getLogger(PackageCreatePostActions.class); - + /** * @param isApplication * @param packageId @@ -39,80 +33,55 @@ public class PackageCreatePostActions extends Thread { * @param tags * @param title */ - public PackageCreatePostActions( - String username, - boolean isApplication, - String datasetUrl, - String packageId, - String context, - String token, - JSONArray tags, - String title) { + public PackageCreatePostActions(String datasetUrl, String packageId, JSONArray tags, String title) { super(); this.packageId = packageId; this.datasetUrl = datasetUrl; - this.isApplication = isApplication; - this.context = context; - this.token = token; - this.username = username; this.tags = tags; this.title = title; } - + @Override public void run() { - - try{ - - ScopeProvider.instance.set(context); - SecurityTokenProvider.instance.set(token); - - DataCatalogue utils = CatalogueUtils.getCatalogue(); - String apiKey = isApplication ? CatalogueUtils.fetchSysAPI(context) : utils.getApiKeyFromUsername(username); - utils.setSearchableField(packageId, true); - + + try { + DataCatalogue dataCatalogue = CatalogueUtils.getCatalogue(); + String apiKey = CatalogueUtils.getApiKey(); + dataCatalogue.setSearchableField(packageId, true); + // add also this information as custom field if(datasetUrl == null) - datasetUrl = utils.getUnencryptedUrlFromDatasetIdOrName(packageId); - Map> addField = new HashMap>(); + datasetUrl = dataCatalogue.getUnencryptedUrlFromDatasetIdOrName(packageId); + Map> addField = new HashMap>(); addField.put(ITEM_URL, Arrays.asList(datasetUrl)); - utils.patchProductCustomFields(packageId, apiKey, addField, false); - - String fullNameUser = null; - if(!isApplication){ - JSONObject profile = CatalogueUtils.getUserProfile(username); - JSONObject profileValues = (JSONObject)profile.get(Constants.RESULT_KEY); - fullNameUser = (String) profileValues.get(Constants.FULLNAME_IN_PROFILE_KEY); - }else{ - fullNameUser = username; + dataCatalogue.patchProductCustomFields(packageId, apiKey, addField, false); + + String userFullName = ContextUtils.getUsername(); + + if(!ContextUtils.isApplication()) { + JSONObject profile = CatalogueUtils.getUserProfile(); + JSONObject profileValues = (JSONObject) profile.get(Constants.RESULT_KEY); + userFullName = (String) profileValues.get(Constants.FULLNAME_IN_PROFILE_KEY); } - + List tagsList = null; - - if(tags != null){ + + if(tags != null) { tagsList = new ArrayList(); - for(int i = 0; i < tags.size(); i++){ - JSONObject obj = (JSONObject)(tags.get(i)); - tagsList.add((String)(obj.get("display_name"))); + for(int i = 0; i < tags.size(); i++) { + JSONObject obj = (JSONObject) (tags.get(i)); + tagsList.add((String) (obj.get("display_name"))); } } - + // write notification post - WritePostCatalogueManagerThread threadWritePost = - new WritePostCatalogueManagerThread( - context, - title, - datasetUrl, - utils.isNotificationToUsersEnabled(), - tagsList, - fullNameUser, - token - ); + WritePostCatalogueManagerThread threadWritePost = new WritePostCatalogueManagerThread(title, datasetUrl, + dataCatalogue.isNotificationToUsersEnabled(), tagsList, userFullName); threadWritePost.start(); - - }catch(Exception e){ + + } catch(Exception e) { logger.error("Error while executing post creation actions", e); } } - + } diff --git a/src/main/java/org/gcube/datacatalogue/catalogue/utils/Validator.java b/src/main/java/org/gcube/datacatalogue/catalogue/utils/Validator.java index ad5deec..f6e3e1f 100644 --- a/src/main/java/org/gcube/datacatalogue/catalogue/utils/Validator.java +++ b/src/main/java/org/gcube/datacatalogue/catalogue/utils/Validator.java @@ -12,7 +12,6 @@ import java.util.Map.Entry; import java.util.Set; import org.apache.commons.lang.math.NumberUtils; -import org.gcube.common.authorization.library.utils.Caller; import org.gcube.common.scope.api.ScopeProvider; import org.gcube.common.scope.impl.ScopeBean; import org.gcube.common.scope.impl.ScopeBean.Type; @@ -27,50 +26,52 @@ import org.gcube.datacatalogue.metadatadiscovery.bean.jaxb.NamespaceCategory; import org.geojson.GeoJsonObject; import org.json.simple.JSONArray; import org.json.simple.JSONObject; +import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.fasterxml.jackson.databind.ObjectMapper; +import eu.trentorise.opendata.jackan.model.CkanGroup; + /** * Validate creation item requests utilities. - * @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it) + * @author Costantino Perciante (ISTI - CNR) + * @author Luca Frosini (ISTI - CNR) */ -@SuppressWarnings({"rawtypes","unchecked"}) +@SuppressWarnings({"rawtypes", "unchecked"}) public class Validator { - - private static final org.slf4j.Logger logger = LoggerFactory.getLogger(Validator.class); + + private static final Logger logger = LoggerFactory.getLogger(Validator.class); + private static final SimpleDateFormat DATE_SIMPLE = new SimpleDateFormat("yyyy-MM-dd"); private static final SimpleDateFormat DATE_HOUR_MINUTES = new SimpleDateFormat("yyyy-MM-dd HH:mm"); - + /** * Check resources have at least url/name * @param json * @param caller * @throws Exception */ - public static void checkResourcesInformation(JSONObject dataset, Caller caller) throws Exception { - - JSONArray resources = (JSONArray)dataset.get(Constants.RESOURCES_KEY); - - if(resources == null || resources.isEmpty()) + public static void checkResourcesInformation(JSONObject dataset) throws Exception { + JSONArray resources = (JSONArray) dataset.get(Constants.RESOURCES_KEY); + if(resources == null || resources.isEmpty()) { return; - else{ - + } else { Iterator it = resources.iterator(); - while (it.hasNext()) { + while(it.hasNext()) { JSONObject resource = (JSONObject) it.next(); - - String name = (String)resource.get(Constants.RESOURCE_NAME_KEY); - String url = (String)resource.get(Constants.RESOURCE_URL_KEY); - - if(url == null || name == null || url.isEmpty() || name.isEmpty()) + + String name = (String) resource.get(Constants.RESOURCE_NAME_KEY); + String url = (String) resource.get(Constants.RESOURCE_URL_KEY); + + if(url == null || name == null || url.isEmpty() || name.isEmpty()) { throw new Exception("Resources must have at least a name and an url field set!"); - + } + } } - } - + /** * This method validates the incoming json, in this sense: *
    @@ -84,53 +85,52 @@ public class Validator { * @return * @throws Exception */ - public static void checkBaseInformation(JSONObject dataset, Caller caller, boolean isAppRequest) throws Exception{ - + public static void checkBaseInformation(JSONObject dataset) throws Exception { // check license - String licenseId = (String)dataset.get(Constants.LICENSE_KEY); - + String licenseId = (String) dataset.get(Constants.LICENSE_KEY); + if(licenseId == null || licenseId.isEmpty()) - throw new Exception("You must specify a license identifier to be attached to the item. License list can be retrieved invoking license methods"); - + throw new Exception( + "You must specify a license identifier to be attached to the item. License list can be retrieved invoking license methods"); + // set author and author email - - if(!isAppRequest){ - JSONObject profile = CatalogueUtils.getUserProfile(caller.getClient().getId()); - JSONObject profileValues = (JSONObject)profile.get(Constants.RESULT_KEY); + if(!ContextUtils.isApplication()) { + JSONObject profile = CatalogueUtils.getUserProfile(); + JSONObject profileValues = (JSONObject) profile.get(Constants.RESULT_KEY); dataset.put(Constants.AUTHOR_KEY, profileValues.get(Constants.FULLNAME_IN_PROFILE_KEY)); dataset.put(Constants.AUTHOR_EMAIL_KEY, profileValues.get(Constants.EMAIL_IN_PROFILE_KEY)); - }else{ - dataset.put(Constants.AUTHOR_KEY, caller.getClient().getId()); + } else { + dataset.put(Constants.AUTHOR_KEY, ContextUtils.getUsername()); dataset.put(Constants.AUTHOR_EMAIL_KEY, CatalogueUtils.getCatalogue().getCatalogueEmail()); } - + // version - String version = (String)dataset.get(Constants.VERSION_KEY); - if(version == null || version.isEmpty()){ + String version = (String) dataset.get(Constants.VERSION_KEY); + if(version == null || version.isEmpty()) { version = "1"; dataset.put(Constants.VERSION_KEY, version); } - + // owner organization must be specified if the token belongs to a VRE - String username = caller.getClient().getId(); ScopeBean scopeBean = new ScopeBean(ScopeProvider.instance.get()); String ownerOrgFromScope = scopeBean.name(); boolean isVREToken = scopeBean.is(Type.VRE); - String ownerOrg = (String)dataset.get(Constants.OWNER_ORG_KEY); - - String organization = isVREToken ? ownerOrgFromScope.toLowerCase().replace(" ", "_").replace("-", "_") : ownerOrg != null ? - ownerOrg.toLowerCase().replace(" ", "_").replace("-", "_") : null; - - if(organization != null){ - if(!isAppRequest) - CatalogueUtils.checkRole(username, organization); - dataset.put(Constants.OWNER_ORG_KEY, organization); - } - else - throw new Exception("You must specify the field 'owner_org' in which the item should be published!"); - + String ownerOrg = (String) dataset.get(Constants.OWNER_ORG_KEY); + + String organization = isVREToken ? ownerOrgFromScope.toLowerCase().replace(" ", "_").replace("-", "_") + : ownerOrg != null ? ownerOrg.toLowerCase().replace(" ", "_").replace("-", "_") : null; + + if(organization != null) { + if(!ContextUtils.isApplication()) { + CatalogueUtils.checkRole(organization); + } + dataset.put(Constants.OWNER_ORG_KEY, organization); + } else { + throw new Exception("You must specify the field '" + Constants.OWNER_ORG_KEY + "' in which the item should be published!"); + } + } - + /** * This method validate the incoming json dataset wrt a metadata profile * @param json @@ -139,167 +139,184 @@ public class Validator { * @return * @throws Exception */ - public static void validateAgainstProfile(JSONObject obj, Caller caller, List profiles, boolean isApplication) throws Exception { - - JSONArray extrasArrayOriginal = (JSONArray)obj.get(Constants.EXTRAS_KEY); - JSONArray groupsArrayOriginal = (JSONArray)obj.get(Constants.GROUPS_KEY); - JSONArray tagsArrayOriginal = (JSONArray)obj.get(Constants.TAGS_KEY); - - if(extrasArrayOriginal == null || extrasArrayOriginal.isEmpty()) + public static void validateAgainstProfile(JSONObject obj, List profiles) throws Exception { + + JSONArray extrasArrayOriginal = (JSONArray) obj.get(Constants.EXTRAS_KEY); + JSONArray groupsArrayOriginal = (JSONArray) obj.get(Constants.GROUPS_KEY); + JSONArray tagsArrayOriginal = (JSONArray) obj.get(Constants.TAGS_KEY); + + if(extrasArrayOriginal == null || extrasArrayOriginal.isEmpty()) { throw new Exception("'extras' field is missing in context where metadata profile(s) are defined!"); - + } + + if(groupsArrayOriginal == null) { + groupsArrayOriginal = new JSONArray(); + } + + if(tagsArrayOriginal == null) { + tagsArrayOriginal = new JSONArray(); + } + // get the metadata profile specifying the type CustomField metadataTypeCF = null; List customFields = new ArrayList(extrasArrayOriginal.size()); Iterator iterator = extrasArrayOriginal.iterator(); - while (iterator.hasNext()) { + while(iterator.hasNext()) { JSONObject object = (JSONObject) iterator.next(); CustomField cf = new CustomField(object); - if(cf.getKey().equals(Constants.TYPE_KEY)) + if(cf.getKey().equals(Constants.TYPE_KEY)) { metadataTypeCF = cf; - else if(cf.getKey().equals(PackageCreatePostActions.ITEM_URL)) + } else if(cf.getKey().equals(PackageCreatePostActions.ITEM_URL)) { continue; - else + } else { customFields.add(cf); + } } - - if(metadataTypeCF == null) - throw new Exception("'" + Constants.TYPE_KEY + "' extra field is missing in context where metadata profile(s) are defined!"); - - if(groupsArrayOriginal == null) - groupsArrayOriginal = new JSONArray(); - - if(tagsArrayOriginal == null) - tagsArrayOriginal = new JSONArray(); - + + if(metadataTypeCF == null) { + throw new Exception("'" + Constants.TYPE_KEY + + "' extra field is missing in context where metadata profile(s) are defined!"); + } + + // fetch the profile by metadata type specified above MetadataFormat profile = null; - for (String profileName : profiles) { - profile = CatalogueUtils.getMetadataProfile(profileName); - if(profile.getType().equals(metadataTypeCF.getValue())) + for(String profileName : profiles) { + profile = CatalogueUtils.getMetadataProfile(profileName); + if(profile.getType().equals(metadataTypeCF.getValue())) { break; - else + } else { profile = null; + } } - - if(profile == null) - throw new Exception("'" + Constants.TYPE_KEY + "' extra field's value specified as custom field doesn't match any of the profiles defined in this context!"); - else{ - + + if(profile == null) { + throw new Exception("'" + Constants.TYPE_KEY + + "' extra field's value ('" + metadataTypeCF.getValue() + + "') specified as custom field doesn't match any of the profiles defined in this context!"); + } else { JSONArray extrasArrayUpdated = null; List metadataFields = profile.getMetadataFields(); - - if(metadataFields == null || metadataFields.isEmpty()) + + if(metadataFields == null || metadataFields.isEmpty()) { extrasArrayUpdated = extrasArrayOriginal; - else{ - + } else { extrasArrayUpdated = new JSONArray(); - List categories = CatalogueUtils.getNamespaceCategories(); - logger.debug("Retrieved namespaces are " + categories); + + List categories = CatalogueUtils.getNamespaceCategories(); + logger.debug("Retrieved namespaces are {}", categories); List categoriesIds = new ArrayList(categories == null ? 0 : categories.size()); - if(categories == null || categories.isEmpty()) - logger.warn("No category defined in context " + ScopeProvider.instance.get()); - else - for (NamespaceCategory metadataCategory : categories) + if(categories == null || categories.isEmpty()) { + logger.warn("No category defined in context {}", ScopeProvider.instance.get()); + } else { + for(NamespaceCategory metadataCategory : categories) { categoriesIds.add(metadataCategory.getId()); // save them later for matching with custom fields - + } + } + // the list of already validated customFields List validatedCustomFields = new ArrayList(customFields.size()); - + // keep track of mandatory fields and their cardinality - Map fieldsMandatoryLowerBoundMap = new HashMap(metadataFields.size()); - Map fieldsMandatoryUpperBoundMap = new HashMap(metadataFields.size()); - Map numberFieldsMandatorySameKeyMap = new HashMap(metadataFields.size()); - + Map fieldsMandatoryLowerBoundMap = new HashMap(metadataFields.size()); + Map fieldsMandatoryUpperBoundMap = new HashMap(metadataFields.size()); + Map numberFieldsMandatorySameKeyMap = new HashMap( + metadataFields.size()); + // keep track of the groups that must be created AFTER validation but BEFORE item creation List groupsToCreateAfterValidation = new ArrayList(); - + // now validate fields int metadataIndex = 0; - for (MetadataField metadataField : metadataFields) { - + for(MetadataField metadataField : metadataFields) { + int categoryIdIndex = categoriesIds.indexOf(metadataField.getCategoryRef()); - logger.debug("Found index for category " + metadataField.getCategoryRef() + " " + categoryIdIndex); - List validCFs = validateAgainstMetadataField( - metadataIndex, - categoryIdIndex, - customFields, - tagsArrayOriginal, - groupsArrayOriginal, - metadataField, - categories, - fieldsMandatoryLowerBoundMap, - fieldsMandatoryUpperBoundMap, - numberFieldsMandatorySameKeyMap, - groupsToCreateAfterValidation, - caller.getClient().getId(), - isApplication); + logger.debug("Found index for category " + metadataField.getCategoryRef() + " " + categoryIdIndex); + List validCFs = validateAgainstMetadataField(metadataIndex, categoryIdIndex, + customFields, tagsArrayOriginal, groupsArrayOriginal, metadataField, categories, + fieldsMandatoryLowerBoundMap, fieldsMandatoryUpperBoundMap, numberFieldsMandatorySameKeyMap, + groupsToCreateAfterValidation); validatedCustomFields.addAll(validCFs); metadataIndex++; - + } - + // check mandatory fields - Iterator> iteratorLowerBounds = fieldsMandatoryLowerBoundMap.entrySet().iterator(); - while (iteratorLowerBounds.hasNext()) { - Map.Entry entry = (Map.Entry) iteratorLowerBounds + Iterator> iteratorLowerBounds = fieldsMandatoryLowerBoundMap.entrySet() + .iterator(); + while(iteratorLowerBounds.hasNext()) { + Map.Entry entry = (Map.Entry) iteratorLowerBounds .next(); int lowerBound = entry.getValue(); int upperBound = fieldsMandatoryUpperBoundMap.get(entry.getKey()); int inserted = numberFieldsMandatorySameKeyMap.get(entry.getKey()); - - logger.info("Field with key '" + entry.getKey() + "' has been found " + inserted + " times and its lower bound is " + lowerBound + " and upper bound " + upperBound); - - if(inserted < lowerBound || inserted > upperBound) - throw new Exception("Field with key '" + entry.getKey() + "' is mandatory, but it's not present among the provided fields or its cardinality is not respected ([min = " + lowerBound + ", max=" + upperBound +"])."); + + logger.info("Field with key '" + entry.getKey() + "' has been found " + inserted + + " times and its lower bound is " + lowerBound + " and upper bound " + upperBound); + + if(inserted < lowerBound || inserted > upperBound) { + throw new Exception("Field with key '" + entry.getKey() + + "' is mandatory, but it's not present among the provided fields or its cardinality is not respected ([min = " + + lowerBound + ", max=" + upperBound + "])."); + } } - + // if there are no tags, throw an exception - if(tagsArrayOriginal.isEmpty()) + if(tagsArrayOriginal.isEmpty()) { throw new Exception("Please define at least one tag for this item!"); - + } + // sort validated custom fields and add to the extrasArrayUpdated json array Collections.sort(validatedCustomFields); - + logger.debug("Sorted list of custom fields is " + validatedCustomFields); - + // add missing fields with no match (append them at the end, since no metadataIndex or categoryIndex was defined for them) for(CustomField cf : customFields) validatedCustomFields.add(cf); - + // convert back to json - for (CustomField customField : validatedCustomFields) { + for(CustomField customField : validatedCustomFields) { JSONObject jsonObj = new JSONObject(); jsonObj.put(Constants.EXTRA_KEY, customField.getQualifiedKey()); jsonObj.put(Constants.EXTRA_VALUE, customField.getValue()); extrasArrayUpdated.add(jsonObj); } - + // add metadata type field as last element JSONObject metadataTypeJSON = new JSONObject(); metadataTypeJSON.put(Constants.EXTRA_KEY, metadataTypeCF.getKey()); metadataTypeJSON.put(Constants.EXTRA_VALUE, metadataTypeCF.getValue()); extrasArrayUpdated.add(metadataTypeJSON); - + // create groups - for (String title : groupsToCreateAfterValidation){ + for(String title : groupsToCreateAfterValidation) { try { - CatalogueUtils.createGroupAsSysAdmin(title, title, ""); - } catch (Exception e) { + createGroupAsSysAdmin(title, title, ""); + } catch(Exception e) { logger.error("Failed to create group with title " + title, e); } } } - + obj.put(Constants.TAGS_KEY, tagsArrayOriginal); obj.put(Constants.GROUPS_KEY, groupsArrayOriginal); obj.put(Constants.EXTRAS_KEY, extrasArrayUpdated); - + } - + } - - + + /** + * Retrieve an instance of the library for the scope + * @param scope if it is null it is evaluated from the session + * @return + * @throws Exception + */ + public static CkanGroup createGroupAsSysAdmin(String title, String groupName, String description) throws Exception { + return CatalogueUtils.getCatalogue().createGroup(groupName, title, description); + } + /** * Validate this field and generate a new value (or returns the same if there is nothing to update) * @param metadataIndex @@ -315,120 +332,109 @@ public class Validator { * @return * @throws Exception */ - private static List validateAgainstMetadataField( - int metadataIndex, - int categoryIndex, - List customFields, - JSONArray tagsArrayOriginal, - JSONArray groupsArrayOriginal, - MetadataField metadataField, - List categories, - Map fieldsMandatoryLowerBoundMap, - Map fieldsMandatoryUpperBoundMap, - Map numberFieldsMandatorySameKeyMap, - List groupToCreate, - String username, boolean isApplication) throws Exception { - + private static List validateAgainstMetadataField(int metadataIndex, int categoryIndex, + List customFields, JSONArray tagsArrayOriginal, JSONArray groupsArrayOriginal, + MetadataField metadataField, List categories, + Map fieldsMandatoryLowerBoundMap, Map fieldsMandatoryUpperBoundMap, + Map numberFieldsMandatorySameKeyMap, List groupToCreate) throws Exception { + List toReturn = new ArrayList(); String metadataFieldName = metadataField.getCategoryFieldQName(); // get the qualified one, if any int fieldsFoundWithThisKey = 0; - + Iterator iterator = customFields.iterator(); - while (iterator.hasNext()) { + while(iterator.hasNext()) { CustomField cf = (CustomField) iterator.next(); - if(cf.getKey().equals(metadataFieldName)){ - + if(cf.getKey().equals(metadataFieldName)) { validate(cf, metadataField); - fieldsFoundWithThisKey ++; + fieldsFoundWithThisKey++; cf.setIndexCategory(categoryIndex); cf.setIndexMetadataField(metadataIndex); - checkAsGroup(cf, metadataField, groupsArrayOriginal, groupToCreate, username, isApplication); + checkAsGroup(cf, metadataField, groupsArrayOriginal, groupToCreate); checkAsTag(cf, metadataField, tagsArrayOriginal); toReturn.add(cf); iterator.remove(); - } } - + // in case of mandatory fields, keep track of the number of times they appear - if(metadataField.getMandatory()){ - + if(metadataField.getMandatory()) { // lower bound int lowerBound = 1; if(fieldsMandatoryLowerBoundMap.containsKey(metadataFieldName)) lowerBound = fieldsMandatoryLowerBoundMap.get(metadataFieldName) + 1; fieldsMandatoryLowerBoundMap.put(metadataFieldName, lowerBound); - + // upper bound boolean hasVocabulary = metadataField.getVocabulary() != null; - int upperBound = hasVocabulary ? - (metadataField.getVocabulary().isMultiSelection() ? metadataField.getVocabulary().getVocabularyFields().size() : 1) : 1; - - if(fieldsMandatoryUpperBoundMap.containsKey(metadataFieldName)) - upperBound += fieldsMandatoryUpperBoundMap.get(metadataFieldName); - - fieldsMandatoryUpperBoundMap.put(metadataFieldName, upperBound); - - // fields with this same key - int countPerFields = fieldsFoundWithThisKey; - if(numberFieldsMandatorySameKeyMap.containsKey(metadataFieldName)) - countPerFields += numberFieldsMandatorySameKeyMap.get(metadataFieldName); - numberFieldsMandatorySameKeyMap.put(metadataFieldName, countPerFields); - + int upperBound = hasVocabulary ? (metadataField.getVocabulary().isMultiSelection() + ? metadataField.getVocabulary().getVocabularyFields().size() + : 1) : 1; + + if(fieldsMandatoryUpperBoundMap.containsKey(metadataFieldName)) + upperBound += fieldsMandatoryUpperBoundMap.get(metadataFieldName); + + fieldsMandatoryUpperBoundMap.put(metadataFieldName, upperBound); + + // fields with this same key + int countPerFields = fieldsFoundWithThisKey; + if(numberFieldsMandatorySameKeyMap.containsKey(metadataFieldName)) + countPerFields += numberFieldsMandatorySameKeyMap.get(metadataFieldName); + numberFieldsMandatorySameKeyMap.put(metadataFieldName, countPerFields); } - + // if there was no field with this key and it was not mandatory, just add an entry of the kind {"key": "key-value", "value" : ""}. // Sometimes it is important to view the field as empty. - if(fieldsFoundWithThisKey == 0 && !metadataField.getMandatory()){ + if(fieldsFoundWithThisKey == 0 && !metadataField.getMandatory()) { toReturn.add(new CustomField(metadataFieldName, "", -1, -1)); } - + return toReturn; - + } - + /** * Check if a tag must be generated * @param fieldToValidate * @param metadataField * @param tagsArrayOriginal */ - private static void checkAsTag(CustomField fieldToValidate, - MetadataField metadataField, JSONArray tagsArrayOriginal) { + private static void checkAsTag(CustomField fieldToValidate, MetadataField metadataField, + JSONArray tagsArrayOriginal) { MetadataTagging tagging = metadataField.getTagging(); - if(tagging != null){ - + if(tagging != null) { + String tag = ""; - - switch(tagging.getTaggingValue()){ - case onFieldName: - tag = metadataField.getFieldName(); - break; - case onValue: - tag = fieldToValidate.getValue(); - break; - case onFieldName_onValue: - tag = metadataField.getFieldName() + tagging.getSeparator() + fieldToValidate.getValue(); - break; - case onValue_onFieldName: - tag = fieldToValidate.getValue() + tagging.getSeparator() + metadataField.getFieldName(); - break; - default: - return; + + switch(tagging.getTaggingValue()) { + case onFieldName: + tag = metadataField.getFieldName(); + break; + case onValue: + tag = fieldToValidate.getValue(); + break; + case onFieldName_onValue: + tag = metadataField.getFieldName() + tagging.getSeparator() + fieldToValidate.getValue(); + break; + case onValue_onFieldName: + tag = fieldToValidate.getValue() + tagging.getSeparator() + metadataField.getFieldName(); + break; + default: + return; } - + tag = tag.substring(0, Constants.MAX_TAG_CHARS > tag.length() ? tag.length() : Constants.MAX_TAG_CHARS); logger.debug("Tag is " + tag); - + JSONObject tagJSON = new JSONObject(); tagJSON.put("name", tag); tagJSON.put("display_name", tag); tagsArrayOriginal.add(tagJSON); - + } - + } - + /** * Check if a group must be generated * @param fieldToValidate @@ -437,44 +443,45 @@ public class Validator { * @param isApplication * @throws Exception */ - private static void checkAsGroup(CustomField fieldToValidate, - MetadataField metadataField, JSONArray groupsArrayOriginal, List groupToCreate, String username, boolean isApplication) throws Exception { - + private static void checkAsGroup(CustomField fieldToValidate, MetadataField metadataField, + JSONArray groupsArrayOriginal, List groupToCreate) throws Exception { + logger.debug("Custom field is " + fieldToValidate); logger.debug("MetadataField field is " + metadataField); logger.debug("JSONArray field is " + groupsArrayOriginal); - + MetadataGrouping grouping = metadataField.getGrouping(); - if(grouping != null){ - + if(grouping != null) { + boolean propagateUp = grouping.getPropagateUp(); final Set groupNames = new HashSet(); - - switch(grouping.getGroupingValue()){ - case onFieldName: - groupNames.add(metadataField.getFieldName()); - break; - case onValue: - if(fieldToValidate.getValue() != null && !fieldToValidate.getValue().isEmpty()) - groupNames.add(fieldToValidate.getValue()); - break; - case onFieldName_onValue: - case onValue_onFieldName: - groupNames.add(metadataField.getFieldName()); - if(fieldToValidate.getValue() != null && !fieldToValidate.getValue().isEmpty()) - groupNames.add(fieldToValidate.getValue()); - break; - default: - return; + + switch(grouping.getGroupingValue()) { + case onFieldName: + groupNames.add(metadataField.getFieldName()); + break; + case onValue: + if(fieldToValidate.getValue() != null && !fieldToValidate.getValue().isEmpty()) + groupNames.add(fieldToValidate.getValue()); + break; + case onFieldName_onValue: + case onValue_onFieldName: + groupNames.add(metadataField.getFieldName()); + if(fieldToValidate.getValue() != null && !fieldToValidate.getValue().isEmpty()) + groupNames.add(fieldToValidate.getValue()); + break; + default: + return; } - - for (String title : groupNames) { + + for(String title : groupNames) { logger.debug("Adding group to which add this item " + CatalogueUtilMethods.fromGroupTitleToName(title)); JSONObject group = new JSONObject(); group.put("name", CatalogueUtilMethods.fromGroupTitleToName(title)); - if(propagateUp){ - List parents = CatalogueUtils.getGroupHierarchyNames(CatalogueUtilMethods.fromGroupTitleToName(title), username, isApplication); - for (String parent : parents) { + if(propagateUp) { + List parents = CatalogueUtils + .getGroupHierarchyNames(CatalogueUtilMethods.fromGroupTitleToName(title)); + for(String parent : parents) { JSONObject groupP = new JSONObject(); groupP.put("name", parent); groupsArrayOriginal.add(groupP); @@ -482,16 +489,16 @@ public class Validator { } groupsArrayOriginal.add(group); } - + // force group creation if needed - if(grouping.getCreate()){ - for (String title : groupNames) + if(grouping.getCreate()) { + for(String title : groupNames) groupToCreate.add(title); } } - + } - + /** * Validate the single field * @param fieldToValidate @@ -500,118 +507,121 @@ public class Validator { * @return * @throws Exception */ - private static void validate(CustomField fieldToValidate, - MetadataField metadataField) throws Exception { - + private static void validate(CustomField fieldToValidate, MetadataField metadataField) throws Exception { + DataType dataType = metadataField.getDataType(); - String regex = metadataField.getValidator() != null ? metadataField.getValidator().getRegularExpression() : null; + String regex = metadataField.getValidator() != null ? metadataField.getValidator().getRegularExpression() + : null; boolean hasControlledVocabulary = metadataField.getVocabulary() != null; String value = fieldToValidate.getValue(); String key = fieldToValidate.getKey(); String defaultValue = metadataField.getDefaultValue(); - + // replace key by prepending the qualified name of the category, if needed fieldToValidate.setQualifiedKey(metadataField.getCategoryFieldQName()); - + if((value == null || value.isEmpty())) if(metadataField.getMandatory() || hasControlledVocabulary) - throw new Exception("Mandatory field with name '" + key + "' doesn't have a value but it is mandatory or has a controlled vocabulary!"); + throw new Exception("Mandatory field with name '" + key + + "' doesn't have a value but it is mandatory or has a controlled vocabulary!"); else { - if(defaultValue != null && !defaultValue.isEmpty()){ + if(defaultValue != null && !defaultValue.isEmpty()) { value = defaultValue; fieldToValidate.setValue(defaultValue); } return; // there is no need to check other stuff } - - switch(dataType){ - - case String: - case Text: - - if(regex != null && !value.matches(regex)) - throw new Exception("Field with key '" + key + "' doesn't match the provided regular expression (" + regex + ")!"); - - if(hasControlledVocabulary){ - - List valuesVocabulary = metadataField.getVocabulary().getVocabularyFields(); - - if(valuesVocabulary == null || valuesVocabulary.isEmpty()) - return; - - boolean match = false; - for (String valueVocabulary : valuesVocabulary) { - match = value.equals(valueVocabulary); - if(match) - break; + + switch(dataType) { + + case String: + case Text: + + if(regex != null && !value.matches(regex)) + throw new Exception("Field with key '" + key + "' doesn't match the provided regular expression (" + + regex + ")!"); + + if(hasControlledVocabulary) { + + List valuesVocabulary = metadataField.getVocabulary().getVocabularyFields(); + + if(valuesVocabulary == null || valuesVocabulary.isEmpty()) + return; + + boolean match = false; + for(String valueVocabulary : valuesVocabulary) { + match = value.equals(valueVocabulary); + if(match) + break; + } + + if(!match) + throw new Exception("Field with key '" + key + "' has a value '" + value + + "' but it doesn't match any of the vocabulary's values (" + valuesVocabulary + ")!"); + } - - if(!match) - throw new Exception("Field with key '" + key + "' has a value '" + value + "' but it doesn't match any of the vocabulary's values ("+valuesVocabulary+")!"); - - } - - break; - case Time: - - if(!isValidDate(value)) - throw new Exception("Field with key '" + key + "' doesn't seem a valid time!"); - - break; - case Time_Interval: - - String[] timeValues = value.split("/"); - for (int i = 0; i < timeValues.length; i++) { - String time = timeValues[i]; - if(!isValidDate(time)) - throw new Exception("Field with key '" + key + "' doesn't seem a valid time interval!"); - } - - break; - case Times_ListOf: - - String[] timeIntervals = value.split(","); - for (int i = 0; i < timeIntervals.length; i++) { - String[] timeIntervalValues = timeIntervals[i].split("/"); - if(timeIntervalValues.length > 2) - throw new Exception("Field with key '" + key + "' doesn't seem a valid list of times!"); - for (i = 0; i < timeIntervalValues.length; i++) { - String time = timeIntervalValues[i]; + + break; + case Time: + + if(!isValidDate(value)) + throw new Exception("Field with key '" + key + "' doesn't seem a valid time!"); + + break; + case Time_Interval: + + String[] timeValues = value.split("/"); + for(int i = 0; i < timeValues.length; i++) { + String time = timeValues[i]; if(!isValidDate(time)) - throw new Exception("Field with key '" + key + "' doesn't seem a valid list of times!"); + throw new Exception("Field with key '" + key + "' doesn't seem a valid time interval!"); } - } - - break; - case Boolean: - - if (value.equalsIgnoreCase("true") || value.equalsIgnoreCase("false")) { - - }else - throw new Exception("Field with key '" + key + "' doesn't seem a valid boolean value!"); - - break; - case Number: - - if(!NumberUtils.isNumber(value)) - throw new Exception("Field's value with key '" + key + "' is not a valid number!"); - - break; - case GeoJSON: - - try{ - new ObjectMapper().readValue(fieldToValidate.getValue(), GeoJsonObject.class); - }catch(Exception e){ - throw new Exception("GeoJSON field with key '" + key + "' seems not valid!"); - } - - break; - default: - break; + + break; + case Times_ListOf: + + String[] timeIntervals = value.split(","); + for(int i = 0; i < timeIntervals.length; i++) { + String[] timeIntervalValues = timeIntervals[i].split("/"); + if(timeIntervalValues.length > 2) + throw new Exception("Field with key '" + key + "' doesn't seem a valid list of times!"); + for(i = 0; i < timeIntervalValues.length; i++) { + String time = timeIntervalValues[i]; + if(!isValidDate(time)) + throw new Exception("Field with key '" + key + "' doesn't seem a valid list of times!"); + } + } + + break; + case Boolean: + + if(value.equalsIgnoreCase("true") || value.equalsIgnoreCase("false")) { + + } else + throw new Exception("Field with key '" + key + "' doesn't seem a valid boolean value!"); + + break; + case Number: + + if(!NumberUtils.isNumber(value)) + throw new Exception("Field's value with key '" + key + "' is not a valid number!"); + + break; + case GeoJSON: + + try { + new ObjectMapper().readValue(fieldToValidate.getValue(), GeoJsonObject.class); + } catch(Exception e) { + throw new Exception("GeoJSON field with key '" + key + "' seems not valid!"); + } + + break; + default: + break; } - + } - + /** * Validate a time date against a formatter * @param value @@ -619,22 +629,21 @@ public class Validator { * @return */ private static boolean isValidDate(String value) { - - try{ + + try { DATE_HOUR_MINUTES.parse(value); return true; - }catch(Exception e){ + } catch(Exception e) { logger.debug("failed to parse date with hours and minutes, trying the other one"); - try{ + try { DATE_SIMPLE.parse(value); return true; - }catch(Exception e2){ + } catch(Exception e2) { logger.warn("failed to parse date with simple format, returning false"); return false; } } - + } - - + } diff --git a/src/main/java/org/gcube/datacatalogue/catalogue/utils/WritePostCatalogueManagerThread.java b/src/main/java/org/gcube/datacatalogue/catalogue/utils/WritePostCatalogueManagerThread.java index a260694..4531a48 100644 --- a/src/main/java/org/gcube/datacatalogue/catalogue/utils/WritePostCatalogueManagerThread.java +++ b/src/main/java/org/gcube/datacatalogue/catalogue/utils/WritePostCatalogueManagerThread.java @@ -20,80 +20,63 @@ import org.json.simple.parser.JSONParser; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - /** * Let the Product Catalogue Manager write a post in a VRE and alert there is a new product. - * @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it) + * @author Costantino Perciante (ISTI - CNR) + * @author Luca Frosini (ISTI - CNR) */ public class WritePostCatalogueManagerThread extends Thread { - - private static final String APPLICATION_ID_CATALOGUE_MANAGER = "org.gcube.datacatalogue.ProductCatalogue"; + + private static Logger logger = LoggerFactory.getLogger(WritePostCatalogueManagerThread.class); + + private static final String APPLICATION_ID_CATALOGUE_MANAGER = "org.gcube.datacatalogue.ProductCatalogue"; private static final String NOTIFICATION_MESSAGE = "Dear members,
    The item '$PRODUCT_TITLE' has been just published by $USER_FULLNAME.
    You can find it here: $PRODUCT_URL
    "; private static final String SOCIAL_SERVICE_APPLICATION_TOKEN = "/2/tokens/generate-application-token"; private static final String SOCIAL_SERVICE_WRITE_APPLICATION_POST = "/2/posts/write-post-app"; private static final String MEDIATYPE_JSON = "application/json"; - private static Logger logger = LoggerFactory.getLogger(WritePostCatalogueManagerThread.class); - private String scope; - private String productTitle; + + private String productName; private String productUrl; private boolean enableNotification; private List hashtags; private String userFullName; - private String token; - + /** - * @param token - * @param scope * @param productTitle * @param productUrl * @param enableNotification * @param hashtags * @param userFullName */ - public WritePostCatalogueManagerThread( - String scope, - String productTitle, String productUrl, boolean enableNotification, - List hashtags, String userFullName, String token) { + public WritePostCatalogueManagerThread(String productName, String productUrl, boolean enableNotification, + List hashtags, String userFullName) { super(); - this.scope = scope; - this.productTitle = productTitle; + this.productName = productName; this.productUrl = productUrl; this.enableNotification = enableNotification; this.hashtags = hashtags; this.userFullName = userFullName; - this.token = token; } - + @Override public void run() { - - try{ - - // set token and scope - ScopeProvider.instance.set(scope); - SecurityTokenProvider.instance.set(token); - - logger.info("Started request to write application post " - + "for new product created. Scope is " + scope + " and " - + "token is " + token.substring(0, 10) + "****************"); - + + try { + logger.info( + "Started request to write application post for new product created. Scope is {} and token is {}****************", + ScopeProvider.instance.get(), SecurityTokenProvider.instance.get().substring(0, 10)); + // write - writeProductPost( - productTitle, - productUrl, - userFullName, - hashtags, - enableNotification - ); - - }catch(Exception e){ + writeProductPost(); + + } catch(Exception e) { logger.error("Failed to write the post because of the following error ", e); - }finally{ + } finally { SecurityTokenProvider.instance.reset(); ScopeProvider.instance.reset(); } } - + /** * Send notification to vre members about the created product by writing a post. * @param productName the title of the product @@ -101,40 +84,41 @@ public class WritePostCatalogueManagerThread extends Thread { * @param hashtags a list of product's hashtags * @throws Exception */ - private static void writeProductPost(String productName, String productUrl, String userFullname, List hashtags, boolean enablePostNotification) throws Exception{ - + private void writeProductPost() throws Exception { + // discover service endpoint for the social networking library String currentScope = ScopeProvider.instance.get(); String tokenUser = SecurityTokenProvider.instance.get(); - - logger.info("Current scope for writeProductPost is " + currentScope + " and token is " + tokenUser.substring(0, 10) + "***************"); + + logger.debug("Current scope for writeProductPost is " + currentScope + " and token is " + + tokenUser.substring(0, 10) + "***************"); + GcoreEndpointReaderSNL socialService = new GcoreEndpointReaderSNL(); String basePath = socialService.getServiceBasePath(); - - if(basePath == null){ - + + if(basePath == null) { logger.error("Unable to write a post because there is no social networking service available"); - - }else{ - + } else { // check base path form basePath = basePath.endsWith("/") ? basePath : basePath + "/"; - - try(CloseableHttpClient client = HttpClientBuilder.create().build();){ - - String pathTokenApp = basePath + SOCIAL_SERVICE_APPLICATION_TOKEN + "?" + Constants.GCUBE_TOKEN_PARAMETER + "=" + tokenUser; + + try(CloseableHttpClient client = HttpClientBuilder.create().build();) { + String pathTokenApp = basePath + SOCIAL_SERVICE_APPLICATION_TOKEN + "?" + + Constants.GCUBE_TOKEN_PARAMETER + "=" + tokenUser; String tokenApp = requireAppToken(client, pathTokenApp); - if(tokenApp != null){ - String pathWritePost = basePath + SOCIAL_SERVICE_WRITE_APPLICATION_POST + "?gcube-token=" + tokenApp; - writePost(client, pathWritePost, productName, productUrl, userFullname, hashtags, enablePostNotification); + if(tokenApp != null) { + String pathWritePost = basePath + SOCIAL_SERVICE_WRITE_APPLICATION_POST + "?gcube-token=" + + tokenApp; + writePost(client, pathWritePost, productName, productUrl, userFullName, hashtags, + enableNotification); } - - }catch(Exception e){ + + } catch(Exception e) { logger.error("Failed to create a post", e); } } } - + /** * Require the application token * @param tokenUser @@ -142,46 +126,48 @@ public class WritePostCatalogueManagerThread extends Thread { * @param client * @return */ - private static String requireAppToken(CloseableHttpClient client, String path){ - + private static String requireAppToken(CloseableHttpClient client, String path) { + String token = null; - try{ - - HttpResponse response = performRequest(client, path, "{\"app_id\":\"" + APPLICATION_ID_CATALOGUE_MANAGER + "\"}"); - + try { + + HttpResponse response = performRequest(client, path, + "{\"app_id\":\"" + APPLICATION_ID_CATALOGUE_MANAGER + "\"}"); + int statusTokenGenerate = response.getStatusLine().getStatusCode(); - - if(statusTokenGenerate == HttpURLConnection.HTTP_CREATED){ - + + if(statusTokenGenerate == HttpURLConnection.HTTP_CREATED) { + // extract token JSONObject obj = getJSONObject(response); if(((Boolean) obj.get("success"))) - token = (String)obj.get("result"); + token = (String) obj.get("result"); else return null; - - }else if(statusTokenGenerate == HttpURLConnection.HTTP_MOVED_TEMP + + } else if(statusTokenGenerate == HttpURLConnection.HTTP_MOVED_TEMP || statusTokenGenerate == HttpURLConnection.HTTP_MOVED_PERM - || statusTokenGenerate == HttpURLConnection.HTTP_SEE_OTHER){ - + || statusTokenGenerate == HttpURLConnection.HTTP_SEE_OTHER) { + // re-execute Header[] locations = response.getHeaders("Location"); Header lastLocation = locations[locations.length - 1]; String realLocation = lastLocation.getValue(); logger.debug("New location is " + realLocation); token = requireAppToken(client, realLocation); - - }else + + } else return null; - - }catch(Exception e){ + + } catch(Exception e) { logger.error("Failed to retrieve application token", e); } - - logger.info("Returning app token " + (token != null ? token.substring(0, 10) + "*************************" : null)); + + logger.info( + "Returning app token " + (token != null ? token.substring(0, 10) + "*************************" : null)); return token; } - + /** * Write post request * @param client @@ -192,95 +178,96 @@ public class WritePostCatalogueManagerThread extends Thread { * @param hashtags */ @SuppressWarnings("unchecked") - private static void writePost(CloseableHttpClient client, String path, String productName, String productUrl, String userFullname, List hashtags, - boolean enablePostNotification) { - - try{ - + private static void writePost(CloseableHttpClient client, String path, String productName, String productUrl, + String userFullname, List hashtags, boolean enablePostNotification) { + + try { + // replace - String message = NOTIFICATION_MESSAGE.replace("$PRODUCT_TITLE", productName).replace("$PRODUCT_URL", productUrl).replace("$USER_FULLNAME", userFullname); - + String message = NOTIFICATION_MESSAGE.replace("$PRODUCT_TITLE", productName) + .replace("$PRODUCT_URL", productUrl).replace("$USER_FULLNAME", userFullname); + if(hashtags != null && !hashtags.isEmpty()) - for (String hashtag : hashtags) { + for(String hashtag : hashtags) { String modifiedHashtag = hashtag.replaceAll(" ", "_").replace("_+", "_"); if(modifiedHashtag.endsWith("_")) modifiedHashtag = modifiedHashtag.substring(0, modifiedHashtag.length() - 1); message += " #" + modifiedHashtag; // ckan accepts tag with empty spaces, we don't } - + logger.info("The post that is going to be written is -> " + message); - + JSONObject objRequest = new JSONObject(); objRequest.put("text", message); objRequest.put("enable_notification", enablePostNotification); - HttpResponse response = performRequest(client, path, objRequest.toJSONString()); + HttpResponse response = performRequest(client, path, objRequest.toJSONString()); int statusWritePost = response.getStatusLine().getStatusCode(); - - if(statusWritePost == HttpURLConnection.HTTP_CREATED){ - + + if(statusWritePost == HttpURLConnection.HTTP_CREATED) { + // extract token JSONObject obj = getJSONObject(response); if(((Boolean) obj.get("success"))) logger.info("Post written"); else logger.info("Failed to write the post " + obj.get("message")); - - }else if(statusWritePost == HttpURLConnection.HTTP_MOVED_TEMP + + } else if(statusWritePost == HttpURLConnection.HTTP_MOVED_TEMP || statusWritePost == HttpURLConnection.HTTP_MOVED_PERM - || statusWritePost == HttpURLConnection.HTTP_SEE_OTHER){ - + || statusWritePost == HttpURLConnection.HTTP_SEE_OTHER) { + // re-execute Header[] locations = response.getHeaders("Location"); Header lastLocation = locations[locations.length - 1]; String realLocation = lastLocation.getValue(); logger.debug("New location is " + realLocation); - writePost(client, realLocation, productName, productUrl, userFullname, hashtags, enablePostNotification); - - }else + writePost(client, realLocation, productName, productUrl, userFullname, hashtags, + enablePostNotification); + + } else throw new RuntimeException("Failed to write the post"); - - }catch(Exception e){ + + } catch(Exception e) { logger.error("Failed to retrieve application token", e); } - + } - + /** * Convert the json response to a map * @param response * @return */ - private static JSONObject getJSONObject(HttpResponse response){ - + private static JSONObject getJSONObject(HttpResponse response) { + JSONObject toReturn = null; HttpEntity entity = response.getEntity(); - - if (entity != null) { + + if(entity != null) { try { JSONParser parser = new JSONParser(); - return (JSONObject)parser.parse(EntityUtils.toString(response.getEntity())); - }catch(Exception e){ + return (JSONObject) parser.parse(EntityUtils.toString(response.getEntity())); + } catch(Exception e) { logger.error("Failed to read json object", e); } } - + logger.trace("Returning " + toReturn); return toReturn; } - + /** * Perform an http request post request with json entity * @throws IOException * @throws ClientProtocolException */ - private static HttpResponse performRequest(CloseableHttpClient client, String path, String entity) throws ClientProtocolException, IOException{ - + private static HttpResponse performRequest(CloseableHttpClient client, String path, String entity) + throws ClientProtocolException, IOException { HttpPost request = new HttpPost(path); StringEntity stringEntity = new StringEntity(entity); stringEntity.setContentType(MEDIATYPE_JSON); request.setEntity(stringEntity); return client.execute(request); - } - + } \ No newline at end of file diff --git a/src/main/java/org/gcube/datacatalogue/catalogue/ws/Group.java b/src/main/java/org/gcube/datacatalogue/catalogue/ws/Group.java index bf3bf9f..473cd71 100644 --- a/src/main/java/org/gcube/datacatalogue/catalogue/ws/Group.java +++ b/src/main/java/org/gcube/datacatalogue/catalogue/ws/Group.java @@ -10,110 +10,77 @@ import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.UriInfo; -import org.gcube.common.authorization.library.provider.AuthorizationProvider; -import org.gcube.common.authorization.library.utils.Caller; -import org.gcube.common.scope.api.ScopeProvider; -import org.gcube.datacatalogue.catalogue.utils.CatalogueUtils; import org.gcube.datacatalogue.catalogue.utils.Constants; import org.gcube.datacatalogue.catalogue.utils.Delegator; - @Path(Constants.GROUPS) /** * Groups service endpoint. - * @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it) + * All checks are demanded to CKAN + * @author Costantino Perciante (ISTI - CNR) + * @author Luca Frosini (ISTI - CNR) */ public class Group { - + @GET @Path(Constants.SHOW_METHOD) @Produces(MediaType.APPLICATION_JSON) - public String show(@Context UriInfo uriInfo){ - + public String show(@Context UriInfo uriInfo) { // see http://docs.ckan.org/en/latest/api/#ckan.logic.action.get.group_show - Caller caller = AuthorizationProvider.instance.get(); - String context = ScopeProvider.instance.get(); - boolean isApplication = CatalogueUtils.isApplicationToken(caller); - return Delegator.delegateGet(caller, context, Constants.GROUP_SHOW, uriInfo, isApplication); - + return Delegator.delegateGet(Constants.GROUP_SHOW, uriInfo); } @GET @Path(Constants.LIST_METHOD) @Produces(MediaType.APPLICATION_JSON) - public String list(@Context UriInfo uriInfo){ - + public String list(@Context UriInfo uriInfo) { // see http://docs.ckan.org/en/latest/api/#ckan.logic.action.get.group_list - Caller caller = AuthorizationProvider.instance.get(); - String context = ScopeProvider.instance.get(); - boolean isApplication = CatalogueUtils.isApplicationToken(caller); - return Delegator.delegateGet(caller, context, Constants.GROUP_LIST, uriInfo, isApplication); - + return Delegator.delegateGet(Constants.GROUP_LIST, uriInfo); } - + @POST @Path(Constants.CREATE_METHOD) @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - public String create(String json, @Context UriInfo uriInfo){ - - // see http://docs.ckan.org/en/latest/api/#ckan.logic.action.get.group_create - Caller caller = AuthorizationProvider.instance.get(); - String context = ScopeProvider.instance.get(); - return Delegator.delegatePost(caller, context, Constants.GROUP_CREATE, json, uriInfo, false); - + public String create(String json, @Context UriInfo uriInfo) { + // see http://docs.ckan.org/en/latest/api/#ckan.logic.action.create.group_create + return Delegator.delegatePost(Constants.GROUP_CREATE, json, uriInfo); } - + @DELETE @Path(Constants.DELETE_METHOD) @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - public String delete(String json, @Context UriInfo uriInfo){ - - // see http://docs.ckan.org/en/latest/api/#ckan.logic.action.get.group_delete - Caller caller = AuthorizationProvider.instance.get(); - String context = ScopeProvider.instance.get(); - return Delegator.delegatePost(caller, context, Constants.GROUP_DELETE, json, uriInfo, false); - + public String delete(String json, @Context UriInfo uriInfo) { + // see http://docs.ckan.org/en/latest/api/#ckan.logic.action.delete.group_delete + return Delegator.delegatePost(Constants.GROUP_DELETE, json, uriInfo); } - + @DELETE @Path(Constants.PURGE_METHOD) @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - public String purge(String json, @Context UriInfo uriInfo){ - - // see http://docs.ckan.org/en/latest/api/#ckan.logic.action.get.group_purge - Caller caller = AuthorizationProvider.instance.get(); - String context = ScopeProvider.instance.get(); - return Delegator.delegatePost(caller, context, Constants.GROUP_PURGE, json, uriInfo, false); - + public String purge(String json, @Context UriInfo uriInfo) { + // see http://docs.ckan.org/en/latest/api/#ckan.logic.action.delete.group_purge + return Delegator.delegatePost(Constants.GROUP_PURGE, json, uriInfo); } - + @POST @Path(Constants.UPDATE_METHOD) @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - public String update(String json, @Context UriInfo uriInfo){ - - // see http://docs.ckan.org/en/latest/api/#ckan.logic.action.get.group_update - Caller caller = AuthorizationProvider.instance.get(); - String context = ScopeProvider.instance.get(); - return Delegator.delegatePost(caller, context, Constants.GROUP_UPDATE, json, uriInfo, false); - + public String update(String json, @Context UriInfo uriInfo) { + // see http://docs.ckan.org/en/latest/api/#ckan.logic.action.update.group_update + return Delegator.delegatePost(Constants.GROUP_UPDATE, json, uriInfo); } - + @POST @Path(Constants.PATCH_METHOD) @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - public String patch(String json, @Context UriInfo uriInfo){ - - // see http://docs.ckan.org/en/latest/api/#ckan.logic.action.get.group_patch - Caller caller = AuthorizationProvider.instance.get(); - String context = ScopeProvider.instance.get(); - return Delegator.delegatePost(caller, context, Constants.GROUP_PATCH, json, uriInfo, false); - + public String patch(String json, @Context UriInfo uriInfo) { + // see http://docs.ckan.org/en/latest/api/#ckan.logic.action.patch.group_patch + return Delegator.delegatePost(Constants.GROUP_PATCH, json, uriInfo); } - + } diff --git a/src/main/java/org/gcube/datacatalogue/catalogue/ws/Item.java b/src/main/java/org/gcube/datacatalogue/catalogue/ws/Item.java index 194a9a0..f38c3ba 100644 --- a/src/main/java/org/gcube/datacatalogue/catalogue/ws/Item.java +++ b/src/main/java/org/gcube/datacatalogue/catalogue/ws/Item.java @@ -7,18 +7,16 @@ import javax.ws.rs.DELETE; 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.core.Context; import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.UriInfo; -import org.gcube.common.authorization.library.provider.AuthorizationProvider; -import org.gcube.common.authorization.library.provider.SecurityTokenProvider; -import org.gcube.common.authorization.library.utils.Caller; -import org.gcube.common.scope.api.ScopeProvider; +import org.gcube.datacatalogue.catalogue.entities.CatalogueItem; import org.gcube.datacatalogue.catalogue.utils.CatalogueUtils; import org.gcube.datacatalogue.catalogue.utils.Constants; +import org.gcube.datacatalogue.catalogue.utils.ContextUtils; import org.gcube.datacatalogue.catalogue.utils.Delegator; import org.gcube.datacatalogue.catalogue.utils.PackageCreatePostActions; import org.gcube.datacatalogue.catalogue.utils.Validator; @@ -29,6 +27,7 @@ import org.json.simple.JSONArray; import org.json.simple.JSONObject; import org.json.simple.parser.JSONParser; import org.json.simple.parser.ParseException; +import org.slf4j.Logger; import org.slf4j.LoggerFactory; import eu.trentorise.opendata.jackan.model.CkanDataset; @@ -36,300 +35,291 @@ import eu.trentorise.opendata.jackan.model.CkanDataset; @Path(Constants.ITEMS) /** * Items service endpoint. - * @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it) + * @author Costantino Perciante (ISTI - CNR) + * @author Luca Frosini (ISTI - CNR) */ public class Item { - - private static final org.slf4j.Logger logger = LoggerFactory.getLogger(Item.class); - - @GET - @Path(Constants.SHOW_METHOD) - @Produces(MediaType.APPLICATION_JSON) - public String show(@Context UriInfo uriInfo){ - - // see http://docs.ckan.org/en/latest/api/#ckan.logic.action.get.package_show - Caller caller = AuthorizationProvider.instance.get(); - String context = ScopeProvider.instance.get(); - boolean isApplication = CatalogueUtils.isApplicationToken(caller); - String username = caller.getClient().getId(); - - if(!isApplication) - return Delegator.delegateGet(caller, context, Constants.ITEM_SHOW, uriInfo, false); - else{ - try{ - DataCatalogue utils = CatalogueUtils.getCatalogue(); - String organization = CatalogueUtilMethods.getOrganizationNameFromScope(context); - String datasetId = null; - - MultivaluedMap queryParams = uriInfo.getQueryParameters(false); - List ids = queryParams.get("id"); - - if(ids == null || ids.isEmpty()) - throw new Exception("'id' field is missing!"); - - datasetId = ids.get(0); - - CkanDataset item = utils.getDataset(datasetId, CatalogueUtils.fetchSysAPI(context)); - - if(organization.equalsIgnoreCase(item.getOrganization().getName()) && username.equals(item.getAuthor())){ - return Delegator.delegateGet(caller, context, Constants.ITEM_SHOW, uriInfo, true); - }else - throw new Exception("You are not authorized to access this item"); - - }catch(Exception e){ - return CatalogueUtils.createJSONOnFailure(e.toString()); + + private static final Logger logger = LoggerFactory.getLogger(Item.class); + + private static final String ID_NAME = "id"; + + private static final String ID_PATH_PARAM = "id"; + + private void applicationChecks(String datasetId, String authorizationErroMessage) throws Exception { + if(ContextUtils.isApplication()) { + logger.debug("Application Token Request"); + DataCatalogue dataCatalogue = CatalogueUtils.getCatalogue(); + CkanDataset dataset = dataCatalogue.getDataset(datasetId, CatalogueUtils.fetchSysAPI()); + + String organization = CatalogueUtilMethods.getCKANOrganization(); + if(organization.equalsIgnoreCase(dataset.getOrganization().getName()) + && ContextUtils.getUsername().equals(dataset.getAuthor())) { + return; } + throw new Exception(authorizationErroMessage); } - } - - @SuppressWarnings("unchecked") + + @GET + @Path("{" + ID_PATH_PARAM + "}") + @Produces(MediaType.APPLICATION_JSON) + public String show(@PathParam(ID_PATH_PARAM) String itemId, @Context UriInfo uriInfo) { + try { + if(itemId.compareTo(Constants.SHOW_METHOD)==0) { + return show(uriInfo); + } + CatalogueItem item = new CatalogueItem(); + item.setId(itemId); + return item.read(); + } catch(Exception e) { + logger.error("", e); + return CatalogueUtils.createJSONOnFailure(e.toString()); + } + } + + public String show(@Context UriInfo uriInfo) { + // see http://docs.ckan.org/en/latest/api/#ckan.logic.action.get.package_show + try { + String datasetId = CatalogueUtils.getIdFromUriInfo(ID_NAME, uriInfo); + applicationChecks(datasetId, "You are not authorized to access this item"); + } catch(Exception e) { + logger.error("", e); + return CatalogueUtils.createJSONOnFailure(e.toString()); + } + return Delegator.delegateGet(Constants.ITEM_SHOW, uriInfo); + } + @POST @Path(Constants.CREATE_METHOD) @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - public String create(String json, @Context UriInfo uriInfo){ - - // see http://docs.ckan.org/en/latest/api/#ckan.logic.action.get.package_create - Caller caller = AuthorizationProvider.instance.get(); - String username = caller.getClient().getId(); // in case of application token is the label of the token - String context = ScopeProvider.instance.get(); - boolean isApplication = CatalogueUtils.isApplicationToken(caller); - - try{ - + @Deprecated + public String oldCreate(String json, @Context UriInfo uriInfo) { + return this.create(json, uriInfo); + } + + + @SuppressWarnings("unchecked") + @POST + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public String create(String json, @Context UriInfo uriInfo) { + // see http://docs.ckan.org/en/latest/api/#ckan.logic.action.create.package_create + try { JSONParser parser = new JSONParser(); - JSONObject obj = (JSONObject)parser.parse(json); - + JSONObject obj = (JSONObject) parser.parse(json); + // check base information (and set them if needed) - Validator.checkBaseInformation(obj, caller, isApplication); - + Validator.checkBaseInformation(obj); + // check resources information (name and url must be there) - Validator.checkResourcesInformation(obj, caller); - + Validator.checkResourcesInformation(obj); + // Check if there are profiles here List profiles = CatalogueUtils.getProfilesNames(); - - if(profiles != null && !profiles.isEmpty()) - Validator.validateAgainstProfile(obj, caller, profiles, isApplication); - - obj = (JSONObject)parser.parse(Delegator.delegatePost(caller, context, Constants.ITEM_CREATE, obj.toJSONString(), uriInfo, isApplication)); - + + if(profiles != null && !profiles.isEmpty()) { + Validator.validateAgainstProfile(obj, profiles); + } + + JSONParser resultParser = new JSONParser(); + JSONObject createdJSONObject = (JSONObject) resultParser + .parse(Delegator.delegatePost(Constants.ITEM_CREATE, obj.toJSONString(), uriInfo)); + // after creation, if it is ok ... - if((boolean)obj.get(Constants.SUCCESS_KEY)){ - - JSONObject result = (JSONObject)obj.get(Constants.RESULT_KEY); - DataCatalogue utils = CatalogueUtils.getCatalogue(); - + if((boolean) createdJSONObject.get(Constants.SUCCESS_KEY)) { + + JSONObject result = (JSONObject) createdJSONObject.get(Constants.RESULT_KEY); + DataCatalogue dataCatalogue = CatalogueUtils.getCatalogue(); + // add also this information as custom field - String datasetUrl = utils.getUnencryptedUrlFromDatasetIdOrName((String)(result.get(Constants.DATASET_KEY))); - if(datasetUrl != null){ + String datasetUrl = dataCatalogue + .getUnencryptedUrlFromDatasetIdOrName((String) (result.get(Constants.DATASET_KEY))); + if(datasetUrl != null) { JSONObject itemUrl = new JSONObject(); itemUrl.put(Constants.EXTRA_KEY, PackageCreatePostActions.ITEM_URL); itemUrl.put(Constants.EXTRA_VALUE, datasetUrl); - ((JSONArray)((JSONObject)obj.get(Constants.RESULT_KEY)).get(Constants.EXTRAS_KEY)).add(itemUrl); + ((JSONArray) ((JSONObject) createdJSONObject.get(Constants.RESULT_KEY)).get(Constants.EXTRAS_KEY)) + .add(itemUrl); } - PackageCreatePostActions packagePostActions = new PackageCreatePostActions( - username, - isApplication, - datasetUrl, - (String)(result.get(Constants.DATASET_KEY)), - context, - SecurityTokenProvider.instance.get(), - (JSONArray)(result.get(Constants.TAGS_KEY)), - (String)(result.get(Constants.TITLE_KEY)) - ); - + + PackageCreatePostActions packagePostActions = new PackageCreatePostActions(datasetUrl, + (String) (result.get(Constants.DATASET_KEY)), + (JSONArray) (result.get(Constants.TAGS_KEY)), + (String) (result.get(Constants.TITLE_KEY))); + packagePostActions.start(); - + } - - return obj.toJSONString(); - - }catch(Exception e){ + return createdJSONObject.toJSONString(); + + } catch(Exception e) { logger.error("Something went wrong... ", e); - if(e instanceof ParseException) + if(e instanceof ParseException) { return CatalogueUtils.createJSONOnFailure("Failed to parse incoming json!"); - else + } else { return CatalogueUtils.createJSONOnFailure(e.toString()); + } } - + } - + @DELETE + @Path("{" + ID_PATH_PARAM + "}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public String delete(@PathParam(ID_PATH_PARAM) String itemId, String json, @Context UriInfo uriInfo) { + // see http://docs.ckan.org/en/latest/api/#ckan.logic.action.delete.package_delete + try { + if(itemId.compareTo(Constants.DELETE_METHOD)==0) { + itemId = CatalogueUtils.getIdFromJSONString(ID_NAME, json); + } + applicationChecks(itemId, "You cannot delete this item"); + } catch(Exception e) { + logger.error("", e); + if(e instanceof ParseException) { + return CatalogueUtils.createJSONOnFailure("Failed to parse incoming json!"); + } else { + return CatalogueUtils.createJSONOnFailure(e.toString()); + } + } + return Delegator.delegatePost(Constants.ITEM_DELETE, json, uriInfo); + + } + + +/* @DELETE @Path(Constants.DELETE_METHOD) @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - public String delete(String json, @Context UriInfo uriInfo){ - - // see http://docs.ckan.org/en/latest/api/#ckan.logic.action.get.package_delete - Caller caller = AuthorizationProvider.instance.get(); - String context = ScopeProvider.instance.get(); - String username = caller.getClient().getId(); - boolean isApplication = CatalogueUtils.isApplicationToken(caller); - - if(!isApplication) - return Delegator.delegatePost(caller, context, Constants.ITEM_DELETE, json, uriInfo, isApplication); - else{ - try { - DataCatalogue utils = CatalogueUtils.getCatalogue(); - - // in this case we check the author has been filled with the same qualifier of this token: the same qualifier can be used in two different contexts - String organization = CatalogueUtilMethods.getOrganizationNameFromScope(context); - String datasetId = null; - - JSONParser parser = new JSONParser(); - JSONObject obj = (JSONObject)parser.parse(json); - - datasetId = (String)obj.get("id"); - if(datasetId == null || datasetId.isEmpty()) - throw new Exception("'id' field is missing!"); - - CkanDataset item = utils.getDataset(datasetId, CatalogueUtils.fetchSysAPI(context)); - - if(organization.equalsIgnoreCase(item.getOrganization().getName()) && username.equals(item.getAuthor())){ - return Delegator.delegatePost(caller, context, Constants.ITEM_DELETE, json, uriInfo, true); - }else - throw new Exception("You cannot delete this item"); - - } catch (Exception e) { - logger.error("Something went wrong... ", e); - if(e instanceof ParseException) - return CatalogueUtils.createJSONOnFailure("Failed to parse incoming json!"); - else - return CatalogueUtils.createJSONOnFailure(e.toString()); + public String delete(String json, @Context UriInfo uriInfo) { + // see http://docs.ckan.org/en/latest/api/#ckan.logic.action.delete.package_delete + try { + String datasetId = CatalogueUtils.getIdFromJSONString(ID_NAME, json); + applicationChecks(datasetId, "You cannot delete this item"); + } catch(Exception e) { + logger.error("", e); + if(e instanceof ParseException) { + return CatalogueUtils.createJSONOnFailure("Failed to parse incoming json!"); + } else { + return CatalogueUtils.createJSONOnFailure(e.toString()); } } - - } - + return Delegator.delegatePost(Constants.ITEM_DELETE, json, uriInfo); + + }*/ + @DELETE @Path(Constants.PURGE_METHOD) @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - public String purge(String json, @Context UriInfo uriInfo){ - + public String purge(String json, @Context UriInfo uriInfo) { // see http://docs.ckan.org/en/latest/api/#ckan.logic.action.delete.dataset_purge - Caller caller = AuthorizationProvider.instance.get(); - String context = ScopeProvider.instance.get(); - String username = caller.getClient().getId(); - - try { - - DataCatalogue utils = CatalogueUtils.getCatalogue(); - boolean isApplication = CatalogueUtils.isApplicationToken(caller); - - if(isApplication){ - - // in this case we check the author has been filled with the same qualifier of this token: the same qualifier can be used in two different contexts - String organization = CatalogueUtilMethods.getOrganizationNameFromScope(context); - String datasetId = null; - - JSONParser parser = new JSONParser(); - JSONObject obj = (JSONObject)parser.parse(json); - - datasetId = (String)obj.get("id"); - if(datasetId == null || datasetId.isEmpty()) - throw new Exception("'id' field is missing!"); - - CkanDataset item = utils.getDataset(datasetId, CatalogueUtils.fetchSysAPI(context)); - - if(organization.equalsIgnoreCase(item.getOrganization().getName()) && username.equals(item.getAuthor())){ - return Delegator.delegatePost(caller, context, Constants.ITEM_PURGE, json, uriInfo, true); - }else - throw new Exception("You cannot purge this item"); - - } - else{ - - // if sysadmin, just invoke ckan - if(utils.isSysAdmin(username)){ - logger.debug("User " + caller.getClient().getId() + " seems a sysadmin"); - return Delegator.delegatePost(caller, context, Constants.ITEM_PURGE, json, uriInfo, false); - } - else{ - String datasetId = null; - String ownerId = null; - String organization = null; - - JSONParser parser = new JSONParser(); - JSONObject obj = (JSONObject)parser.parse(json); - - datasetId = (String)obj.get("id"); - if(datasetId == null || datasetId.isEmpty()) - throw new Exception("'id' field is missing!"); - - String userApiKey = utils.getApiKeyFromUsername(username); - CkanDataset item = utils.getDataset(datasetId, userApiKey); - ownerId = item.getCreatorUserId(); - organization = item.getOrganization().getName(); - + DataCatalogue dataCatalogue = CatalogueUtils.getCatalogue(); + String username = ContextUtils.getUsername(); + if(!dataCatalogue.isSysAdmin(username)) { + String datasetId = CatalogueUtils.getIdFromJSONString(ID_NAME, json); + if(ContextUtils.isApplication()) { + applicationChecks(datasetId, "You cannot purge this item"); + } else { + + String userApiKey = dataCatalogue.getApiKeyFromUsername(ContextUtils.getUsername()); + CkanDataset item = dataCatalogue.getDataset(datasetId, userApiKey); + + String ownerId = item.getCreatorUserId(); + String organization = item.getOrganization().getName(); + // check user role here - RolesCkanGroupOrOrg roleInOrganization = RolesCkanGroupOrOrg.convertFromCapacity(utils.getRoleOfUserInOrganization(username, organization, userApiKey)); - + RolesCkanGroupOrOrg roleInOrganization = RolesCkanGroupOrOrg.convertFromCapacity( + dataCatalogue.getRoleOfUserInOrganization(username, organization, userApiKey)); + boolean purged = false; - if(roleInOrganization.equals(RolesCkanGroupOrOrg.MEMBER)){ + if(roleInOrganization.equals(RolesCkanGroupOrOrg.MEMBER)) { throw new Exception("You have not enough priviliges to delete item with id " + datasetId); - }else if(roleInOrganization.equals(RolesCkanGroupOrOrg.ADMIN)){ - purged = utils.deleteProduct(datasetId, userApiKey, true); - }else{ + } else if(roleInOrganization.equals(RolesCkanGroupOrOrg.ADMIN)) { + purged = dataCatalogue.deleteProduct(datasetId, userApiKey, true); + } else { // we have an editor here; just check she owns the dataset - String userIdCkan = utils.getUserFromApiKey(userApiKey).getId(); - if(ownerId.equals(userIdCkan)) - purged = utils.deleteProduct(datasetId, userApiKey, true); - else + String userIdCkan = dataCatalogue.getUserFromApiKey(userApiKey).getId(); + if(ownerId.equals(userIdCkan)) { + purged = dataCatalogue.deleteProduct(datasetId, userApiKey, true); + } else { throw new Exception("Editors can only remove their own items!"); + } } return CatalogueUtils.createJSONObjectMin(purged, null).toJSONString(); - } } - } - catch (Exception e) { - logger.error("Something went wrong... ", e); - if(e instanceof ParseException) + } catch(Exception e) { + logger.error("", e); + if(e instanceof ParseException) { return CatalogueUtils.createJSONOnFailure("Failed to parse incoming json!"); - else + } else { return CatalogueUtils.createJSONOnFailure(e.toString()); + } } - + return Delegator.delegatePost(Constants.ITEM_PURGE, json, uriInfo); } + + @POST + @Path(Constants.UPDATE_METHOD) + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public String update(String json, @Context UriInfo uriInfo) { + // see http://docs.ckan.org/en/latest/api/#ckan.logic.action.update.package_update + try { + String datasetId = CatalogueUtils.getIdFromJSONString(ID_NAME, json); + applicationChecks(datasetId, "You cannot update this item"); + + + JSONParser parser = new JSONParser(); + JSONObject obj = (JSONObject) parser.parse(json); + + // check base information (and set them if needed) + Validator.checkBaseInformation(obj); + + // check resources information (name and url must be there) + Validator.checkResourcesInformation(obj); + + // Check if there are profiles here + List profiles = CatalogueUtils.getProfilesNames(); + if(profiles != null && !profiles.isEmpty()) { + Validator.validateAgainstProfile(obj, profiles); + } - // TODO PROFILE VALIDATION MUST BE PERFORMED HERE AS WELL - // @POST - // @Path(Constants.UPDATE_METHOD) - // @Consumes(MediaType.APPLICATION_JSON) - // @Produces(MediaType.APPLICATION_JSON) - // public String update(String json){ - // - // - // // 1) Check if there are profiles here - // // 2) If there are profiles: match the record against them - // // 3) Else submit it - // - // // see http://docs.ckan.org/en/latest/api/#ckan.logic.action.get.package_update - // Caller caller = AuthorizationProvider.instance.get(); - // String context = ScopeProvider.instance.get(); - // return CatalogueUtils.delegatePost(caller, context, Constants.ITEM_UPDATE, json); - // - // } - - // @POST - // @Path(Constants.PATCH_METHOD) - // @Consumes(MediaType.APPLICATION_JSON) - // @Produces(MediaType.APPLICATION_JSON) - // public String patch(String json){ - // - // - // // 1) Check if there are profiles here - // // 2) If there are profiles: match the record against them - // // 3) Else submit it - // - // // see http://docs.ckan.org/en/latest/api/#ckan.logic.action.get.package_patch - // Caller caller = AuthorizationProvider.instance.get(); - // String context = ScopeProvider.instance.get(); - // return CatalogueUtils.delegatePost(caller, context, Constants.ITEM_PATCH, json); - // - // } + return Delegator.delegatePost(Constants.ITEM_UPDATE, json, uriInfo); + + } catch (Exception e) { + logger.error("", e); + if(e instanceof ParseException) { + return CatalogueUtils.createJSONOnFailure("Failed to parse incoming json!"); + } else { + return CatalogueUtils.createJSONOnFailure(e.toString()); + } + } + + } + + /* + @POST + @Path(Constants.PATCH_METHOD) + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public String patch(String json, @Context UriInfo uriInfo) { + // see http://docs.ckan.org/en/latest/api/#ckan.logic.action.patch.package_patch + try { + return Delegator.delegatePost(Constants.ITEM_PATCH, json, uriInfo); + } catch (Exception e) { + logger.error("", e); + if(e instanceof ParseException) { + return CatalogueUtils.createJSONOnFailure("Failed to parse incoming json!"); + } else { + return CatalogueUtils.createJSONOnFailure(e.toString()); + } + } + + } + */ } diff --git a/src/main/java/org/gcube/datacatalogue/catalogue/ws/ItemProfile.java b/src/main/java/org/gcube/datacatalogue/catalogue/ws/ItemProfile.java index 2b73190..bc5ce8d 100644 --- a/src/main/java/org/gcube/datacatalogue/catalogue/ws/ItemProfile.java +++ b/src/main/java/org/gcube/datacatalogue/catalogue/ws/ItemProfile.java @@ -14,79 +14,72 @@ import org.gcube.datacatalogue.catalogue.utils.Constants; import org.gcube.datacatalogue.metadatadiscovery.bean.jaxb.NamespaceCategory; import org.json.simple.JSONArray; import org.json.simple.JSONObject; +import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Path(Constants.PROFILES) /** * Items profiles service endpoint. - * @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it) + * @author Costantino Perciante (ISTI - CNR) + * @author Luca Frosini (ISTI - CNR) */ public class ItemProfile { - - private static final org.slf4j.Logger logger = LoggerFactory.getLogger(ItemProfile.class); - + + private static final Logger logger = LoggerFactory.getLogger(ItemProfile.class); + @SuppressWarnings("unchecked") @GET @Path(Constants.PROFILES_NAMES_SHOW) @Produces(MediaType.APPLICATION_JSON) - public String showNames(){ - + public String showNames() { String context = ScopeProvider.instance.get(); logger.debug("Incoming request for context " + context); - // get the names as list JSONObject json = CatalogueUtils.createJSONObjectMin(true, null); - - try{ + try { List names = CatalogueUtils.getProfilesNames(); JSONArray array = new JSONArray(); - for (String elem : names) { - try{ + for(String elem : names) { + try { array.add(elem); - }catch(Exception e){ + } catch(Exception e) { } } json.put(Constants.RESULT_KEY, array); - }catch(Exception e){ + } catch(Exception e) { json = CatalogueUtils.createJSONObjectMin(false, e.getMessage()); } - return json.toJSONString(); } - + @GET @Path(Constants.PROFILE_SHOW) @Produces({MediaType.APPLICATION_XML, /*MediaType.APPLICATION_JSON*/}) public String showSource( //@DefaultValue(MediaType.APPLICATION_XML) @HeaderParam("Accept") String accept, - @QueryParam("name") String profileName) throws Exception{ - + @QueryParam("name") String profileName) throws Exception { String context = ScopeProvider.instance.get(); - logger.debug("Incoming request for context/name " + context+ "/" + profileName); - + logger.debug("Incoming request for context/name " + context + "/" + profileName); // TODO Check how this mapping xml-> json works /*if(accept.equals(MediaType.APPLICATION_JSON)){ org.json.JSONObject xmlJSONObj = XML.toJSONObject(content); return xmlJSONObj.toString(PRETTY_PRINT_INDENT_FACTOR); - - }*/ + }*/ return CatalogueUtils.getProfileSource(profileName); } - @GET @Path(Constants.NAMESPACES_SHOW) @Produces(MediaType.APPLICATION_JSON) @SuppressWarnings("unchecked") - public String showNamespaces() throws Exception{ - + public String showNamespaces() throws Exception { // get the names as list JSONObject json = CatalogueUtils.createJSONObjectMin(true, null); JSONArray namespacesJson = new JSONArray(); - try{ + try { List namespaces = CatalogueUtils.getNamespaceCategories(); - for (NamespaceCategory namespaceCategory : namespaces) { + for(NamespaceCategory namespaceCategory : namespaces) { JSONObject obj = new JSONObject(); obj.put("id", namespaceCategory.getId()); obj.put("title", namespaceCategory.getTitle()); @@ -95,11 +88,10 @@ public class ItemProfile { namespacesJson.add(obj); } json.put(Constants.RESULT_KEY, namespacesJson); - }catch(Exception e){ + } catch(Exception e) { json = CatalogueUtils.createJSONObjectMin(false, e.getMessage()); } - return json.toJSONString(); } - + } diff --git a/src/main/java/org/gcube/datacatalogue/catalogue/ws/License.java b/src/main/java/org/gcube/datacatalogue/catalogue/ws/License.java index 397ffbd..4868221 100644 --- a/src/main/java/org/gcube/datacatalogue/catalogue/ws/License.java +++ b/src/main/java/org/gcube/datacatalogue/catalogue/ws/License.java @@ -7,10 +7,6 @@ import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.UriInfo; -import org.gcube.common.authorization.library.provider.AuthorizationProvider; -import org.gcube.common.authorization.library.utils.Caller; -import org.gcube.common.scope.api.ScopeProvider; -import org.gcube.datacatalogue.catalogue.utils.CatalogueUtils; import org.gcube.datacatalogue.catalogue.utils.Constants; import org.gcube.datacatalogue.catalogue.utils.Delegator; @@ -18,7 +14,8 @@ import org.gcube.datacatalogue.catalogue.utils.Delegator; @Path(Constants.LICENSES) /** * Licenses service endpoint. - * @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it) + * @author Costantino Perciante (ISTI - CNR) + * @author Luca Frosini (ISTI - CNR) */ public class License { @@ -26,13 +23,8 @@ public class License { @Path(Constants.LIST_METHOD) @Produces(MediaType.APPLICATION_JSON) public String show(@Context UriInfo uriInfo){ - // see http://docs.ckan.org/en/latest/api/#ckan.logic.action.get.license_list - Caller caller = AuthorizationProvider.instance.get(); - String context = ScopeProvider.instance.get(); - boolean isApplication = CatalogueUtils.isApplicationToken(caller); - return Delegator.delegateGet(caller, context, Constants.LICENSES_SHOW, uriInfo, isApplication); - + return Delegator.delegateGet(Constants.LICENSES_SHOW, uriInfo); } } diff --git a/src/main/java/org/gcube/datacatalogue/catalogue/ws/Organization.java b/src/main/java/org/gcube/datacatalogue/catalogue/ws/Organization.java index 65b7e0b..eb316da 100644 --- a/src/main/java/org/gcube/datacatalogue/catalogue/ws/Organization.java +++ b/src/main/java/org/gcube/datacatalogue/catalogue/ws/Organization.java @@ -1,7 +1,5 @@ package org.gcube.datacatalogue.catalogue.ws; -import java.util.List; - import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; import javax.ws.rs.GET; @@ -10,146 +8,115 @@ import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.UriInfo; -import org.gcube.common.authorization.library.provider.AuthorizationProvider; -import org.gcube.common.authorization.library.utils.Caller; -import org.gcube.common.scope.api.ScopeProvider; import org.gcube.datacatalogue.catalogue.utils.CatalogueUtils; import org.gcube.datacatalogue.catalogue.utils.Constants; +import org.gcube.datacatalogue.catalogue.utils.ContextUtils; import org.gcube.datacatalogue.catalogue.utils.Delegator; import org.gcube.datacatalogue.ckanutillibrary.server.DataCatalogue; import org.gcube.datacatalogue.ckanutillibrary.server.utils.CatalogueUtilMethods; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import eu.trentorise.opendata.jackan.model.CkanOrganization; - @Path(Constants.ORGANIZATIONS) /** * Organizations service endpoint. - * @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it) + * @author Costantino Perciante (ISTI - CNR) + * @author Luca Frosini (ISTI - CNR) */ public class Organization { - + + private static final Logger logger = LoggerFactory.getLogger(Organization.class); + + private static final String ID_NAME = "id"; + + private void applicationChecks(String organizationId, String authorizationErroMessage) throws Exception { + if(ContextUtils.isApplication()) { + logger.debug("Application Token Request"); + DataCatalogue dataCatalogue = CatalogueUtils.getCatalogue(); + String organization = CatalogueUtilMethods.getCKANOrganization(); + + CkanOrganization fetchedOrganization = dataCatalogue.getOrganizationByName(organizationId); + + if(organization.equalsIgnoreCase(fetchedOrganization.getName())) { + return; + } + + throw new Exception(authorizationErroMessage); + } + } + @GET @Path(Constants.SHOW_METHOD) @Produces(MediaType.APPLICATION_JSON) - public String show(@Context UriInfo uriInfo){ - + public String show(@Context UriInfo uriInfo) { // see http://docs.ckan.org/en/latest/api/#ckan.logic.action.get.organization_show - Caller caller = AuthorizationProvider.instance.get(); - String context = ScopeProvider.instance.get(); - boolean isApplication = CatalogueUtils.isApplicationToken(caller); - - if(!isApplication) - return Delegator.delegateGet(caller, context, Constants.ORGANIZATION_SHOW, uriInfo, false); - else{ - - try{ - DataCatalogue utils = CatalogueUtils.getCatalogue(); - String organization = CatalogueUtilMethods.getOrganizationNameFromScope(context); - String organizationId = null; - - MultivaluedMap queryParams = uriInfo.getQueryParameters(false); - List ids = queryParams.get("id"); - - if(ids == null || ids.isEmpty()) - throw new Exception("'id' field is missing!"); - - organizationId = ids.get(0); - - CkanOrganization fetchedOrganization = utils.getOrganizationByName(organizationId); - - if(organization.equalsIgnoreCase(fetchedOrganization.getName())){ - return Delegator.delegateGet(caller, context, Constants.ORGANIZATION_SHOW, uriInfo, true); - }else - throw new Exception("You are not authorized to access this organization"); - - }catch(Exception e){ - return CatalogueUtils.createJSONOnFailure(e.toString()); - } - + try { + String organizationId = CatalogueUtils.getIdFromUriInfo(ID_NAME, uriInfo); + applicationChecks(organizationId, "You are not authorized to access this organization"); + } catch(Exception e) { + logger.error("", e); + return CatalogueUtils.createJSONOnFailure(e.toString()); } - + return Delegator.delegateGet(Constants.ORGANIZATION_SHOW, uriInfo); } - + @GET @Path(Constants.LIST_METHOD) @Produces(MediaType.APPLICATION_JSON) - public String organizationList(@Context UriInfo uriInfo){ - + public String organizationList(@Context UriInfo uriInfo) { // see http://docs.ckan.org/en/latest/api/#ckan.logic.action.get.organization_list - Caller caller = AuthorizationProvider.instance.get(); - String context = ScopeProvider.instance.get(); - boolean isApplication = CatalogueUtils.isApplicationToken(caller); - return Delegator.delegateGet(caller, context, Constants.ORGANIZATION_LIST, uriInfo, isApplication); - + return Delegator.delegateGet(Constants.ORGANIZATION_LIST, uriInfo); + } - + @POST @Path(Constants.CREATE_METHOD) @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - public String create(String json, @Context UriInfo uriInfo){ - - // see http://docs.ckan.org/en/latest/api/#ckan.logic.action.get.organization_create - Caller caller = AuthorizationProvider.instance.get(); - String context = ScopeProvider.instance.get(); - return Delegator.delegatePost(caller, context, Constants.ORGANIZATION_CREATE, json, uriInfo, false); - + public String create(String json, @Context UriInfo uriInfo) { + // see http://docs.ckan.org/en/latest/api/#ckan.logic.action.create.organization_create + return Delegator.delegatePost(Constants.ORGANIZATION_CREATE, json, uriInfo); } - + @DELETE @Path(Constants.DELETE_METHOD) @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - public String delete(String json, @Context UriInfo uriInfo){ - - // see http://docs.ckan.org/en/latest/api/#ckan.logic.action.get.organization_delete - Caller caller = AuthorizationProvider.instance.get(); - String context = ScopeProvider.instance.get(); - return Delegator.delegatePost(caller, context, Constants.ORGANIZATION_DELETE, json, uriInfo, false); - + public String delete(String json, @Context UriInfo uriInfo) { + // see http://docs.ckan.org/en/latest/api/#ckan.logic.action.delete.organization_delete + return Delegator.delegatePost(Constants.ORGANIZATION_DELETE, json, uriInfo); } - + @DELETE @Path(Constants.PURGE_METHOD) @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - public String purge(String json, @Context UriInfo uriInfo){ - - // see http://docs.ckan.org/en/latest/api/#ckan.logic.action.get.organization_create - Caller caller = AuthorizationProvider.instance.get(); - String context = ScopeProvider.instance.get(); - return Delegator.delegatePost(caller, context, Constants.ORGANIZATION_PURGE, json, uriInfo, false); - + public String purge(String json, @Context UriInfo uriInfo) { + // see http://docs.ckan.org/en/latest/api/#ckan.logic.action.delete.organization_purge + return Delegator.delegatePost(Constants.ORGANIZATION_PURGE, json, uriInfo); } - + @POST @Path(Constants.UPDATE_METHOD) @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - public String update(String json, @Context UriInfo uriInfo){ - - // see http://docs.ckan.org/en/latest/api/#ckan.logic.action.get.organization_update - Caller caller = AuthorizationProvider.instance.get(); - String context = ScopeProvider.instance.get(); - return Delegator.delegatePost(caller, context, Constants.ORGANIZATION_UPDATE, json, uriInfo, false); - + public String update(String json, @Context UriInfo uriInfo) { + // see http://docs.ckan.org/en/latest/api/#ckan.logic.action.update.organization_update + return Delegator.delegatePost(Constants.ORGANIZATION_UPDATE, json, uriInfo); + } - + @POST @Path(Constants.PATCH_METHOD) @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - public String patch(String json, @Context UriInfo uriInfo){ - - // see http://docs.ckan.org/en/latest/api/#ckan.logic.action.get.organization_patch - Caller caller = AuthorizationProvider.instance.get(); - String context = ScopeProvider.instance.get(); - return Delegator.delegatePost(caller, context, Constants.ORGANIZATION_PATCH, json, uriInfo, false); - + public String patch(String json, @Context UriInfo uriInfo) { + // see http://docs.ckan.org/en/latest/api/#ckan.logic.action.patch.organization_patch + return Delegator.delegatePost(Constants.ORGANIZATION_PATCH, json, uriInfo); } - + } diff --git a/src/main/java/org/gcube/datacatalogue/catalogue/ws/Resource.java b/src/main/java/org/gcube/datacatalogue/catalogue/ws/Resource.java index a64e1ad..0c0d255 100644 --- a/src/main/java/org/gcube/datacatalogue/catalogue/ws/Resource.java +++ b/src/main/java/org/gcube/datacatalogue/catalogue/ws/Resource.java @@ -1,8 +1,5 @@ package org.gcube.datacatalogue.catalogue.ws; - -import java.util.List; - import javax.servlet.http.HttpServletRequest; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; @@ -12,22 +9,17 @@ import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.UriInfo; -import org.gcube.common.authorization.library.provider.AuthorizationProvider; -import org.gcube.common.authorization.library.utils.Caller; -import org.gcube.common.scope.api.ScopeProvider; -import org.gcube.common.scope.impl.ScopeBean; import org.gcube.datacatalogue.catalogue.utils.CatalogueUtils; import org.gcube.datacatalogue.catalogue.utils.Constants; +import org.gcube.datacatalogue.catalogue.utils.ContextUtils; import org.gcube.datacatalogue.catalogue.utils.Delegator; import org.gcube.datacatalogue.ckanutillibrary.server.DataCatalogue; import org.gcube.datacatalogue.ckanutillibrary.server.utils.CatalogueUtilMethods; import org.glassfish.jersey.media.multipart.FormDataMultiPart; -import org.json.simple.JSONObject; -import org.json.simple.parser.JSONParser; import org.json.simple.parser.ParseException; +import org.slf4j.Logger; import org.slf4j.LoggerFactory; import eu.trentorise.opendata.jackan.model.CkanDataset; @@ -36,288 +28,148 @@ import eu.trentorise.opendata.jackan.model.CkanResource; @Path(Constants.RESOURCES) /** * Resource service endpoint. - * @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it) + * @author Costantino Perciante (ISTI - CNR) + * @author Luca Frosini (ISTI - CNR) */ public class Resource { - - private static final org.slf4j.Logger logger = LoggerFactory.getLogger(Resource.class); - + + private static final Logger logger = LoggerFactory.getLogger(Resource.class); + + private static final String ID_NAME = "id"; + private static final String PACKAGE_ID_NAME = "package_id"; + + private void applicationChecks(String datasetId, String authorizationErroMessage) throws Exception { + if(ContextUtils.isApplication()) { + logger.debug("Application Token Request"); + DataCatalogue dataCatalogue = CatalogueUtils.getCatalogue(); + CkanDataset dataset = dataCatalogue.getDataset(datasetId, CatalogueUtils.fetchSysAPI()); + + String organization = CatalogueUtilMethods.getCKANOrganization(); + if(organization.equalsIgnoreCase(dataset.getOrganization().getName()) + && ContextUtils.getUsername().equals(dataset.getAuthor())) { + return; + } + throw new Exception(authorizationErroMessage); + } + } + @GET @Path(Constants.SHOW_METHOD) @Produces(MediaType.APPLICATION_JSON) - public String show(@Context UriInfo uriInfo){ - + public String show(@Context UriInfo uriInfo) { // see http://docs.ckan.org/en/latest/api/#ckan.logic.action.get.resource_show - Caller caller = AuthorizationProvider.instance.get(); - String context = ScopeProvider.instance.get(); - String username = caller.getClient().getId(); - boolean isApplication = CatalogueUtils.isApplicationToken(caller); - - if(isApplication){ - try{ - DataCatalogue utils = CatalogueUtils.getCatalogue(); - String organization = CatalogueUtilMethods.getOrganizationNameFromScope(context); - String resourceId = null; - - MultivaluedMap queryParams = uriInfo.getQueryParameters(false); - List ids = queryParams.get("id"); - - if(ids == null || ids.isEmpty()) - throw new Exception("'id' field is missing!"); - - CkanResource resource = utils.getResource(resourceId, CatalogueUtils.fetchSysAPI(context)); - CkanDataset item = utils.getDataset(resource.getPackageId(), CatalogueUtils.fetchSysAPI(context)); - - if(organization.equalsIgnoreCase(item.getOrganization().getName()) && username.equals(item.getAuthor())){ - return Delegator.delegateGet(caller, context, Constants.RESOURCE_SHOW, uriInfo, true); - }else - throw new Exception("You are not authorized to access this resource"); - } catch (Exception e) { - return CatalogueUtils.createJSONOnFailure(e.toString()); - } + try { + String resourceId = CatalogueUtils.getIdFromUriInfo(ID_NAME, uriInfo); + CkanResource resource = CatalogueUtils.getCatalogue().getResource(resourceId, CatalogueUtils.fetchSysAPI()); + applicationChecks(resource.getPackageId(), "You are not authorized to access this resource"); + } catch(Exception e) { + logger.error("", e); + return CatalogueUtils.createJSONOnFailure(e.toString()); } - - return Delegator.delegateGet(caller, context, Constants.RESOURCE_SHOW, uriInfo, isApplication); - + return Delegator.delegateGet(Constants.RESOURCE_SHOW, uriInfo); } - + @POST @Path(Constants.CREATE_METHOD) @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - public String create(String json, @Context UriInfo uriInfo){ - + public String create(String json, @Context UriInfo uriInfo) { // see http://docs.ckan.org/en/latest/api/#ckan.logic.action.create.resource_create - Caller caller = AuthorizationProvider.instance.get(); - String context = ScopeProvider.instance.get(); - String username = caller.getClient().getId(); - boolean isApplication = CatalogueUtils.isApplicationToken(caller); - - if(!isApplication) - return Delegator.delegatePost(caller, context, Constants.RESOURCE_CREATE, json, uriInfo, isApplication); - else{ - try { - DataCatalogue utils = CatalogueUtils.getCatalogue(); - - // in this case we check the author has been filled with the same qualifier of this token: the same qualifier can be used in two different contexts - String organization = CatalogueUtilMethods.getOrganizationNameFromScope(ScopeProvider.instance.get()); - String datasetId = null; - - JSONParser parser = new JSONParser(); - JSONObject obj = (JSONObject)parser.parse(json); - - datasetId = (String)obj.get("package_id"); // within the resource it is defined this way - if(datasetId == null || datasetId.isEmpty()) - throw new Exception("'id' field is missing!"); - - CkanDataset item = utils.getDataset(datasetId, CatalogueUtils.fetchSysAPI(context)); - - if(organization.equalsIgnoreCase(item.getOrganization().getName()) && username.equals(item.getAuthor())){ - return Delegator.delegatePost(caller, context, Constants.RESOURCE_CREATE, json, uriInfo, true); - }else - throw new Exception("You cannot add a resource to this item"); - - } catch (Exception e) { - logger.error("Something went wrong... ", e); - if(e instanceof ParseException) - return CatalogueUtils.createJSONOnFailure("Failed to parse incoming json!"); - else - return CatalogueUtils.createJSONOnFailure(e.toString()); + try { + String datasetId = CatalogueUtils.getIdFromJSONString(PACKAGE_ID_NAME, json); + applicationChecks(datasetId, "You cannot add a resource to this item"); + } catch(Exception e) { + logger.error("", e); + if(e instanceof ParseException) { + return CatalogueUtils.createJSONOnFailure("Failed to parse incoming json!"); + } else { + return CatalogueUtils.createJSONOnFailure(e.toString()); } } - + return Delegator.delegatePost(Constants.RESOURCE_CREATE, json, uriInfo); } - + @POST @Path(Constants.CREATE_METHOD) @Consumes(MediaType.MULTIPART_FORM_DATA) @Produces(MediaType.APPLICATION_JSON) - public String create( - FormDataMultiPart multiPart, @Context UriInfo uriInfo, - @Context final HttpServletRequest request - ){ - - Caller caller = AuthorizationProvider.instance.get(); - String context = ScopeProvider.instance.get(); - String username = caller.getClient().getId(); - boolean isApplication = CatalogueUtils.isApplicationToken(caller); - - if(!isApplication) - return Delegator.delegatePost(caller, context, Constants.RESOURCE_CREATE, multiPart, uriInfo, false); - else{ - try { - DataCatalogue utils = CatalogueUtils.getCatalogue(); - - // in this case we check the author has been filled with the same qualifier of this token: the same qualifier can be used in two different contexts - ScopeBean bean = new ScopeBean(ScopeProvider.instance.get()); - String organization = bean.name().toLowerCase().replace(" ", "_").replace("-", "_"); - String datasetId = null; - - datasetId = (String)multiPart.getField("package_id").getValue(); // within the resource it is defined this way - if(datasetId == null || datasetId.isEmpty()) - throw new Exception("'id' field is missing!"); - - CkanDataset item = utils.getDataset(datasetId, CatalogueUtils.fetchSysAPI(context)); - - if(organization.equalsIgnoreCase(item.getOrganization().getName()) && username.equals(item.getAuthor())){ - return Delegator.delegatePost(caller, context, Constants.RESOURCE_CREATE, multiPart, uriInfo, true); - }else - throw new Exception("You cannot add a resource to this item"); - - } catch (Exception e) { - logger.error("Something went wrong... ", e); - if(e instanceof ParseException) - return CatalogueUtils.createJSONOnFailure("Failed to parse incoming json!"); - else - return CatalogueUtils.createJSONOnFailure(e.toString()); + public String create(FormDataMultiPart multiPart, @Context UriInfo uriInfo, + @Context final HttpServletRequest request) { + // see http://docs.ckan.org/en/latest/api/#ckan.logic.action.create.resource_create + try { + String datasetId = (String) multiPart.getField(PACKAGE_ID_NAME).getValue(); // within the resource it is defined this way + if(datasetId == null || datasetId.isEmpty()) { + throw new Exception("'" + PACKAGE_ID_NAME +"' field is missing!"); } + applicationChecks(datasetId, "You cannot add a resource to this item"); + } catch(Exception e) { + logger.error("", e); + return CatalogueUtils.createJSONOnFailure(e.toString()); } - + return Delegator.delegatePost(Constants.RESOURCE_CREATE, multiPart, uriInfo); } - + @DELETE @Path(Constants.DELETE_METHOD) @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - public String delete(String json, @Context UriInfo uriInfo){ - - // see http://docs.ckan.org/en/latest/api/#ckan.logic.action.create.resource_delete - Caller caller = AuthorizationProvider.instance.get(); - String context = ScopeProvider.instance.get(); - String username = caller.getClient().getId(); - boolean isApplication = CatalogueUtils.isApplicationToken(caller); - - if(!isApplication) - return Delegator.delegatePost(caller, context, Constants.RESOURCE_DELETE, json, uriInfo, false); - else{ - try { - DataCatalogue utils = CatalogueUtils.getCatalogue(); - - // in this case we check the author has been filled with the same qualifier of this token: the same qualifier can be used in two different contexts - ScopeBean bean = new ScopeBean(ScopeProvider.instance.get()); - String organization = bean.name().toLowerCase().replace(" ", "_").replace("-", "_"); - - JSONParser parser = new JSONParser(); - JSONObject obj = (JSONObject)parser.parse(json); - - String resourceId = (String)obj.get("id"); // within the resource it is defined this way - if(resourceId == null || resourceId.isEmpty()) - throw new Exception("'id' field is missing!"); - - CkanResource resource = utils.getResource(resourceId, CatalogueUtils.fetchSysAPI(context)); - CkanDataset item = utils.getDataset(resource.getPackageId(), CatalogueUtils.fetchSysAPI(context)); - - if(organization.equalsIgnoreCase(item.getOrganization().getName()) && username.equals(item.getAuthor())){ - return Delegator.delegatePost(caller, context, Constants.RESOURCE_DELETE, json, uriInfo, true); - }else - throw new Exception("You cannot delete this resource"); - - } catch (Exception e) { - logger.error("Something went wrong... ", e); - if(e instanceof ParseException) - return CatalogueUtils.createJSONOnFailure("Failed to parse incoming json!"); - else - return CatalogueUtils.createJSONOnFailure(e.toString()); + public String delete(String json, @Context UriInfo uriInfo) { + // see http://docs.ckan.org/en/latest/api/#ckan.logic.action.delete.resource_delete + try { + String resourceId = CatalogueUtils.getIdFromJSONString(ID_NAME, json); + CkanResource resource = CatalogueUtils.getCatalogue().getResource(resourceId, CatalogueUtils.fetchSysAPI()); + applicationChecks(resource.getPackageId(), "You cannot delete this resource"); + } catch(Exception e) { + logger.error("", e); + if(e instanceof ParseException) { + return CatalogueUtils.createJSONOnFailure("Failed to parse incoming json!"); + } else { + return CatalogueUtils.createJSONOnFailure(e.toString()); } } - + return Delegator.delegatePost(Constants.RESOURCE_DELETE, json, uriInfo); } - + @POST @Path(Constants.UPDATE_METHOD) @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - public String update(String json, @Context UriInfo uriInfo){ - + public String update(String json, @Context UriInfo uriInfo) { // see http://docs.ckan.org/en/latest/api/#ckan.logic.action.update.resource_update - Caller caller = AuthorizationProvider.instance.get(); - String context = ScopeProvider.instance.get(); - String username = caller.getClient().getId(); - boolean isApplication = CatalogueUtils.isApplicationToken(caller); - - if(!isApplication) - return Delegator.delegatePost(caller, context, Constants.RESOURCE_UPDATE, json, uriInfo, false); - else{ - try { - DataCatalogue utils = CatalogueUtils.getCatalogue(); - - // in this case we check the author has been filled with the same qualifier of this token: the same qualifier can be used in two different contexts - ScopeBean bean = new ScopeBean(ScopeProvider.instance.get()); - String organization = bean.name().toLowerCase().replace(" ", "_").replace("-", "_"); - - JSONParser parser = new JSONParser(); - JSONObject obj = (JSONObject)parser.parse(json); - - String resourceId = (String)obj.get("id"); // within the resource it is defined this way - if(resourceId == null || resourceId.isEmpty()) - throw new Exception("'id' field is missing!"); - - CkanResource resource = utils.getResource(resourceId, CatalogueUtils.fetchSysAPI(context)); - CkanDataset item = utils.getDataset(resource.getPackageId(), CatalogueUtils.fetchSysAPI(context)); - - if(organization.equalsIgnoreCase(item.getOrganization().getName()) && username.equals(item.getAuthor())){ - return Delegator.delegatePost(caller, context, Constants.RESOURCE_UPDATE, json, uriInfo, true); - }else - throw new Exception("You cannot update this resource"); - - } catch (Exception e) { - logger.error("Something went wrong... ", e); - if(e instanceof ParseException) - return CatalogueUtils.createJSONOnFailure("Failed to parse incoming json!"); - else - return CatalogueUtils.createJSONOnFailure(e.toString()); + try { + String resourceId = CatalogueUtils.getIdFromJSONString(ID_NAME, json); + CkanResource resource = CatalogueUtils.getCatalogue().getResource(resourceId, CatalogueUtils.fetchSysAPI()); + applicationChecks(resource.getPackageId(), "You cannot update this resource"); + } catch(Exception e) { + logger.error("", e); + if(e instanceof ParseException) { + return CatalogueUtils.createJSONOnFailure("Failed to parse incoming json!"); + } else { + return CatalogueUtils.createJSONOnFailure(e.toString()); } } - + return Delegator.delegatePost(Constants.RESOURCE_UPDATE, json, uriInfo); } - + @POST @Path(Constants.PATCH_METHOD) @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - public String patch(String json, @Context UriInfo uriInfo){ - - // see http://docs.ckan.org/en/latest/api/#ckan.logic.action.update.resource_patch - Caller caller = AuthorizationProvider.instance.get(); - String context = ScopeProvider.instance.get(); - String username = caller.getClient().getId(); - boolean isApplication = CatalogueUtils.isApplicationToken(caller); - - if(!isApplication) - return Delegator.delegatePost(caller, context, Constants.RESOURCE_PATCH, json, uriInfo, false); - else{ - try { - DataCatalogue utils = CatalogueUtils.getCatalogue(); - - // in this case we check the author has been filled with the same qualifier of this token: the same qualifier can be used in two different contexts - ScopeBean bean = new ScopeBean(ScopeProvider.instance.get()); - String organization = bean.name().toLowerCase().replace(" ", "_").replace("-", "_"); - - JSONParser parser = new JSONParser(); - JSONObject obj = (JSONObject)parser.parse(json); - - String resourceId = (String)obj.get("id"); // within the resource it is defined this way - if(resourceId == null || resourceId.isEmpty()) - throw new Exception("'id' field is missing!"); - - CkanResource resource = utils.getResource(resourceId, CatalogueUtils.fetchSysAPI(context)); - CkanDataset item = utils.getDataset(resource.getPackageId(), CatalogueUtils.fetchSysAPI(context)); - - if(organization.equalsIgnoreCase(item.getOrganization().getName()) && username.equals(item.getAuthor())){ - return Delegator.delegatePost(caller, context, Constants.RESOURCE_PATCH, json, uriInfo, true); - }else - throw new Exception("You cannot patch this resource"); - - } catch (Exception e) { - logger.error("Something went wrong... ", e); - if(e instanceof ParseException) - return CatalogueUtils.createJSONOnFailure("Failed to parse incoming json!"); - else - return CatalogueUtils.createJSONOnFailure(e.toString()); + public String patch(String json, @Context UriInfo uriInfo) { + // see http://docs.ckan.org/en/latest/api/#ckan.logic.action.patch.resource_patch + try { + String resourceId = CatalogueUtils.getIdFromJSONString(ID_NAME, json); + CkanResource resource = CatalogueUtils.getCatalogue().getResource(resourceId, CatalogueUtils.fetchSysAPI()); + applicationChecks(resource.getPackageId(), "You cannot patch this resource"); + } catch(Exception e) { + logger.error("", e); + if(e instanceof ParseException) { + return CatalogueUtils.createJSONOnFailure("Failed to parse incoming json!"); + } else { + return CatalogueUtils.createJSONOnFailure(e.toString()); } } - - + return Delegator.delegatePost(Constants.RESOURCE_PATCH, json, uriInfo); } - + } diff --git a/src/main/java/org/gcube/datacatalogue/catalogue/ws/User.java b/src/main/java/org/gcube/datacatalogue/catalogue/ws/User.java index 1a906bc..62f2f72 100644 --- a/src/main/java/org/gcube/datacatalogue/catalogue/ws/User.java +++ b/src/main/java/org/gcube/datacatalogue/catalogue/ws/User.java @@ -10,9 +10,6 @@ import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.UriInfo; -import org.gcube.common.authorization.library.provider.AuthorizationProvider; -import org.gcube.common.authorization.library.utils.Caller; -import org.gcube.common.scope.api.ScopeProvider; import org.gcube.datacatalogue.catalogue.utils.Constants; import org.gcube.datacatalogue.catalogue.utils.Delegator; @@ -20,7 +17,8 @@ import org.gcube.datacatalogue.catalogue.utils.Delegator; @Path(Constants.USERS) /** * User service endpoint. - * @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it) + * @author Costantino Perciante (ISTI - CNR) + * @author Luca Frosini (ISTI - CNR) */ public class User { @@ -28,11 +26,8 @@ public class User { @Path(Constants.SHOW_METHOD) @Produces(MediaType.TEXT_PLAIN) public String show(@Context UriInfo uriInfo){ - // see http://docs.ckan.org/en/latest/api/#ckan.logic.action.get.user_show - Caller caller = AuthorizationProvider.instance.get(); - String context = ScopeProvider.instance.get(); - return Delegator.delegateGet(caller, context, Constants.USER_SHOW, uriInfo, false); + return Delegator.delegateGet(Constants.USER_SHOW, uriInfo); } @@ -41,11 +36,8 @@ public class User { @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public String create(String json, @Context UriInfo uriInfo){ - - // see http://docs.ckan.org/en/latest/api/#ckan.logic.action.get.user_create - Caller caller = AuthorizationProvider.instance.get(); - String context = ScopeProvider.instance.get(); - return Delegator.delegatePost(caller, context, Constants.USER_CREATE, json, uriInfo, false); + // see http://docs.ckan.org/en/latest/api/#ckan.logic.action.create.user_create + return Delegator.delegatePost(Constants.USER_CREATE, json, uriInfo); } @@ -54,11 +46,8 @@ public class User { @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public String delete(String json, @Context UriInfo uriInfo){ - - // see http://docs.ckan.org/en/latest/api/#ckan.logic.action.get.user_delete - Caller caller = AuthorizationProvider.instance.get(); - String context = ScopeProvider.instance.get(); - return Delegator.delegatePost(caller, context, Constants.USER_DELETE, json, uriInfo, false); + // see http://docs.ckan.org/en/latest/api/#ckan.logic.action.delete.user_delete + return Delegator.delegatePost(Constants.USER_DELETE, json, uriInfo); } @@ -67,11 +56,8 @@ public class User { @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public String update(String json, @Context UriInfo uriInfo){ - - // see http://docs.ckan.org/en/latest/api/#ckan.logic.action.get.user_update - Caller caller = AuthorizationProvider.instance.get(); - String context = ScopeProvider.instance.get(); - return Delegator.delegatePost(caller, context, Constants.USER_UPDATE, json, uriInfo, false); + // see http://docs.ckan.org/en/latest/api/#ckan.logic.action.update.user_update + return Delegator.delegatePost(Constants.USER_UPDATE, json, uriInfo); } diff --git a/src/main/resources/ehcache.xml b/src/main/resources/ehcache.xml deleted file mode 100644 index f1f2ab1..0000000 --- a/src/main/resources/ehcache.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/test/java/CataloguePublishExample.java b/src/test/java/CataloguePublishExample.java index 3d2b860..8634ca4 100644 --- a/src/test/java/CataloguePublishExample.java +++ b/src/test/java/CataloguePublishExample.java @@ -1,6 +1,4 @@ -import java.util.HashMap; - import org.json.simple.JSONArray; import org.json.simple.JSONObject; import org.json.simple.parser.JSONParser; @@ -14,14 +12,12 @@ import eu.trentorise.opendata.jackan.internal.org.apache.http.impl.client.Closea import eu.trentorise.opendata.jackan.internal.org.apache.http.impl.client.HttpClientBuilder; import eu.trentorise.opendata.jackan.internal.org.apache.http.util.EntityUtils; - - /** * An example of publishing in the data catalogue. * @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it) */ public class CataloguePublishExample { - + private static final String LICENSE_LIST = "/api/licenses/list/"; private static final String ORGANIZATIONS_LIST = "/api/organizations/list"; private static final String ORGANIZATIONS_SHOW = "/api/organizations/show?id="; @@ -30,72 +26,72 @@ public class CataloguePublishExample { private static final String GET_SINGLE_PROFILE_XML = "/api/profiles/profile?name="; // GET IT'S XML private static final String CREATE_ITEM = "/api/items/create"; private static final String GET_BACK_ITEM = "/api/items/show?id="; - + public static void main(String[] args) throws Exception { - + // you should recover the address via IS... String catalogueServiceEndpoint = "http://catalogue-ws-d-d4s.d4science.org/catalogue-ws/rest"; - + // token for the VRE in which the catalogue is present (and where I have at least catalogue-editor role, if // I'm willing to publish). Note: a catalogue may host more than one VRE/Organization. I'm taking the token I need. String myToken = ""; - + // fetch list of licenses and print it JSONObject licenseBean = get(catalogueServiceEndpoint + LICENSE_LIST, myToken); - - if(licenseBean != null){ - + + if(licenseBean != null) { + // get "real result" and print couple license id - license name - JSONArray licenses = (JSONArray)licenseBean.get("result"); - - for(int i = 0; i < licenses.size(); i++){ - - JSONObject license = (JSONObject)licenses.get(i); - System.out.println("License name is " + (String)license.get("id")); - System.out.println("License id is " + (String)license.get("title")); - + JSONArray licenses = (JSONArray) licenseBean.get("result"); + + for(int i = 0; i < licenses.size(); i++) { + + JSONObject license = (JSONObject) licenses.get(i); + System.out.println("License name is " + (String) license.get("id")); + System.out.println("License id is " + (String) license.get("title")); + } - + } - + // do the same with organizations JSONObject organizationsBean = get(catalogueServiceEndpoint + ORGANIZATIONS_LIST, myToken); - if(organizationsBean != null){ - + if(organizationsBean != null) { + // get list of organizations (a list of names is returned) - JSONArray organizations = (JSONArray)organizationsBean.get("result"); - - for(int i = 0; i < organizations.size(); i++){ - String organization = (String)organizations.get(i); - System.out.println("Organization name is " + organization); + JSONArray organizations = (JSONArray) organizationsBean.get("result"); + + for(int i = 0; i < organizations.size(); i++) { + String organization = (String) organizations.get(i); + System.out.println("Organization name is " + organization); } - + } - + // take "nextnext" and show its details JSONObject organizationBean = get(catalogueServiceEndpoint + ORGANIZATIONS_SHOW + "nextnext", myToken); - if(organizationBean != null){ - + if(organizationBean != null) { + // get list of organizations (a list of names is returned) - JSONObject organization = (JSONObject)organizationBean.get("result"); + JSONObject organization = (JSONObject) organizationBean.get("result"); System.out.println("Next Next looks like " + organization.toJSONString()); - + } - + // list groups JSONObject groupsBean = get(catalogueServiceEndpoint + GROUPS_LIST, myToken); - if(groupsBean != null){ - + if(groupsBean != null) { + // get list of organizations (a list of names is returned) - JSONArray groups = (JSONArray)groupsBean.get("result"); - - for(int i = 0; i < groups.size(); i++){ - String group = (String)groups.get(i); - System.out.println("Group name is " + group); + JSONArray groups = (JSONArray) groupsBean.get("result"); + + for(int i = 0; i < groups.size(); i++) { + String group = (String) groups.get(i); + System.out.println("Group name is " + group); } - + } - + // now, the interesting part for publishing: we need to check for "profiles" metadata, if any, in the context // Currently, in dev, we have: // Profile name is Test profile and Categories @@ -105,26 +101,26 @@ public class CataloguePublishExample { // Profile name is EOSCService // Profile name is SoBigData.eu: Application Metadata NextNext JSONObject profilesBean = get(catalogueServiceEndpoint + PROFILES_LIST, myToken); - if(profilesBean != null){ - + if(profilesBean != null) { + // get list of organizations (a list of names is returned) - JSONArray profiles = (JSONArray)profilesBean.get("result"); - - for(int i = 0; i < profiles.size(); i++){ - String profile = (String)profiles.get(i); - System.out.println("Profile name is " + profile); + JSONArray profiles = (JSONArray) profilesBean.get("result"); + + for(int i = 0; i < profiles.size(); i++) { + String profile = (String) profiles.get(i); + System.out.println("Profile name is " + profile); } } - + // let's check (because it sounds interesting) the "Empty" profile.. (NOTE: xml is returned here) String emptyProfile = getXML(catalogueServiceEndpoint + GET_SINGLE_PROFILE_XML + "Empty%20Profile", myToken); System.out.println("Empty profile looks like \n"); System.out.println(emptyProfile); - + // result is: // - + // great! Now let's create an item with such profile JSONObject item = new JSONObject(); item.put("name", "my_test_item"); // the name will be part of the uri.. it must be unique @@ -137,21 +133,21 @@ public class CataloguePublishExample { // Note: we have profiles, so we must set an extra with key system:type and a proper value(for instance, "EmptyType"). JSONArray extras = new JSONArray(); JSONObject sysTypeObject = new JSONObject(); - sysTypeObject.put("key","system:type"); - sysTypeObject.put("value","EmptyType"); + sysTypeObject.put("key", "system:type"); + sysTypeObject.put("value", "EmptyType"); JSONObject otherField = new JSONObject(); - otherField.put("key","Temporal Coverage"); - otherField.put("value","whatever"); + otherField.put("key", "Temporal Coverage"); + otherField.put("value", "whatever"); extras.add(sysTypeObject); extras.add(otherField); item.put("extras", extras); item.put("tags", tags); - + JSONObject created = post(catalogueServiceEndpoint + CREATE_ITEM, item, myToken); System.out.println("Result is " + created.toJSONString()); - + } - + /** * Executes an http get request * @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it) @@ -159,26 +155,26 @@ public class CataloguePublishExample { * @return * @throws Exception */ - private static JSONObject get(String url, String token) throws Exception{ - try (CloseableHttpClient httpClient = HttpClientBuilder.create().build()) { - + private static JSONObject get(String url, String token) throws Exception { + try(CloseableHttpClient httpClient = HttpClientBuilder.create().build()) { + HttpGet req = new HttpGet(url); req.setHeader("gcube-token", token); HttpResponse response = httpClient.execute(req); - + if(response.getStatusLine().getStatusCode() != 200) throw new Exception("There was an error while serving the request " + response.getStatusLine()); - + JSONParser parser = new JSONParser(); - JSONObject parsedObject = (JSONObject)parser.parse(EntityUtils.toString(response.getEntity())); + JSONObject parsedObject = (JSONObject) parser.parse(EntityUtils.toString(response.getEntity())); return parsedObject; - - }catch(Exception e){ + + } catch(Exception e) { System.err.println("Error while serving request " + e); throw e; } } - + /** * Executes a post request * @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it) @@ -187,32 +183,32 @@ public class CataloguePublishExample { * @return * @throws Exception */ - private static JSONObject post(String url, JSONObject request, String token) throws Exception{ - - try (CloseableHttpClient httpClient = HttpClientBuilder.create().build()) { - + private static JSONObject post(String url, JSONObject request, String token) throws Exception { + + try(CloseableHttpClient httpClient = HttpClientBuilder.create().build()) { + HttpPost post = new HttpPost(url); post.setHeader("gcube-token", token); - + StringEntity params = new StringEntity(request.toJSONString(), ContentType.APPLICATION_JSON); post.setEntity(params); - + HttpResponse response = httpClient.execute(post); - + if(response.getStatusLine().getStatusCode() != 200) throw new Exception("There was an error while serving the request " + response.getStatusLine()); - + JSONParser parser = new JSONParser(); - JSONObject parsedObject = (JSONObject)parser.parse(EntityUtils.toString(response.getEntity())); + JSONObject parsedObject = (JSONObject) parser.parse(EntityUtils.toString(response.getEntity())); return parsedObject; - - }catch(Exception e){ + + } catch(Exception e) { System.err.println("Error while serving request " + e); throw e; } - + } - + /** * Executes an http get request to fetch an xml data * @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it) @@ -220,19 +216,19 @@ public class CataloguePublishExample { * @return * @throws Exception */ - private static String getXML(String url, String token) throws Exception{ - try (CloseableHttpClient httpClient = HttpClientBuilder.create().build()) { - + private static String getXML(String url, String token) throws Exception { + try(CloseableHttpClient httpClient = HttpClientBuilder.create().build()) { + HttpGet req = new HttpGet(url); req.setHeader("gcube-token", token); HttpResponse response = httpClient.execute(req); - + if(response.getStatusLine().getStatusCode() != 200) throw new Exception("There was an error while serving the request " + response.getStatusLine()); - + return EntityUtils.toString(response.getEntity()); - - }catch(Exception e){ + + } catch(Exception e) { System.err.println("Error while serving request " + e); throw e; } diff --git a/src/test/java/JavaTests.java b/src/test/java/JavaTests.java index 2117108..592d233 100644 --- a/src/test/java/JavaTests.java +++ b/src/test/java/JavaTests.java @@ -4,13 +4,11 @@ import java.util.Collections; import java.util.Date; import java.util.List; -import net.sf.ehcache.Cache; -import net.sf.ehcache.Element; +import javax.cache.Cache; import org.gcube.common.scope.api.ScopeProvider; import org.gcube.datacatalogue.catalogue.beans.resource.CustomField; import org.gcube.datacatalogue.catalogue.utils.CachesManager; -import org.gcube.datacatalogue.catalogue.utils.CatalogueUtils; import org.gcube.datacatalogue.catalogue.utils.Constants; import org.gcube.datacatalogue.metadatadiscovery.DataCalogueMetadataFormatReader; import org.gcube.datacatalogue.metadatadiscovery.bean.MetadataProfile; @@ -20,22 +18,20 @@ import org.json.simple.parser.JSONParser; import org.json.simple.parser.ParseException; import org.junit.Test; - - public class JavaTests { - + //@Test public void testGetMetadataNames() throws Exception { - + ScopeProvider.instance.set("/gcube/devNext/NextNext"); DataCalogueMetadataFormatReader reader = new DataCalogueMetadataFormatReader(); List listProfiles = reader.getListOfMetadataProfiles(); System.out.println("Result is " + listProfiles); - + } - + //@Test - public void testJSONValueCategory(){ + public void testJSONValueCategory() { JSONObject catJsonObj = new JSONObject(); JSONObject value = new JSONObject(); value.put("id", "aaaaa"); @@ -44,102 +40,99 @@ public class JavaTests { catJsonObj.put("qualified_name", value); // TODO check System.out.println(catJsonObj); } - + //@Test - public void testDate(){ - + public void testDate() { + SimpleDateFormat formatter1 = new SimpleDateFormat("yyyy-MM-dd"); SimpleDateFormat formatter2 = new SimpleDateFormat("yyyy-MM-dd HH:mm"); - + String value = "2005-03-01"; - - try{ - + + try { + Date d = formatter2.parse(value); System.out.println("F1 is " + d.toLocaleString()); if(d == null) d = formatter2.parse(value); - - }catch(Exception e){ + + } catch(Exception e) { System.err.println("failed to parse date " + e); } - + } - - + //@Test - public void testSorting(){ - + public void testSorting() { + List toSort = new ArrayList(); - - toSort.add(new CustomField("C", "value1", Integer.MAX_VALUE, 7)); - toSort.add(new CustomField("E", "value1", Integer.MAX_VALUE, 6)); + + toSort.add(new CustomField("C", "value1", Integer.MAX_VALUE, 7)); + toSort.add(new CustomField("E", "value1", Integer.MAX_VALUE, 6)); toSort.add(new CustomField("X", "value1", Integer.MAX_VALUE, 3)); - toSort.add(new CustomField("Z", "value1", 0, 3)); - toSort.add(new CustomField("A", "value2", 1, 2)); - toSort.add(new CustomField("D", "value1", 2, 4)); - toSort.add(new CustomField("B", "value1", 2, 1)); - + toSort.add(new CustomField("Z", "value1", 0, 3)); + toSort.add(new CustomField("A", "value2", 1, 2)); + toSort.add(new CustomField("D", "value1", 2, 4)); + toSort.add(new CustomField("B", "value1", 2, 1)); + Collections.sort(toSort); - + System.out.println("Sorted list " + toSort); } - + //@Test - public void testJsonArray(){ - + public void testJsonArray() { + JSONArray tagsArrayOriginal = new JSONArray(); String tag = ""; tagsArrayOriginal.add(tag); - + System.out.println(tagsArrayOriginal); - + } - - //@Test - public void testEHCache() throws Exception{ - + + @Test + public void testEHCache() throws Exception { + ScopeProvider.instance.set("/gcube/devNext/NextNext"); - - Cache profilesCache = CachesManager.getCache(CachesManager.PROFILES_READERS_CACHE); + + Cache readerCache = CachesManager.getReaderCache(); String context = ScopeProvider.instance.get(); - List toReturn = new ArrayList(); - DataCalogueMetadataFormatReader reader; - if(profilesCache.isKeyInCache(context)) - reader = (DataCalogueMetadataFormatReader) profilesCache.get(context).getObjectValue(); - else{ + if(readerCache.containsKey(context)){ + reader = readerCache.get(context); + }else { reader = new DataCalogueMetadataFormatReader(); - profilesCache.put(new Element(context, reader)); + readerCache.put(context, reader); } - + Thread.sleep(1000 * 60); } - + //@Test - public void testJSONObj() throws Exception{ - + public void testJSONObj() throws Exception { + JSONObject obj = new JSONObject(); obj.put("c", "d"); modifyJSON(obj); System.out.println(obj); } - - private static void modifyJSON(JSONObject obj){ - + + private static void modifyJSON(JSONObject obj) { + obj.put("a", "b"); - + } - + //@Test - public void testJSONParser() throws ParseException{ - + public void testJSONParser() throws ParseException { + String jsonString = "{\"help\": \"https://ckan-d-d4s.d4science.org/api/3/action/help_show?name=package_create\", \"success\": true, \"result\": {\"license_title\": \"License Not Specified\", \"maintainer\": \"Giancarlo Panichi\", \"relationships_as_object\": [], \"private\": false, \"maintainer_email\": \"giancarlo.panichi@isti.cnr.it\", \"num_tags\": 2, \"id\": \"e39990ac-c644-49f4-a8a2-6774c2e69b59\", \"metadata_created\": \"2017-03-31T12:07:23.836973\", \"metadata_modified\": \"2017-03-31T12:07:23.836983\", \"author\": \"Costantino Perciante\", \"author_email\": \"costantino.perciante@isti.cnr.it\", \"state\": \"active\", \"version\": \"1\", \"creator_user_id\": \"ab8189ff-6b07-4963-b36a-c83d53d7e49b\", \"type\": \"dataset\", \"resources\": [{\"mimetype\": null, \"cache_url\": null, \"hash\": \"\", \"description\": \"\", \"name\": \"resource A\", \"format\": \"\", \"url\": \"http://www.test.it\", \"datastore_active\": false, \"cache_last_updated\": null, \"package_id\": \"e39990ac-c644-49f4-a8a2-6774c2e69b59\", \"created\": \"2017-03-31T14:07:23.943698\", \"state\": \"active\", \"mimetype_inner\": null, \"last_modified\": null, \"position\": 0, \"revision_id\": \"687a9a8e-4450-4904-9f54-603e6dc71d54\", \"url_type\": null, \"id\": \"fb0c2e90-bc5e-4028-ae61-8cc799814c4d\", \"resource_type\": null, \"size\": null}], \"num_resources\": 1, \"tags\": [{\"vocabulary_id\": null, \"state\": \"active\", \"display_name\": \"Artifact Name-catalogue-ws\", \"id\": \"5b287a15-ff52-429a-8f24-d5f9a4cc0f42\", \"name\": \"Artifact Name-catalogue-ws\"}, {\"vocabulary_id\": null, \"state\": \"active\", \"display_name\": \"Java\", \"id\": \"ad62fb1a-02f7-4ee5-96f8-50c919866552\", \"name\": \"Java\"}], \"groups\": [], \"license_id\": \"notspecified\", \"relationships_as_subject\": [], \"organization\": {\"description\": \"VRE nextnext\", \"created\": \"2016-06-21T17:29:47.479879\", \"title\": \"NextNext\", \"name\": \"nextnext\", \"is_organization\": true, \"state\": \"active\", \"image_url\": \"\", \"revision_id\": \"12264679-247a-4c40-945d-38607c006d2a\", \"type\": \"organization\", \"id\": \"131d8f52-2566-458b-8bc4-04fb57f2580d\", \"approval_status\": \"approved\"}, \"name\": \"test-web-service-3\", \"isopen\": false, \"url\": null, \"notes\": null, \"owner_org\": \"131d8f52-2566-458b-8bc4-04fb57f2580d\", \"extras\": [{\"key\": \"Field/Scope of use\", \"value\": \"Any use\"}, {\"key\": \"UsageMode\", \"value\": \"Download\"}, {\"key\": \"categoryref:artifact_information:Artifact Name\", \"value\": \"catalogue-ws\"}, {\"key\": \"categoryref:artifact_information:Maven Location\", \"value\": \"http://maven.research-infrastructures.eu/nexus/index.html\"}, {\"key\": \"categoryref:artifact_information:Programming language\", \"value\": \"Java\"}, {\"key\": \"categoryref:developer_information:Identifier\", \"value\": \"costantino.perciante\"}, {\"key\": \"categoryref:extra_information:First Release\", \"value\": \"2017-04-03\"}, {\"key\": \"categoryref:extra_information:Size MB\", \"value\": \"2\"}, {\"key\": \"metadatacategory:artifact_information\", \"value\": \"{\\\"id\\\":\\\"artifact_information\\\",\\\"title\\\":\\\"Artifact Information\\\",\\\"description\\\":\\\"Artifact's main information \\\\t\\\\t\\\"}\"}, {\"key\": \"metadatacategory:developer_information\", \"value\": \"{\\\"id\\\":\\\"developer_information\\\",\\\"title\\\":\\\"Developer Information\\\",\\\"description\\\":\\\"This section is about developer(s) information \\\\t\\\\t\\\"}\"}, {\"key\": \"metadatacategory:extra_information\", \"value\": \"{\\\"id\\\":\\\"extra_information\\\",\\\"title\\\":\\\"Extras\\\",\\\"description\\\":\\\"Other information about the artifact \\\\t\\\\t\\\"}\"}, {\"key\": \"metadatatype\", \"value\": \"software_type\"}, {\"key\": \"spatial\", \"value\": \"{\\\"type\\\": \\\"Point\\\",\\\"coordinates\\\": [-3.145, 53.078]}\"}], \"title\": \"title test from web service-3\", \"revision_id\": \"687a9a8e-4450-4904-9f54-603e6dc71d54\"}}"; - + JSONParser parser = new JSONParser(); - JSONObject obj = (JSONObject)parser.parse(jsonString); - JSONArray tags = (JSONArray)((JSONObject)obj.get(Constants.RESULT_KEY)).get(Constants.TAGS_KEY); + JSONObject obj = (JSONObject) parser.parse(jsonString); + JSONArray tags = (JSONArray) ((JSONObject) obj.get(Constants.RESULT_KEY)).get(Constants.TAGS_KEY); System.out.println("Tags are " + tags); } - + } diff --git a/src/test/java/TestJersey.java b/src/test/java/TestJersey.java index 4e123ca..57c3580 100644 --- a/src/test/java/TestJersey.java +++ b/src/test/java/TestJersey.java @@ -21,9 +21,9 @@ import org.json.simple.JSONObject; import org.slf4j.LoggerFactory; public class TestJersey extends JerseyTest { - + private static final org.slf4j.Logger logger = LoggerFactory.getLogger(TestJersey.class); - + //@Override protected Application configure() { logger.info("Configuring service..."); @@ -32,93 +32,73 @@ public class TestJersey extends JerseyTest { resourceConfig.register(MultiPartFeature.class); return resourceConfig; } - + //@Override public void configureClient(ClientConfig config) { logger.info("Configuring client..."); config.register(MultiPartFeature.class); } - + //@Test @SuppressWarnings("unchecked") public void test() throws ParseException, IOException { - + JSONObject obj = new JSONObject(); obj.put("test", "value"); - final JSONObject createResource = target("api/resources/create/") - .request() - .accept(MediaType.APPLICATION_JSON) + final JSONObject createResource = target("api/resources/create/").request().accept(MediaType.APPLICATION_JSON) .post(Entity.json(obj), JSONObject.class); logger.info(createResource.toJSONString()); } - + //@Test public void testFile() throws ParseException, IOException { - - - FileDataBodyPart fileDataBodyPart = new FileDataBodyPart("uploadFile", + + FileDataBodyPart fileDataBodyPart = new FileDataBodyPart("uploadFile", new File("/Users/costantinoperciante/Desktop/rilascio_tess.doc")); - - final MultiPart multipart = new FormDataMultiPart() - .field("foo", "bar") - .bodyPart(fileDataBodyPart); - - final Response createResource = - target("api/resources/create/") - .request() + + final MultiPart multipart = new FormDataMultiPart().field("foo", "bar").bodyPart(fileDataBodyPart); + + final Response createResource = target("api/resources/create/").request() .post(Entity.entity(multipart, multipart.getMediaType())); logger.info(createResource.toString()); // multipart.close(); } - + //@Test public void testProfilesNames() throws ParseException, IOException { - - - FileDataBodyPart fileDataBodyPart = new FileDataBodyPart("uploadFile", + + FileDataBodyPart fileDataBodyPart = new FileDataBodyPart("uploadFile", new File("/Users/costantinoperciante/Desktop/rilascio_tess.doc")); - - final MultiPart multipart = new FormDataMultiPart() - .field("foo", "bar") - .bodyPart(fileDataBodyPart); - - final Response createResource = - target("api/resources/create/") - .request() + + final MultiPart multipart = new FormDataMultiPart().field("foo", "bar").bodyPart(fileDataBodyPart); + + final Response createResource = target("api/resources/create/").request() .post(Entity.entity(multipart, multipart.getMediaType())); logger.info(createResource.toString()); // multipart.close(); } - + //@Test public void testProfileNames() throws ParseException, IOException { - - final String profiles = - target("api/profiles/profile_names/") - .queryParam("context", "/gcube/devNext/NextNext") - .request() - .get(String.class); - + + final String profiles = target("api/profiles/profile_names/").queryParam("context", "/gcube/devNext/NextNext") + .request().get(String.class); + logger.info("Response is " + profiles); - + } //@Test public void testProfileByName() throws ParseException, IOException { - - final String profiles = - target("api/profiles/profile/") - .queryParam("context", "/gcube/devNext/NextNext") - .queryParam("name", "SoBigData.eu: Dataset Metadata NextNext") - .request(MediaType.APPLICATION_JSON) + + final String profiles = target("api/profiles/profile/").queryParam("context", "/gcube/devNext/NextNext") + .queryParam("name", "SoBigData.eu: Dataset Metadata NextNext").request(MediaType.APPLICATION_JSON) .get(String.class); - + logger.info("Response is " + profiles); - + } - - } diff --git a/src/test/java/org/gcube/datacatalogue/catalogue/ScopedTest.java b/src/test/java/org/gcube/datacatalogue/catalogue/ScopedTest.java new file mode 100644 index 0000000..de928ec --- /dev/null +++ b/src/test/java/org/gcube/datacatalogue/catalogue/ScopedTest.java @@ -0,0 +1,121 @@ +package org.gcube.datacatalogue.catalogue; +/** + * + */ + + +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; + +import org.gcube.common.authorization.client.Constants; +import org.gcube.common.authorization.client.exceptions.ObjectNotFound; +import org.gcube.common.authorization.library.AuthorizationEntry; +import org.gcube.common.authorization.library.provider.AuthorizationProvider; +import org.gcube.common.authorization.library.provider.ClientInfo; +import org.gcube.common.authorization.library.provider.SecurityTokenProvider; +import org.gcube.common.authorization.library.utils.Caller; +import org.gcube.common.scope.api.ScopeProvider; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author Luca Frosini (ISTI - CNR) + * + */ +public class ScopedTest { + + private static final Logger logger = LoggerFactory.getLogger(ScopedTest.class); + + protected static final String PROPERTIES_FILENAME = "token.properties"; + + private static final String GCUBE_VARNAME = "GCUBE"; + public static final String GCUBE; + + private static final String GCUBE_DEVNEXT_VARNAME = "GCUBE_DEVNEXT"; + public static final String GCUBE_DEVNEXT; + + private static final String GCUBE_DEVNEXT_NEXTNEXT_VARNAME = "GCUBE_DEVNEXT_NEXTNEXT"; + public static final String GCUBE_DEVNEXT_NEXTNEXT; + + public static final String GCUBE_DEVSEC_VARNAME = "GCUBE_DEVSEC"; + public static final String GCUBE_DEVSEC; + + public static final String GCUBE_DEVSEC_DEVVRE_VARNAME = "GCUBE_DEVSEC_DEVVRE"; + public static final String GCUBE_DEVSEC_DEVVRE; + + + private static final String GCUBE_DEVNEXT_ANOTHER_USER_VARNAME = "GCUBE_DEVNEXT_ANOTHER_USER"; + public static final String GCUBE_DEVNEXT_ANOTHER_USER; + + private static final String GCUBE_DEVVRE_ANOTHER_USER_VARNAME = "GCUBE_DEVVRE_ANOTHER_USER"; + public static final String GCUBE_DEVVRE_ANOTHER_USER; + + + public static final String DEFAULT_TEST_SCOPE; + public static final String PARENT_DEFAULT_TEST_SCOPE; + public static final String DEFAULT_TEST_SCOPE_ANOTHER_USER; + public static final String ALTERNATIVE_TEST_SCOPE; + + static { + Properties properties = new Properties(); + InputStream input = ScopedTest.class.getClassLoader().getResourceAsStream(PROPERTIES_FILENAME); + + try { + // load the properties file + properties.load(input); + } catch (IOException e) { + throw new RuntimeException(e); + } + + GCUBE = properties.getProperty(GCUBE_VARNAME); + + GCUBE_DEVNEXT = properties.getProperty(GCUBE_DEVNEXT_VARNAME); + GCUBE_DEVNEXT_NEXTNEXT = properties.getProperty(GCUBE_DEVNEXT_NEXTNEXT_VARNAME); + + GCUBE_DEVSEC = properties.getProperty(GCUBE_DEVSEC_VARNAME); + GCUBE_DEVSEC_DEVVRE = properties.getProperty(GCUBE_DEVSEC_DEVVRE_VARNAME); + + GCUBE_DEVNEXT_ANOTHER_USER = properties.getProperty(GCUBE_DEVNEXT_ANOTHER_USER_VARNAME); + GCUBE_DEVVRE_ANOTHER_USER = properties.getProperty(GCUBE_DEVVRE_ANOTHER_USER_VARNAME); + + DEFAULT_TEST_SCOPE = GCUBE_DEVSEC_DEVVRE; + PARENT_DEFAULT_TEST_SCOPE = GCUBE_DEVSEC; + + DEFAULT_TEST_SCOPE_ANOTHER_USER = GCUBE_DEVVRE_ANOTHER_USER; + ALTERNATIVE_TEST_SCOPE = GCUBE; + + } + + public static String getCurrentScope(String token) throws ObjectNotFound, Exception{ + AuthorizationEntry authorizationEntry = Constants.authorizationService().get(token); + String context = authorizationEntry.getContext(); + logger.info("Context of token {} is {}", token, context); + return context; + } + + + public static void setContext(String token) throws ObjectNotFound, Exception{ + SecurityTokenProvider.instance.set(token); + AuthorizationEntry authorizationEntry = Constants.authorizationService().get(token); + ClientInfo clientInfo = authorizationEntry.getClientInfo(); + String qualifier = authorizationEntry.getQualifier(); + Caller caller = new Caller(clientInfo, qualifier); + AuthorizationProvider.instance.set(caller); + ScopeProvider.instance.set(getCurrentScope(token)); + } + + @BeforeClass + public static void beforeClass() throws Exception{ + setContext(DEFAULT_TEST_SCOPE); + } + + @AfterClass + public static void afterClass() throws Exception{ + SecurityTokenProvider.instance.reset(); + ScopeProvider.instance.reset(); + } + +} diff --git a/src/test/java/org/gcube/datacatalogue/catalogue/entities/CatalogueItemTest.java b/src/test/java/org/gcube/datacatalogue/catalogue/entities/CatalogueItemTest.java new file mode 100644 index 0000000..f40ac27 --- /dev/null +++ b/src/test/java/org/gcube/datacatalogue/catalogue/entities/CatalogueItemTest.java @@ -0,0 +1,23 @@ +package org.gcube.datacatalogue.catalogue.entities; + +import org.gcube.datacatalogue.catalogue.ScopedTest; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class CatalogueItemTest extends ScopedTest { + + private static final Logger logger = LoggerFactory.getLogger(CatalogueItemTest.class); + + @Test + public void read() { + String id = "3e7b6924-7851-49fc-a08a-bd8a86d4af62"; + CatalogueItem catalogueItem = new CatalogueItem(); + catalogueItem.setId(id); + + String res = catalogueItem.read(); + logger.debug(res); + + } + +} diff --git a/src/test/resources/logback-test.xml b/src/test/resources/logback-test.xml new file mode 100644 index 0000000..362aa73 --- /dev/null +++ b/src/test/resources/logback-test.xml @@ -0,0 +1,19 @@ + + + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{0}: %msg%n + + + + + + + + + + + + \ No newline at end of file