Merged from private branch
git-svn-id: https://svn.d4science.research-infrastructures.eu/gcube/trunk/data-publishing/gcat@176439 82a268e6-3cf1-43bd-a215-b396298e98cf
This commit is contained in:
parent
42badcda3e
commit
f21a714851
|
@ -21,7 +21,6 @@ Authors
|
||||||
--------------------------------------------------
|
--------------------------------------------------
|
||||||
|
|
||||||
* Luca Frosini (luca.frosini-AT-isti.cnr.it), Istituto di Scienza e Tecnologie dell'Informazione "A. Faedo" - CNR, Pisa (Italy).
|
* Luca Frosini (luca.frosini-AT-isti.cnr.it), Istituto di Scienza e Tecnologie dell'Informazione "A. Faedo" - CNR, Pisa (Italy).
|
||||||
* Costantino Perciante (costantino.perciante@isti.cnr.it), Istituto di Scienza e Tecnologie dell'Informazione "A. Faedo" - CNR, Pisa (Italy).
|
|
||||||
|
|
||||||
Maintainers
|
Maintainers
|
||||||
-----------
|
-----------
|
||||||
|
|
|
@ -1,31 +1,7 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!DOCTYPE xml>
|
<!DOCTYPE xml>
|
||||||
<ReleaseNotes>
|
<ReleaseNotes>
|
||||||
<Changeset component="org.gcube.data-catalogue.catalogue-ws.1-4-0" date="${buildDate}">
|
<Changeset component="org.gcube.data-publishing.gcat.1-0-0" date="${buildDate}">
|
||||||
<Change></Change>
|
|
||||||
</Changeset>
|
|
||||||
<Changeset component="org.gcube.data-catalogue.catalogue-ws.1-3-0" date="2018-10-10">
|
|
||||||
<Change>Complete refactoring of code</Change>
|
|
||||||
<Change>Item Port type is now RESTful (old methods are still allowed)</Change>
|
|
||||||
<Change>Added update support for Item #11516</Change>
|
|
||||||
<Change>Changed caching mechanism from ehcache API to JSR-107. Ehcache is still used as runtime library.</Change>
|
|
||||||
<Change>Solved random NullPointer Exception on catalogue-ws related to old caching mechanism #11466</Change>
|
|
||||||
<Change>Fixed normalization of the organization name #12506</Change>
|
|
||||||
<Change>Added the possibility to deny social post on catalogue-ws #12514</Change>
|
|
||||||
</Changeset>
|
|
||||||
<Changeset component="org.gcube.data-catalogue.catalogue-ws.1-1-1"
|
|
||||||
date="2018-01-11">
|
|
||||||
<Change>Item purge method enhanced</Change>
|
|
||||||
</Changeset>
|
|
||||||
<Changeset component="org.gcube.data-catalogue.catalogue-ws.1-1-0"
|
|
||||||
date="2017-06-20">
|
|
||||||
<Change>Minor fixes while checking user's permissions</Change>
|
|
||||||
<Change>Namespaces are no longer transparently managed</Change>
|
|
||||||
<Change>Fixed 'default' value for metadata</Change>
|
|
||||||
<Change>Improved exception handling</Change>
|
|
||||||
</Changeset>
|
|
||||||
<Changeset component="org.gcube.data-catalogue.catalogue-ws.1-0-0"
|
|
||||||
date="2017-05-01">
|
|
||||||
<Change>First Release</Change>
|
<Change>First Release</Change>
|
||||||
</Changeset>
|
</Changeset>
|
||||||
</ReleaseNotes>
|
</ReleaseNotes>
|
||||||
|
|
30
pom.xml
30
pom.xml
|
@ -34,11 +34,6 @@
|
||||||
<type>pom</type>
|
<type>pom</type>
|
||||||
<scope>import</scope>
|
<scope>import</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>org.gcube.common</groupId>
|
|
||||||
<artifactId>gxRest</artifactId>
|
|
||||||
<version>1.0.1-SNAPSHOT</version>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</dependencyManagement>
|
</dependencyManagement>
|
||||||
|
|
||||||
|
@ -52,9 +47,9 @@
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<scm>
|
<scm>
|
||||||
<connection>scm:https://svn.d4science.research-infrastructures.eu/gcube/trunk/data-catalogue/${project.artifactId}</connection>
|
<connection>scm:https://svn.d4science.research-infrastructures.eu/gcube/trunk/data-publishing/${project.artifactId}</connection>
|
||||||
<developerConnection>scm:https://svn.d4science.research-infrastructures.eu/gcube//trunk/data-catalogue/${project.artifactId}</developerConnection>
|
<developerConnection>scm:https://svn.d4science.research-infrastructures.eu/gcube//trunk/data-publishing/${project.artifactId}</developerConnection>
|
||||||
<url>https://svn.d4science.research-infrastructures.eu/gcube/trunk/data-catalogue/${project.artifactId}</url>
|
<url>https://svn.d4science.research-infrastructures.eu/gcube/trunk/data-publishing/${project.artifactId}</url>
|
||||||
</scm>
|
</scm>
|
||||||
|
|
||||||
|
|
||||||
|
@ -144,6 +139,14 @@
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.gcube.common</groupId>
|
||||||
|
<artifactId>gxRest</artifactId>
|
||||||
|
<version>[1.0.0-SNAPSHOT,2.0.0-SNAPSHOT)</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
<!-- Libraries explicitly forced to provided -->
|
<!-- Libraries explicitly forced to provided -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.fasterxml.jackson.core</groupId>
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
|
@ -233,15 +236,14 @@
|
||||||
<version>20140107</version>
|
<version>20140107</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.gcube.data-publishing</groupId>
|
||||||
|
<artifactId>storagehub-application-persistence</artifactId>
|
||||||
|
<version>[1.0.0-SNAPSHOT,2.0.0-SNAPSHOT)</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
<!-- Test libraries -->
|
<!-- Test libraries -->
|
||||||
<dependency>
|
|
||||||
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
|
|
||||||
<artifactId>jersey-test-framework-provider-grizzly2</artifactId>
|
|
||||||
<version>${version.jersey}</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>junit</groupId>
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>junit</artifactId>
|
||||||
|
|
|
@ -8,37 +8,36 @@ import javax.cache.expiry.CreatedExpiryPolicy;
|
||||||
import javax.cache.expiry.Duration;
|
import javax.cache.expiry.Duration;
|
||||||
import javax.cache.spi.CachingProvider;
|
import javax.cache.spi.CachingProvider;
|
||||||
|
|
||||||
import org.gcube.datacatalogue.metadatadiscovery.DataCalogueMetadataFormatReader;
|
// import org.gcube.datacatalogue.metadatadiscovery.DataCalogueMetadataFormatReader;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle caches via Ehcache stuff.
|
|
||||||
* @author Costantino Perciante (ISTI - CNR)
|
* @author Costantino Perciante (ISTI - CNR)
|
||||||
* @author Luca Frosini (ISTI - CNR)
|
* @author Luca Frosini (ISTI - CNR)
|
||||||
*/
|
*/
|
||||||
public class CachesManager {
|
public class CachesManager {
|
||||||
|
|
||||||
// the following caches are declared within the ehcache.xml (no default is available, so pay attention)
|
// 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_READERS_CACHE = "profile_readers";
|
||||||
public static final String PROFILES_USERS_CACHE = "profile_users";
|
public static final String PROFILES_USERS_CACHE = "profile_users";
|
||||||
|
|
||||||
private static final CacheManager cacheManager;
|
private static final CacheManager cacheManager;
|
||||||
private static final Cache<String, DataCalogueMetadataFormatReader> readerCache;
|
// private static final Cache<String, DataCalogueMetadataFormatReader> readerCache;
|
||||||
private static final Cache<String, JsonNode> userCache;
|
private static final Cache<String, JsonNode> userCache;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
CachingProvider provider = Caching.getCachingProvider();
|
CachingProvider provider = Caching.getCachingProvider();
|
||||||
cacheManager = provider.getCacheManager();
|
cacheManager = provider.getCacheManager();
|
||||||
|
|
||||||
|
/*
|
||||||
MutableConfiguration<String, DataCalogueMetadataFormatReader> readerConfiguration =
|
MutableConfiguration<String, DataCalogueMetadataFormatReader> readerConfiguration =
|
||||||
new MutableConfiguration<String, DataCalogueMetadataFormatReader>()
|
new MutableConfiguration<String, DataCalogueMetadataFormatReader>()
|
||||||
.setTypes(String.class, DataCalogueMetadataFormatReader.class)
|
.setTypes(String.class, DataCalogueMetadataFormatReader.class)
|
||||||
.setStoreByValue(false)
|
.setStoreByValue(false)
|
||||||
.setExpiryPolicyFactory(CreatedExpiryPolicy.factoryOf(Duration.ONE_MINUTE));
|
.setExpiryPolicyFactory(CreatedExpiryPolicy.factoryOf(Duration.ONE_MINUTE));
|
||||||
readerCache = cacheManager.createCache(PROFILES_READERS_CACHE, readerConfiguration);
|
readerCache = cacheManager.createCache(PROFILES_READERS_CACHE, readerConfiguration);
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
MutableConfiguration<String, JsonNode> userConfiguration =
|
MutableConfiguration<String, JsonNode> userConfiguration =
|
||||||
new MutableConfiguration<String, JsonNode>()
|
new MutableConfiguration<String, JsonNode>()
|
||||||
|
@ -50,9 +49,11 @@ public class CachesManager {
|
||||||
|
|
||||||
private CachesManager() {}
|
private CachesManager() {}
|
||||||
|
|
||||||
|
/*
|
||||||
public static Cache<String, DataCalogueMetadataFormatReader> getReaderCache() {
|
public static Cache<String, DataCalogueMetadataFormatReader> getReaderCache() {
|
||||||
return readerCache;
|
return readerCache;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
public static Cache<String, JsonNode> getUserCache() {
|
public static Cache<String, JsonNode> getUserCache() {
|
||||||
return userCache;
|
return userCache;
|
||||||
|
|
|
@ -16,8 +16,6 @@ import javax.ws.rs.BadRequestException;
|
||||||
import org.apache.commons.lang.math.NumberUtils;
|
import org.apache.commons.lang.math.NumberUtils;
|
||||||
import org.gcube.common.scope.api.ScopeProvider;
|
import org.gcube.common.scope.api.ScopeProvider;
|
||||||
import org.gcube.datacatalogue.ckanutillibrary.server.utils.CatalogueUtilMethods;
|
import org.gcube.datacatalogue.ckanutillibrary.server.utils.CatalogueUtilMethods;
|
||||||
import org.gcube.datacatalogue.metadatadiscovery.DataCalogueMetadataFormatReader;
|
|
||||||
import org.gcube.datacatalogue.metadatadiscovery.bean.MetadataProfile;
|
|
||||||
import org.gcube.datacatalogue.metadatadiscovery.bean.jaxb.DataType;
|
import org.gcube.datacatalogue.metadatadiscovery.bean.jaxb.DataType;
|
||||||
import org.gcube.datacatalogue.metadatadiscovery.bean.jaxb.MetadataField;
|
import org.gcube.datacatalogue.metadatadiscovery.bean.jaxb.MetadataField;
|
||||||
import org.gcube.datacatalogue.metadatadiscovery.bean.jaxb.MetadataFormat;
|
import org.gcube.datacatalogue.metadatadiscovery.bean.jaxb.MetadataFormat;
|
||||||
|
@ -27,8 +25,7 @@ import org.gcube.datacatalogue.metadatadiscovery.bean.jaxb.NamespaceCategory;
|
||||||
import org.gcube.gcat.persistence.ckan.CKAN;
|
import org.gcube.gcat.persistence.ckan.CKAN;
|
||||||
import org.gcube.gcat.persistence.ckan.CKANPackage;
|
import org.gcube.gcat.persistence.ckan.CKANPackage;
|
||||||
import org.gcube.gcat.persistence.ckan.CKANUtility;
|
import org.gcube.gcat.persistence.ckan.CKANUtility;
|
||||||
import org.gcube.gcat.rest.Namespace;
|
import org.gcube.gcat.profile.MetadataUtility;
|
||||||
import org.gcube.gcat.rest.Profile;
|
|
||||||
import org.gcube.gcat.social.SocialService;
|
import org.gcube.gcat.social.SocialService;
|
||||||
import org.geojson.GeoJsonObject;
|
import org.geojson.GeoJsonObject;
|
||||||
import org.json.simple.JSONArray;
|
import org.json.simple.JSONArray;
|
||||||
|
@ -66,12 +63,11 @@ public class Validator {
|
||||||
return jsonObject;
|
return jsonObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void validateAgainstProfile(String json, List<String> profiles) throws Exception {
|
public static void validateAgainstProfile(String json) throws Exception {
|
||||||
JSONObject jsonObject = getJSONObject(json);
|
JSONObject jsonObject = getJSONObject(json);
|
||||||
validateAgainstProfile(jsonObject, profiles);
|
validateAgainstProfile(jsonObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method validate the incoming json dataset wrt a metadata profile
|
* This method validate the incoming json dataset wrt a metadata profile
|
||||||
* @param json
|
* @param json
|
||||||
|
@ -80,14 +76,14 @@ public class Validator {
|
||||||
* @return
|
* @return
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public static void validateAgainstProfile(JSONObject obj, List<String> profiles) throws Exception {
|
public static void validateAgainstProfile(JSONObject obj) throws Exception {
|
||||||
|
|
||||||
JSONArray extrasArrayOriginal = (JSONArray) obj.get(CKANPackage.EXTRA_TYPES_KEY);
|
JSONArray extrasArrayOriginal = (JSONArray) obj.get(CKANPackage.EXTRA_TYPES_KEY);
|
||||||
JSONArray groupsArrayOriginal = (JSONArray) obj.get(CKANPackage.GROUPS_KEY);
|
JSONArray groupsArrayOriginal = (JSONArray) obj.get(CKANPackage.GROUPS_KEY);
|
||||||
JSONArray tagsArrayOriginal = (JSONArray) obj.get(CKANPackage.TAGS_KEY);
|
JSONArray tagsArrayOriginal = (JSONArray) obj.get(CKANPackage.TAGS_KEY);
|
||||||
|
|
||||||
if(extrasArrayOriginal == null || extrasArrayOriginal.isEmpty()) {
|
if(extrasArrayOriginal == null || extrasArrayOriginal.isEmpty()) {
|
||||||
throw new Exception("'extras' field is missing in context where metadata profile(s) are defined!");
|
throw new BadRequestException("'extras' field is missing in context where metadata profile(s) are defined!");
|
||||||
}
|
}
|
||||||
|
|
||||||
if(groupsArrayOriginal == null) {
|
if(groupsArrayOriginal == null) {
|
||||||
|
@ -115,26 +111,18 @@ public class Validator {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(metadataTypeCF == null) {
|
if(metadataTypeCF == null) {
|
||||||
throw new Exception("'" + CKANPackage.EXTRA_TYPES_KEY_VALUE_SYSTEM_TYPE
|
throw new BadRequestException("'" + CKANPackage.EXTRA_TYPES_KEY_VALUE_SYSTEM_TYPE
|
||||||
+ "' extra field is missing in context where metadata profile(s) are defined!");
|
+ "' extra field is missing in context where metadata profile(s) are defined!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String profileName = metadataTypeCF.getValue();
|
||||||
// fetch the profile by metadata type specified above
|
// fetch the profile by metadata type specified above
|
||||||
MetadataFormat profile = null;
|
MetadataUtility metadataUtility = MetadataUtility.getInstance();
|
||||||
for(String profileName : profiles) {
|
MetadataFormat profile = metadataUtility.getMetadataFormat(profileName);
|
||||||
profile = Validator.getMetadataProfile(profileName);
|
|
||||||
if(profile.getType().equals(metadataTypeCF.getValue())) {
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
profile = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(profile == null) {
|
if(profile == null) {
|
||||||
throw new Exception("'" + CKANPackage.EXTRA_TYPES_KEY_VALUE_SYSTEM_TYPE
|
throw new BadRequestException("'" + CKANPackage.EXTRA_TYPES_KEY_VALUE_SYSTEM_TYPE + "' extra field's value ('"
|
||||||
+ "' extra field's value ('" + metadataTypeCF.getValue() +
|
+ profileName
|
||||||
"') specified as custom field doesn't match any of the profiles defined in this context!");
|
+ "') specified as custom field doesn't match any of the profiles defined in this context!");
|
||||||
} else {
|
} else {
|
||||||
JSONArray extrasArrayUpdated = null;
|
JSONArray extrasArrayUpdated = null;
|
||||||
List<MetadataField> metadataFields = profile.getMetadataFields();
|
List<MetadataField> metadataFields = profile.getMetadataFields();
|
||||||
|
@ -144,7 +132,7 @@ public class Validator {
|
||||||
} else {
|
} else {
|
||||||
extrasArrayUpdated = new JSONArray();
|
extrasArrayUpdated = new JSONArray();
|
||||||
|
|
||||||
List<NamespaceCategory> categories = Namespace.getNamespaceCategories();
|
List<NamespaceCategory> categories = metadataUtility.getNamespaceCategories();
|
||||||
logger.debug("Retrieved namespaces are {}", categories);
|
logger.debug("Retrieved namespaces are {}", categories);
|
||||||
List<String> categoriesIds = new ArrayList<String>(categories == null ? 0 : categories.size());
|
List<String> categoriesIds = new ArrayList<String>(categories == null ? 0 : categories.size());
|
||||||
if(categories == null || categories.isEmpty()) {
|
if(categories == null || categories.isEmpty()) {
|
||||||
|
@ -196,7 +184,7 @@ public class Validator {
|
||||||
+ " times and its lower bound is " + lowerBound + " and upper bound " + upperBound);
|
+ " times and its lower bound is " + lowerBound + " and upper bound " + upperBound);
|
||||||
|
|
||||||
if(inserted < lowerBound || inserted > upperBound) {
|
if(inserted < lowerBound || inserted > upperBound) {
|
||||||
throw new Exception("Field with key '" + entry.getKey()
|
throw new BadRequestException("Field with key '" + entry.getKey()
|
||||||
+ "' is mandatory, but it's not present among the provided fields or its cardinality is not respected ([min = "
|
+ "' is mandatory, but it's not present among the provided fields or its cardinality is not respected ([min = "
|
||||||
+ lowerBound + ", max=" + upperBound + "]).");
|
+ lowerBound + ", max=" + upperBound + "]).");
|
||||||
}
|
}
|
||||||
|
@ -204,7 +192,7 @@ public class Validator {
|
||||||
|
|
||||||
// if there are no tags, throw an exception
|
// 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!");
|
throw new BadRequestException("Please define at least one tag for this item!");
|
||||||
}
|
}
|
||||||
|
|
||||||
// sort validated custom fields and add to the extrasArrayUpdated json array
|
// sort validated custom fields and add to the extrasArrayUpdated json array
|
||||||
|
@ -422,7 +410,8 @@ public class Validator {
|
||||||
JSONObject group = new JSONObject();
|
JSONObject group = new JSONObject();
|
||||||
group.put("name", CatalogueUtilMethods.fromGroupTitleToName(title));
|
group.put("name", CatalogueUtilMethods.fromGroupTitleToName(title));
|
||||||
if(propagateUp) {
|
if(propagateUp) {
|
||||||
List<String> parents = Validator.getGroupHierarchyNames(CatalogueUtilMethods.fromGroupTitleToName(title));
|
List<String> parents = Validator
|
||||||
|
.getGroupHierarchyNames(CatalogueUtilMethods.fromGroupTitleToName(title));
|
||||||
for(String parent : parents) {
|
for(String parent : parents) {
|
||||||
JSONObject groupP = new JSONObject();
|
JSONObject groupP = new JSONObject();
|
||||||
groupP.put("name", parent);
|
groupP.put("name", parent);
|
||||||
|
@ -464,7 +453,7 @@ public class Validator {
|
||||||
|
|
||||||
if((value == null || value.isEmpty()))
|
if((value == null || value.isEmpty()))
|
||||||
if(metadataField.getMandatory() || hasControlledVocabulary)
|
if(metadataField.getMandatory() || hasControlledVocabulary)
|
||||||
throw new Exception("Mandatory field with name '" + key
|
throw new BadRequestException("Mandatory field with name '" + key
|
||||||
+ "' doesn't have a value but it is mandatory or has a controlled vocabulary!");
|
+ "' doesn't have a value but it is mandatory or has a controlled vocabulary!");
|
||||||
else {
|
else {
|
||||||
if(defaultValue != null && !defaultValue.isEmpty()) {
|
if(defaultValue != null && !defaultValue.isEmpty()) {
|
||||||
|
@ -480,7 +469,7 @@ public class Validator {
|
||||||
case Text:
|
case Text:
|
||||||
|
|
||||||
if(regex != null && !value.matches(regex))
|
if(regex != null && !value.matches(regex))
|
||||||
throw new Exception("Field with key '" + key + "' doesn't match the provided regular expression ("
|
throw new BadRequestException("Field with key '" + key + "' doesn't match the provided regular expression ("
|
||||||
+ regex + ")!");
|
+ regex + ")!");
|
||||||
|
|
||||||
if(hasControlledVocabulary) {
|
if(hasControlledVocabulary) {
|
||||||
|
@ -498,7 +487,7 @@ public class Validator {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!match)
|
if(!match)
|
||||||
throw new Exception("Field with key '" + key + "' has a value '" + value
|
throw new BadRequestException("Field with key '" + key + "' has a value '" + value
|
||||||
+ "' but it doesn't match any of the vocabulary's values (" + valuesVocabulary + ")!");
|
+ "' but it doesn't match any of the vocabulary's values (" + valuesVocabulary + ")!");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -507,7 +496,7 @@ public class Validator {
|
||||||
case Time:
|
case Time:
|
||||||
|
|
||||||
if(!isValidDate(value))
|
if(!isValidDate(value))
|
||||||
throw new Exception("Field with key '" + key + "' doesn't seem a valid time!");
|
throw new BadRequestException("Field with key '" + key + "' doesn't seem a valid time!");
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case Time_Interval:
|
case Time_Interval:
|
||||||
|
@ -516,7 +505,7 @@ public class Validator {
|
||||||
for(int i = 0; i < timeValues.length; i++) {
|
for(int i = 0; i < timeValues.length; i++) {
|
||||||
String time = timeValues[i];
|
String time = timeValues[i];
|
||||||
if(!isValidDate(time))
|
if(!isValidDate(time))
|
||||||
throw new Exception("Field with key '" + key + "' doesn't seem a valid time interval!");
|
throw new BadRequestException("Field with key '" + key + "' doesn't seem a valid time interval!");
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -526,11 +515,11 @@ public class Validator {
|
||||||
for(int i = 0; i < timeIntervals.length; i++) {
|
for(int i = 0; i < timeIntervals.length; i++) {
|
||||||
String[] timeIntervalValues = timeIntervals[i].split("/");
|
String[] timeIntervalValues = timeIntervals[i].split("/");
|
||||||
if(timeIntervalValues.length > 2)
|
if(timeIntervalValues.length > 2)
|
||||||
throw new Exception("Field with key '" + key + "' doesn't seem a valid list of times!");
|
throw new BadRequestException("Field with key '" + key + "' doesn't seem a valid list of times!");
|
||||||
for(i = 0; i < timeIntervalValues.length; i++) {
|
for(i = 0; i < timeIntervalValues.length; i++) {
|
||||||
String time = timeIntervalValues[i];
|
String time = timeIntervalValues[i];
|
||||||
if(!isValidDate(time))
|
if(!isValidDate(time))
|
||||||
throw new Exception("Field with key '" + key + "' doesn't seem a valid list of times!");
|
throw new BadRequestException("Field with key '" + key + "' doesn't seem a valid list of times!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -540,13 +529,13 @@ public class Validator {
|
||||||
if(value.equalsIgnoreCase("true") || value.equalsIgnoreCase("false")) {
|
if(value.equalsIgnoreCase("true") || value.equalsIgnoreCase("false")) {
|
||||||
|
|
||||||
} else
|
} else
|
||||||
throw new Exception("Field with key '" + key + "' doesn't seem a valid boolean value!");
|
throw new BadRequestException("Field with key '" + key + "' doesn't seem a valid boolean value!");
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case Number:
|
case Number:
|
||||||
|
|
||||||
if(!NumberUtils.isNumber(value))
|
if(!NumberUtils.isNumber(value))
|
||||||
throw new Exception("Field's value with key '" + key + "' is not a valid number!");
|
throw new BadRequestException("Field's value with key '" + key + "' is not a valid number!");
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case GeoJSON:
|
case GeoJSON:
|
||||||
|
@ -554,7 +543,7 @@ public class Validator {
|
||||||
try {
|
try {
|
||||||
new ObjectMapper().readValue(fieldToValidate.getValue(), GeoJsonObject.class);
|
new ObjectMapper().readValue(fieldToValidate.getValue(), GeoJsonObject.class);
|
||||||
} catch(Exception e) {
|
} catch(Exception e) {
|
||||||
throw new Exception("GeoJSON field with key '" + key + "' seems not valid!");
|
throw new BadRequestException("GeoJSON field with key '" + key + "' seems not valid!");
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -607,27 +596,4 @@ public class Validator {
|
||||||
return toReturn;
|
return toReturn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 {
|
|
||||||
|
|
||||||
DataCalogueMetadataFormatReader reader = Profile.getDataCalogueMetadataFormatReader();
|
|
||||||
List<MetadataProfile> listProfiles = reader.getListOfMetadataProfiles();
|
|
||||||
|
|
||||||
if(listProfiles != null && !listProfiles.isEmpty()) {
|
|
||||||
for(MetadataProfile profile : listProfiles) {
|
|
||||||
if(profile.getName().equals(profileName)) {
|
|
||||||
return reader.getMetadataFormatForMetadataProfile(profile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
package org.gcube.gcat.persistence.ckan;
|
package org.gcube.gcat.persistence.ckan;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
@ -10,12 +15,13 @@ import javax.ws.rs.NotAuthorizedException;
|
||||||
import javax.ws.rs.NotFoundException;
|
import javax.ws.rs.NotFoundException;
|
||||||
import javax.ws.rs.WebApplicationException;
|
import javax.ws.rs.WebApplicationException;
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
|
import javax.ws.rs.core.Response.Status;
|
||||||
|
|
||||||
|
import org.gcube.common.gxhttp.request.GXHTTPStringRequest;
|
||||||
import org.gcube.datacatalogue.ckanutillibrary.server.DataCatalogue;
|
import org.gcube.datacatalogue.ckanutillibrary.server.DataCatalogue;
|
||||||
import org.gcube.datacatalogue.ckanutillibrary.server.DataCatalogueFactory;
|
import org.gcube.datacatalogue.ckanutillibrary.server.DataCatalogueFactory;
|
||||||
|
import org.gcube.gcat.utils.Constants;
|
||||||
import org.gcube.gcat.utils.ContextUtility;
|
import org.gcube.gcat.utils.ContextUtility;
|
||||||
import org.gcube.gcat.utils.HTTPCall;
|
|
||||||
import org.gcube.gcat.utils.HTTPCall.HTTPMETHOD;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
@ -43,6 +49,9 @@ public abstract class CKAN {
|
||||||
protected static final String RESULT_KEY = "result";
|
protected static final String RESULT_KEY = "result";
|
||||||
protected static final String SUCCESS_KEY = "success";
|
protected static final String SUCCESS_KEY = "success";
|
||||||
|
|
||||||
|
public static final String LIMIT_KEY = "limit";
|
||||||
|
public static final String OFFSET_KEY = "offset";
|
||||||
|
|
||||||
protected static final String NOT_FOUND_ERROR = "Not Found Error";
|
protected static final String NOT_FOUND_ERROR = "Not Found Error";
|
||||||
protected static final String AUTHORIZATION_ERROR = "Authorization Error";
|
protected static final String AUTHORIZATION_ERROR = "Authorization Error";
|
||||||
protected static final String VALIDATION_ERROR = "Validation Error";
|
protected static final String VALIDATION_ERROR = "Validation Error";
|
||||||
|
@ -53,6 +62,8 @@ public abstract class CKAN {
|
||||||
// ckan header authorization
|
// ckan header authorization
|
||||||
public final static String AUTH_CKAN_HEADER = "Authorization";
|
public final static String AUTH_CKAN_HEADER = "Authorization";
|
||||||
|
|
||||||
|
public final static String NAME_REGEX = "^[a-z0-9_\\\\-]{2,100}$";
|
||||||
|
|
||||||
protected String LIST;
|
protected String LIST;
|
||||||
protected String CREATE;
|
protected String CREATE;
|
||||||
protected String READ;
|
protected String READ;
|
||||||
|
@ -68,24 +79,24 @@ public abstract class CKAN {
|
||||||
protected String apiKey;
|
protected String apiKey;
|
||||||
|
|
||||||
protected JsonNode result;
|
protected JsonNode result;
|
||||||
|
|
||||||
|
|
||||||
|
protected String nameRegex;
|
||||||
|
|
||||||
public String getApiKey() {
|
public String getApiKey() {
|
||||||
if(apiKey==null) {
|
if(apiKey == null) {
|
||||||
try {
|
try {
|
||||||
return CKANUtility.getApiKey();
|
return CKANUtility.getApiKey();
|
||||||
}catch (Exception e) {
|
} catch(Exception e) {
|
||||||
throw new InternalServerErrorException(e);
|
throw new InternalServerErrorException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return apiKey;
|
return apiKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setApiKey(String apiKey) {
|
public void setApiKey(String apiKey) {
|
||||||
this.apiKey = apiKey;
|
this.apiKey = apiKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
@ -106,7 +117,8 @@ public abstract class CKAN {
|
||||||
try {
|
try {
|
||||||
this.mapper = new ObjectMapper();
|
this.mapper = new ObjectMapper();
|
||||||
this.dataCatalogue = getCatalogue();
|
this.dataCatalogue = getCatalogue();
|
||||||
}catch (Exception e) {
|
this.nameRegex = CKAN.NAME_REGEX;
|
||||||
|
} catch(Exception e) {
|
||||||
throw new InternalServerErrorException(e);
|
throw new InternalServerErrorException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -130,7 +142,6 @@ public abstract class CKAN {
|
||||||
return DataCatalogueFactory.getFactory().getUtilsPerScope(context);
|
return DataCatalogueFactory.getFactory().getUtilsPerScope(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate the CKAN response and return the
|
* Validate the CKAN response and return the
|
||||||
* @param json
|
* @param json
|
||||||
|
@ -150,7 +161,6 @@ public abstract class CKAN {
|
||||||
throw new BadRequestException(getAsString(error));
|
throw new BadRequestException(getAsString(error));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
String message = error.get(MESSAGE_KEY).asText();
|
String message = error.get(MESSAGE_KEY).asText();
|
||||||
|
|
||||||
if(errorType.compareTo(NOT_FOUND_ERROR) == 0) {
|
if(errorType.compareTo(NOT_FOUND_ERROR) == 0) {
|
||||||
|
@ -161,8 +171,6 @@ public abstract class CKAN {
|
||||||
throw new NotAuthorizedException(message);
|
throw new NotAuthorizedException(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// TODO parse more cases
|
// TODO parse more cases
|
||||||
} catch(WebApplicationException e) {
|
} catch(WebApplicationException e) {
|
||||||
throw e;
|
throw e;
|
||||||
|
@ -185,14 +193,18 @@ public abstract class CKAN {
|
||||||
protected JsonNode checkName(JsonNode jsonNode) {
|
protected JsonNode checkName(JsonNode jsonNode) {
|
||||||
try {
|
try {
|
||||||
String gotName = jsonNode.get(NAME_KEY).asText();
|
String gotName = jsonNode.get(NAME_KEY).asText();
|
||||||
if(name==null) {
|
if(!gotName.matches(nameRegex)) {
|
||||||
|
throw new BadRequestException("The 'name' must be between 2 and 100 characters long and contain only lowercase alphanumeric characters, '-' and '_'. You can validate your name using the regular expression : " + NAME_REGEX);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(name == null) {
|
||||||
name = gotName;
|
name = gotName;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(gotName != null && gotName.compareTo(name) != 0) {
|
if(gotName != null && gotName.compareTo(name) != 0) {
|
||||||
String error = String.format(
|
String error = String.format(
|
||||||
"The name (%s) does not match with the '%s' contained in the provided content (%s).",
|
"The name (%s) does not match with the '%s' contained in the provided content (%s).", name,
|
||||||
name, NAME_KEY, gotName);
|
NAME_KEY, gotName);
|
||||||
throw new BadRequestException(error);
|
throw new BadRequestException(error);
|
||||||
}
|
}
|
||||||
return jsonNode;
|
return jsonNode;
|
||||||
|
@ -229,35 +241,83 @@ public abstract class CKAN {
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
public JsonNode sendRequest(HTTPMETHOD httpMethod, String path, Map<String,String> parameters, String body) {
|
protected StringBuilder getStringBuilder(InputStream inputStream) throws IOException {
|
||||||
String catalogueURL = dataCatalogue.getCatalogueUrl().endsWith("/") ? dataCatalogue.getCatalogueUrl() : dataCatalogue.getCatalogueUrl() + "/";
|
StringBuilder result = new StringBuilder();
|
||||||
HTTPCall httpCall = new HTTPCall(catalogueURL);
|
try(BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
|
||||||
httpCall.setgCubeTargetService(false);
|
String line;
|
||||||
httpCall.addHeader(AUTH_CKAN_HEADER, getApiKey());
|
while((line = reader.readLine()) != null) {
|
||||||
String ret = httpCall.call(path, httpMethod, parameters, body, MediaType.APPLICATION_JSON);
|
result.append(line);
|
||||||
JsonNode result = validateCKANResponse(ret);
|
}
|
||||||
if(result instanceof NullNode) {
|
|
||||||
result = mapper.createObjectNode();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String sendGetRequest(String path, Map<String,String> parameters) {
|
protected GXHTTPStringRequest getGXHTTPStringRequest(String path) throws UnsupportedEncodingException {
|
||||||
result = sendRequest(HTTPMETHOD.GET, path, parameters, null);
|
String catalogueURL = dataCatalogue.getCatalogueUrl();
|
||||||
|
GXHTTPStringRequest gxhttpStringRequest = GXHTTPStringRequest.newRequest(catalogueURL);
|
||||||
|
gxhttpStringRequest.from(Constants.CATALOGUE_NAME);
|
||||||
|
gxhttpStringRequest.header("Content-type", MediaType.APPLICATION_JSON);
|
||||||
|
gxhttpStringRequest.isExternalCall(true);
|
||||||
|
gxhttpStringRequest.header(AUTH_CKAN_HEADER, getApiKey());
|
||||||
|
gxhttpStringRequest.path(path);
|
||||||
|
return gxhttpStringRequest;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getResultAsString(HttpURLConnection httpURLConnection) throws IOException {
|
||||||
|
int responseCode = httpURLConnection.getResponseCode();
|
||||||
|
if(responseCode >= Status.BAD_REQUEST.getStatusCode()) {
|
||||||
|
Status status = Status.fromStatusCode(responseCode);
|
||||||
|
throw new WebApplicationException(status);
|
||||||
|
}
|
||||||
|
InputStream inputStream = httpURLConnection.getInputStream();
|
||||||
|
String ret = getStringBuilder(inputStream).toString();
|
||||||
|
logger.trace("Got Respose is {}", ret);
|
||||||
|
result = validateCKANResponse(ret);
|
||||||
|
if(result instanceof NullNode) {
|
||||||
|
result = mapper.createObjectNode();
|
||||||
|
}
|
||||||
return getAsString(result);
|
return getAsString(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String sendPostRequest(String path, String body) {
|
protected String sendGetRequest(String path, Map<String,String> parameters) {
|
||||||
result = sendRequest(HTTPMETHOD.POST, path, null, body);
|
try {
|
||||||
return getAsString(result);
|
GXHTTPStringRequest gxhttpStringRequest = getGXHTTPStringRequest(path);
|
||||||
|
gxhttpStringRequest.queryParams(parameters);
|
||||||
|
HttpURLConnection httpURLConnection = gxhttpStringRequest.get();
|
||||||
|
return getResultAsString(httpURLConnection);
|
||||||
|
} catch(WebApplicationException e) {
|
||||||
|
throw e;
|
||||||
|
} catch(Exception e) {
|
||||||
|
throw new InternalServerErrorException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public String sendPostRequest(String path, JsonNode jsonNode) {
|
protected String sendPostRequest(String path, String body) {
|
||||||
|
try {
|
||||||
|
GXHTTPStringRequest gxhttpStringRequest = getGXHTTPStringRequest(path);
|
||||||
|
HttpURLConnection httpURLConnection = gxhttpStringRequest.post(body);
|
||||||
|
return getResultAsString(httpURLConnection);
|
||||||
|
} catch(WebApplicationException e) {
|
||||||
|
throw e;
|
||||||
|
} catch(Exception e) {
|
||||||
|
throw new InternalServerErrorException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String sendPostRequest(String path, JsonNode jsonNode) {
|
||||||
return sendPostRequest(path, getAsString(jsonNode));
|
return sendPostRequest(path, getAsString(jsonNode));
|
||||||
}
|
}
|
||||||
|
|
||||||
public String list() {
|
public String list(int limit, int offset) {
|
||||||
return sendGetRequest(LIST, null);
|
Map<String,String> parameters = new HashMap<>();
|
||||||
|
if(limit > 0) {
|
||||||
|
parameters.put(LIMIT_KEY, String.valueOf(limit));
|
||||||
|
}
|
||||||
|
if(offset >= 0) {
|
||||||
|
parameters.put(OFFSET_KEY, String.valueOf(offset));
|
||||||
|
}
|
||||||
|
return sendGetRequest(LIST, parameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String create(String json) {
|
public String create(String json) {
|
||||||
|
|
|
@ -20,7 +20,7 @@ import org.gcube.common.scope.impl.ScopeBean;
|
||||||
import org.gcube.common.scope.impl.ScopeBean.Type;
|
import org.gcube.common.scope.impl.ScopeBean.Type;
|
||||||
import org.gcube.gcat.annotation.PURGE;
|
import org.gcube.gcat.annotation.PURGE;
|
||||||
import org.gcube.gcat.oldutils.Validator;
|
import org.gcube.gcat.oldutils.Validator;
|
||||||
import org.gcube.gcat.rest.Profile;
|
import org.gcube.gcat.profile.MetadataUtility;
|
||||||
import org.gcube.gcat.social.SocialService;
|
import org.gcube.gcat.social.SocialService;
|
||||||
import org.gcube.gcat.utils.ContextUtility;
|
import org.gcube.gcat.utils.ContextUtility;
|
||||||
import org.gcube.gcat.utils.URIResolver;
|
import org.gcube.gcat.utils.URIResolver;
|
||||||
|
@ -155,9 +155,9 @@ public class CKANPackage extends CKAN {
|
||||||
ObjectNode objectNode = checkBaseInformation(json);
|
ObjectNode objectNode = checkBaseInformation(json);
|
||||||
|
|
||||||
// Validating against profiles if any
|
// Validating against profiles if any
|
||||||
List<String> profiles = Profile.getProfilesNames();
|
MetadataUtility metadataUtility = MetadataUtility.getInstance();
|
||||||
if(profiles != null && !profiles.isEmpty()) {
|
if(!metadataUtility.getMetadataProfiles().isEmpty()) {
|
||||||
Validator.validateAgainstProfile(getAsString(objectNode), profiles);
|
Validator.validateAgainstProfile(getAsString(objectNode));
|
||||||
}
|
}
|
||||||
|
|
||||||
return objectNode;
|
return objectNode;
|
||||||
|
@ -170,8 +170,8 @@ public class CKANPackage extends CKAN {
|
||||||
|
|
||||||
// see https://docs.ckan.org/en/latest/api/#ckan.logic.action.get.package_list
|
// see https://docs.ckan.org/en/latest/api/#ckan.logic.action.get.package_list
|
||||||
@Override
|
@Override
|
||||||
public String list() {
|
public String list(int limit, int offset) {
|
||||||
return super.list();
|
return super.list(limit, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void rollbackManagedResources() {
|
protected void rollbackManagedResources() {
|
||||||
|
@ -337,7 +337,7 @@ public class CKANPackage extends CKAN {
|
||||||
for(JsonNode jsonNode : arrayNode) {
|
for(JsonNode jsonNode : arrayNode) {
|
||||||
CKANResource ckanResource = new CKANResource(itemID);
|
CKANResource ckanResource = new CKANResource(itemID);
|
||||||
ckanResource.setPreviousRepresentation(jsonNode);
|
ckanResource.setPreviousRepresentation(jsonNode);
|
||||||
ckanResource.deleteFile();
|
ckanResource.deleteFile(); // Only delete file is required because the item has been deleted
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
super.purge();
|
super.purge();
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package org.gcube.gcat.persistence.ckan;
|
package org.gcube.gcat.persistence.ckan;
|
||||||
|
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
@ -14,10 +15,12 @@ import javax.ws.rs.OPTIONS;
|
||||||
import javax.ws.rs.PUT;
|
import javax.ws.rs.PUT;
|
||||||
import javax.ws.rs.WebApplicationException;
|
import javax.ws.rs.WebApplicationException;
|
||||||
|
|
||||||
import org.gcube.gcat.utils.ApplicationMode;
|
import org.apache.commons.io.FilenameUtils;
|
||||||
|
import org.gcube.common.gxhttp.request.GXHTTPStringRequest;
|
||||||
|
import org.gcube.gcat.utils.Constants;
|
||||||
import org.gcube.gcat.utils.ContextUtility;
|
import org.gcube.gcat.utils.ContextUtility;
|
||||||
import org.gcube.gcat.utils.HTTPCall;
|
import org.gcube.gcat.utils.HTTPCall;
|
||||||
import org.gcube.gcat.workspace.StorageHubManagement;
|
import org.gcube.gcat.workspace.CatalogueStorageHubManagement;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
@ -44,7 +47,7 @@ public class CKANResource extends CKAN {
|
||||||
|
|
||||||
/* TODO Remove this code ASAP. It requires a function from Storage HUB */
|
/* TODO Remove this code ASAP. It requires a function from Storage HUB */
|
||||||
private static final String URI_RESOLVER_STORAGE_HUB_HOST_PROD = "data.d4science.org";
|
private static final String URI_RESOLVER_STORAGE_HUB_HOST_PROD = "data.d4science.org";
|
||||||
private static final String URI_RESOLVER_STORAGE_HUB_HOST_DEV = "data-d.d4science.org";
|
private static final String URI_RESOLVER_STORAGE_HUB_HOST_DEV = "data1-d.d4science.org";
|
||||||
|
|
||||||
public static final String URI_RESOLVER_STORAGE_HUB_HOST;
|
public static final String URI_RESOLVER_STORAGE_HUB_HOST;
|
||||||
public static final String URI_RESOLVER_STORAGE_HUB_PATH = "/shub/";
|
public static final String URI_RESOLVER_STORAGE_HUB_PATH = "/shub/";
|
||||||
|
@ -58,6 +61,7 @@ public class CKANResource extends CKAN {
|
||||||
|
|
||||||
private static final String TEMP = "TEMP_";
|
private static final String TEMP = "TEMP_";
|
||||||
|
|
||||||
|
public final static String RESOURCE_NAME_REGEX = "^[\\s\\S]*$";
|
||||||
|
|
||||||
static {
|
static {
|
||||||
String context = ContextUtility.getCurrentContext();
|
String context = ContextUtility.getCurrentContext();
|
||||||
|
@ -78,14 +82,14 @@ public class CKANResource extends CKAN {
|
||||||
|
|
||||||
protected String resourceID;
|
protected String resourceID;
|
||||||
|
|
||||||
protected Boolean persisted;
|
protected boolean persisted;
|
||||||
protected URL persistedURL;
|
protected URL persistedURL;
|
||||||
|
|
||||||
protected String mimeType;
|
protected String mimeType;
|
||||||
|
|
||||||
protected JsonNode previousRepresentation;
|
protected JsonNode previousRepresentation;
|
||||||
|
|
||||||
protected StorageHubManagement storageHubManagement;
|
protected CatalogueStorageHubManagement storageHubManagement;
|
||||||
|
|
||||||
public URL getPersistedURL() {
|
public URL getPersistedURL() {
|
||||||
return persistedURL;
|
return persistedURL;
|
||||||
|
@ -111,6 +115,7 @@ public class CKANResource extends CKAN {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPreviousRepresentation(JsonNode jsonNode) {
|
public void setPreviousRepresentation(JsonNode jsonNode) {
|
||||||
|
validate(jsonNode);
|
||||||
previousRepresentation = jsonNode;
|
previousRepresentation = jsonNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,6 +130,7 @@ public class CKANResource extends CKAN {
|
||||||
|
|
||||||
public CKANResource(String itemID) {
|
public CKANResource(String itemID) {
|
||||||
super();
|
super();
|
||||||
|
this.nameRegex = RESOURCE_NAME_REGEX;
|
||||||
this.itemID = itemID;
|
this.itemID = itemID;
|
||||||
CREATE = RESOURCE_CREATE;
|
CREATE = RESOURCE_CREATE;
|
||||||
READ = RESOURCE_SHOW;
|
READ = RESOURCE_SHOW;
|
||||||
|
@ -132,11 +138,15 @@ public class CKANResource extends CKAN {
|
||||||
PATCH = RESOURCE_PATCH;
|
PATCH = RESOURCE_PATCH;
|
||||||
DELETE = RESOURCE_DELETE;
|
DELETE = RESOURCE_DELETE;
|
||||||
PURGE = null;
|
PURGE = null;
|
||||||
persisted = null;
|
persisted = false;
|
||||||
previousRepresentation = null;
|
previousRepresentation = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
public String list(int limit, int offeset) {
|
||||||
|
return list();
|
||||||
|
}
|
||||||
|
|
||||||
public String list() {
|
public String list() {
|
||||||
CKANPackage ckanPackage = new CKANPackage();
|
CKANPackage ckanPackage = new CKANPackage();
|
||||||
ckanPackage.setName(itemID);
|
ckanPackage.setName(itemID);
|
||||||
|
@ -160,6 +170,10 @@ public class CKANResource extends CKAN {
|
||||||
|
|
||||||
url = copyStorageResource(url);
|
url = copyStorageResource(url);
|
||||||
|
|
||||||
|
if(name!=null) {
|
||||||
|
objectNode.put(NAME_KEY, name);
|
||||||
|
}
|
||||||
|
|
||||||
if(mimeType!=null) {
|
if(mimeType!=null) {
|
||||||
objectNode.put(MIME_TYPE_KEY, mimeType);
|
objectNode.put(MIME_TYPE_KEY, mimeType);
|
||||||
}
|
}
|
||||||
|
@ -219,13 +233,13 @@ public class CKANResource extends CKAN {
|
||||||
protected URL getFinalURL(String url) {
|
protected URL getFinalURL(String url) {
|
||||||
try {
|
try {
|
||||||
URL urlURL = new URL(url);
|
URL urlURL = new URL(url);
|
||||||
return getFinalURL(urlURL);
|
return CKANResource.getFinalURL(urlURL);
|
||||||
} catch(MalformedURLException e) {
|
} catch(MalformedURLException e) {
|
||||||
throw new BadRequestException(e);
|
throw new BadRequestException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected URL getFinalURL(URL url) {
|
public static URL getFinalURL(URL url) {
|
||||||
HTTPCall httpCall = new HTTPCall(url.toString());
|
HTTPCall httpCall = new HTTPCall(url.toString());
|
||||||
httpCall.setgCubeTargetService(false);
|
httpCall.setgCubeTargetService(false);
|
||||||
URL finalURL = httpCall.getFinalURL(url);
|
URL finalURL = httpCall.getFinalURL(url);
|
||||||
|
@ -250,40 +264,40 @@ public class CKANResource extends CKAN {
|
||||||
protected URL copyStorageResource(URL url) {
|
protected URL copyStorageResource(URL url) {
|
||||||
persistedURL = getFinalURL(url);
|
persistedURL = getFinalURL(url);
|
||||||
if(isStorageFile(persistedURL)) {
|
if(isStorageFile(persistedURL)) {
|
||||||
ApplicationMode applicationMode = new ApplicationMode();
|
storageHubManagement = new CatalogueStorageHubManagement();
|
||||||
applicationMode.start();
|
try {
|
||||||
storageHubManagement = new StorageHubManagement();
|
persistedURL = storageHubManagement.ensureResourcePersistence(persistedURL, itemID, resourceID);
|
||||||
persistedURL = storageHubManagement.ensureResourcePersistence(persistedURL, itemID, resourceID, name);
|
name = FilenameUtils.removeExtension(storageHubManagement.getOriginalFilename());
|
||||||
mimeType = storageHubManagement.getMimeType();
|
mimeType = storageHubManagement.getMimeType();
|
||||||
persisted = true;
|
persisted = true;
|
||||||
applicationMode.end();
|
}catch (Exception e) {
|
||||||
|
throw new InternalServerErrorException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return persistedURL;
|
return persistedURL;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void deleteStorageResource(URL url) {
|
protected void deleteStorageResource(URL url, String resourceID, String mimetype) {
|
||||||
persistedURL = getFinalURL(url);
|
persistedURL = getFinalURL(url);
|
||||||
if(isStorageFile(persistedURL)) {
|
if(isStorageFile(persistedURL)) {
|
||||||
ApplicationMode applicationMode = new ApplicationMode();
|
try {
|
||||||
applicationMode.start();
|
GXHTTPStringRequest gxhttpStringRequest = GXHTTPStringRequest.newRequest(url.toString());
|
||||||
storageHubManagement = new StorageHubManagement();
|
HttpURLConnection httpURLConnection = gxhttpStringRequest.from(Constants.CATALOGUE_NAME).head();
|
||||||
storageHubManagement.deleteResourcePersistence(persistedURL, itemID);
|
String storageHubContentType = httpURLConnection.getContentType().split(";")[0];
|
||||||
applicationMode.end();
|
if(mimetype.compareTo(storageHubContentType)!=0) {
|
||||||
}
|
mimetype = storageHubContentType;
|
||||||
}
|
// Using storage hub mimetype
|
||||||
|
}
|
||||||
public boolean isPersisted() {
|
}catch (Exception e) {
|
||||||
if(persisted == null) {
|
// using provided mimetype
|
||||||
persistedURL = getFinalURL(persistedURL);
|
}
|
||||||
if(isStorageFile(persistedURL)) {
|
storageHubManagement = new CatalogueStorageHubManagement();
|
||||||
ApplicationMode applicationMode = new ApplicationMode();
|
try {
|
||||||
applicationMode.start();
|
storageHubManagement.deleteResourcePersistence(itemID, resourceID, mimetype);
|
||||||
storageHubManagement = new StorageHubManagement();
|
} catch(Exception e) {
|
||||||
persisted = storageHubManagement.isItemPersistedFile(persistedURL, itemID);
|
throw new InternalServerErrorException(e);
|
||||||
applicationMode.end();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return persisted;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String create(JsonNode jsonNode) {
|
protected String create(JsonNode jsonNode) {
|
||||||
|
@ -291,16 +305,20 @@ public class CKANResource extends CKAN {
|
||||||
ObjectNode objectNode = validate(jsonNode);
|
ObjectNode objectNode = validate(jsonNode);
|
||||||
objectNode = persistStorageFile(objectNode);
|
objectNode = persistStorageFile(objectNode);
|
||||||
String ret = super.create(getAsString(objectNode));
|
String ret = super.create(getAsString(objectNode));
|
||||||
String gotResourceID = result.get(ID_KEY).asText();
|
if(persisted) {
|
||||||
if(gotResourceID.compareTo(resourceID)!=0) {
|
String gotResourceID = result.get(ID_KEY).asText();
|
||||||
resourceID = gotResourceID;
|
if(gotResourceID!=null && gotResourceID.compareTo(resourceID)!=0) {
|
||||||
String revisionID = result.get(REVISION_ID_KEY).asText();
|
resourceID = gotResourceID;
|
||||||
storageHubManagement.renameFile(resourceID, revisionID);
|
String revisionID = result.get(REVISION_ID_KEY).asText();
|
||||||
|
storageHubManagement.renameFile(resourceID, revisionID);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
} catch(WebApplicationException e) {
|
} catch(WebApplicationException e) {
|
||||||
|
// TODO Remove created file if any
|
||||||
throw e;
|
throw e;
|
||||||
} catch(Exception e) {
|
} catch(Exception e) {
|
||||||
|
// TODO Remove created file if any
|
||||||
throw new InternalServerErrorException(e);
|
throw new InternalServerErrorException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -359,6 +377,11 @@ public class CKANResource extends CKAN {
|
||||||
throw new NotAllowedException(OPTIONS.class.getSimpleName(), moreAllowed);
|
throw new NotAllowedException(OPTIONS.class.getSimpleName(), moreAllowed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void delete(boolean purge) {
|
||||||
|
delete();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void delete() {
|
public void delete() {
|
||||||
try {
|
try {
|
||||||
|
@ -392,7 +415,8 @@ public class CKANResource extends CKAN {
|
||||||
try {
|
try {
|
||||||
getPreviousRepresentation();
|
getPreviousRepresentation();
|
||||||
URL url = new URL(previousRepresentation.get(URL_KEY).asText());
|
URL url = new URL(previousRepresentation.get(URL_KEY).asText());
|
||||||
deleteStorageResource(url);
|
mimeType = previousRepresentation.get(MIME_TYPE_KEY).asText();
|
||||||
|
deleteStorageResource(url, resourceID, mimeType);
|
||||||
} catch(Exception e) {
|
} catch(Exception e) {
|
||||||
logger.error("Unable to delete resource {}", previousRepresentation!=null ? getAsString(previousRepresentation) : "");
|
logger.error("Unable to delete resource {}", previousRepresentation!=null ? getAsString(previousRepresentation) : "");
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,6 +54,7 @@ public class CKANUtility {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static JsonNode createCKANUser(String ckanUsername) {
|
protected static JsonNode createCKANUser(String ckanUsername) {
|
||||||
|
ckanUsername = CKANUtility.getCKANUsername(ckanUsername);
|
||||||
CKANUser ckanUser = new CKANUser();
|
CKANUser ckanUser = new CKANUser();
|
||||||
ckanUser.setApiKey(getSysAdminAPI());
|
ckanUser.setApiKey(getSysAdminAPI());
|
||||||
try {
|
try {
|
||||||
|
@ -77,7 +78,7 @@ public class CKANUtility {
|
||||||
ckanOrganization.setApiKey(getSysAdminAPI());
|
ckanOrganization.setApiKey(getSysAdminAPI());
|
||||||
String organizationName = CKANOrganization.getCKANOrganizationName();
|
String organizationName = CKANOrganization.getCKANOrganizationName();
|
||||||
ckanOrganization.setName(organizationName);
|
ckanOrganization.setName(organizationName);
|
||||||
ckanOrganization.addUserToOrganisation(ContextUtility.getUsername(), role, force);
|
ckanOrganization.addUserToOrganisation(ckanUsername, role, force);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getApiKey() throws Exception {
|
public static String getApiKey() throws Exception {
|
||||||
|
|
|
@ -0,0 +1,107 @@
|
||||||
|
package org.gcube.gcat.profile;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javax.ws.rs.InternalServerErrorException;
|
||||||
|
|
||||||
|
import org.gcube.datacatalogue.metadatadiscovery.DataCalogueMetadataFormatReader;
|
||||||
|
import org.gcube.datacatalogue.metadatadiscovery.bean.MetadataProfile;
|
||||||
|
import org.gcube.datacatalogue.metadatadiscovery.bean.jaxb.MetadataFormat;
|
||||||
|
import org.gcube.datacatalogue.metadatadiscovery.bean.jaxb.NamespaceCategory;
|
||||||
|
|
||||||
|
public class MetadataUtility {
|
||||||
|
|
||||||
|
private DataCalogueMetadataFormatReader dataCalogueMetadataFormatReader;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* this map contains the Metadata Profiles. The key is the name of the profile.
|
||||||
|
*/
|
||||||
|
private Map<String,MetadataProfile> metadataProfiles;
|
||||||
|
|
||||||
|
private static DataCalogueMetadataFormatReader getDataCalogueMetadataFormatReaderInstance() throws Exception {
|
||||||
|
/*
|
||||||
|
Cache<String,DataCalogueMetadataFormatReader> 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 new DataCalogueMetadataFormatReader();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void clearCache() {
|
||||||
|
/*
|
||||||
|
Cache<String,DataCalogueMetadataFormatReader> readerCache = CachesManager.getReaderCache();
|
||||||
|
readerCache.clear();
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
private MetadataUtility() throws Exception{
|
||||||
|
dataCalogueMetadataFormatReader = getDataCalogueMetadataFormatReaderInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final InheritableThreadLocal<MetadataUtility> metadataUtility = new InheritableThreadLocal<MetadataUtility>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected MetadataUtility initialValue() {
|
||||||
|
try {
|
||||||
|
return new MetadataUtility();
|
||||||
|
} catch(Exception e) {
|
||||||
|
throw new InternalServerErrorException("Unable to instantiate MetadataUtility.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
public static MetadataUtility getInstance() {
|
||||||
|
return metadataUtility.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public DataCalogueMetadataFormatReader getDataCalogueMetadataFormatReader() {
|
||||||
|
return dataCalogueMetadataFormatReader;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, MetadataProfile> getMetadataProfiles() throws Exception{
|
||||||
|
if(metadataProfiles==null) {
|
||||||
|
metadataProfiles = new HashMap<>();
|
||||||
|
List<MetadataProfile> list = dataCalogueMetadataFormatReader.getListOfMetadataProfiles();
|
||||||
|
for(MetadataProfile profile : list) {
|
||||||
|
metadataProfiles.put(profile.getName(), profile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return metadataProfiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the names of the metadata profiles in a given context
|
||||||
|
* @param context
|
||||||
|
* @return
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public Set<String> getProfilesNames() throws Exception {
|
||||||
|
return getMetadataProfiles().keySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
public MetadataFormat getMetadataFormat(String profileName) throws Exception {
|
||||||
|
MetadataProfile profile = getMetadataProfiles().get(profileName);
|
||||||
|
if(profile!=null) {
|
||||||
|
return dataCalogueMetadataFormatReader.getMetadataFormatForMetadataProfile(profile);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public List<NamespaceCategory> getNamespaceCategories() throws Exception {
|
||||||
|
return dataCalogueMetadataFormatReader.getListOfNamespaceCategories();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -31,6 +31,9 @@ public class BaseREST {
|
||||||
|
|
||||||
protected static final String LOCATION_HEADER = "Location";
|
protected static final String LOCATION_HEADER = "Location";
|
||||||
|
|
||||||
|
public static final String LIMIT_PARAMETER = "limit";
|
||||||
|
public static final String OFFSET_PARAMETER = "offset";
|
||||||
|
|
||||||
protected void setCalledMethod(String method) {
|
protected void setCalledMethod(String method) {
|
||||||
CalledMethodProvider.instance.set(method);
|
CalledMethodProvider.instance.set(method);
|
||||||
logger.info("{}", uriInfo.getAbsolutePath());
|
logger.info("{}", uriInfo.getAbsolutePath());
|
||||||
|
|
|
@ -32,8 +32,9 @@ public class Group extends REST<CKANGroup> {
|
||||||
@GET
|
@GET
|
||||||
@Produces(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
|
@Produces(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
|
||||||
@Override
|
@Override
|
||||||
public String list() {
|
public String list(@QueryParam(BaseREST.LIMIT_PARAMETER) @DefaultValue("10") int limit,
|
||||||
return super.list();
|
@QueryParam(BaseREST.OFFSET_PARAMETER) @DefaultValue("0") int offset) {
|
||||||
|
return super.list(limit, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
@POST
|
@POST
|
||||||
|
@ -72,8 +73,6 @@ public class Group extends REST<CKANGroup> {
|
||||||
|
|
||||||
@DELETE
|
@DELETE
|
||||||
@Path("/{" + GROUP_ID_PARAMETER + "}")
|
@Path("/{" + GROUP_ID_PARAMETER + "}")
|
||||||
@Consumes(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
|
|
||||||
@Produces(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
|
|
||||||
@Override
|
@Override
|
||||||
public Response delete(@PathParam(GROUP_ID_PARAMETER) String id,
|
public Response delete(@PathParam(GROUP_ID_PARAMETER) String id,
|
||||||
@QueryParam(BaseREST.PURGE_QUERY_PARAMETER) @DefaultValue("false") Boolean purge) {
|
@QueryParam(BaseREST.PURGE_QUERY_PARAMETER) @DefaultValue("false") Boolean purge) {
|
||||||
|
@ -82,8 +81,6 @@ public class Group extends REST<CKANGroup> {
|
||||||
|
|
||||||
@PURGE
|
@PURGE
|
||||||
@Path("/{" + GROUP_ID_PARAMETER + "}")
|
@Path("/{" + GROUP_ID_PARAMETER + "}")
|
||||||
@Consumes(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
|
|
||||||
@Produces(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
|
|
||||||
@Override
|
@Override
|
||||||
public Response purge(@PathParam(GROUP_ID_PARAMETER) String id) {
|
public Response purge(@PathParam(GROUP_ID_PARAMETER) String id) {
|
||||||
return delete(id, true);
|
return delete(id, true);
|
||||||
|
|
|
@ -31,8 +31,9 @@ public class Item extends REST<CKANPackage> {
|
||||||
@GET
|
@GET
|
||||||
@Produces(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
|
@Produces(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
|
||||||
@Override
|
@Override
|
||||||
public String list() {
|
public String list(@QueryParam(BaseREST.LIMIT_PARAMETER) @DefaultValue("10") int limit,
|
||||||
return super.list();
|
@QueryParam(BaseREST.OFFSET_PARAMETER) @DefaultValue("0") int offset) {
|
||||||
|
return super.list(limit, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
@POST
|
@POST
|
||||||
|
@ -73,8 +74,6 @@ public class Item extends REST<CKANPackage> {
|
||||||
|
|
||||||
@DELETE
|
@DELETE
|
||||||
@Path("/{" + ITEM_ID_PARAMETER + "}")
|
@Path("/{" + ITEM_ID_PARAMETER + "}")
|
||||||
@Consumes(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
|
|
||||||
@Produces(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
|
|
||||||
@Override
|
@Override
|
||||||
public Response delete(@PathParam(ITEM_ID_PARAMETER) String id,
|
public Response delete(@PathParam(ITEM_ID_PARAMETER) String id,
|
||||||
@QueryParam(BaseREST.PURGE_QUERY_PARAMETER) @DefaultValue("false") Boolean purge) {
|
@QueryParam(BaseREST.PURGE_QUERY_PARAMETER) @DefaultValue("false") Boolean purge) {
|
||||||
|
@ -83,8 +82,6 @@ public class Item extends REST<CKANPackage> {
|
||||||
|
|
||||||
@PURGE
|
@PURGE
|
||||||
@Path("/{" + ITEM_ID_PARAMETER + "}")
|
@Path("/{" + ITEM_ID_PARAMETER + "}")
|
||||||
@Consumes(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
|
|
||||||
@Produces(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
|
|
||||||
@Override
|
@Override
|
||||||
public Response purge(@PathParam(ITEM_ID_PARAMETER) String id) {
|
public Response purge(@PathParam(ITEM_ID_PARAMETER) String id) {
|
||||||
return super.purge(id);
|
return super.purge(id);
|
||||||
|
|
|
@ -19,9 +19,8 @@ public class License extends REST<CKANLicense> {
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
@Produces(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
|
@Produces(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
|
||||||
@Override
|
|
||||||
public String list() {
|
public String list() {
|
||||||
return super.list();
|
return super.list(-1, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,9 +7,9 @@ import javax.ws.rs.InternalServerErrorException;
|
||||||
import javax.ws.rs.Path;
|
import javax.ws.rs.Path;
|
||||||
import javax.ws.rs.Produces;
|
import javax.ws.rs.Produces;
|
||||||
|
|
||||||
import org.gcube.datacatalogue.metadatadiscovery.DataCalogueMetadataFormatReader;
|
|
||||||
import org.gcube.datacatalogue.metadatadiscovery.bean.jaxb.NamespaceCategory;
|
import org.gcube.datacatalogue.metadatadiscovery.bean.jaxb.NamespaceCategory;
|
||||||
import org.gcube.gcat.ResourceInitializer;
|
import org.gcube.gcat.ResourceInitializer;
|
||||||
|
import org.gcube.gcat.profile.MetadataUtility;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||||
|
@ -21,18 +21,6 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||||
@Path(BaseREST.NAMESPACES)
|
@Path(BaseREST.NAMESPACES)
|
||||||
public class Namespace extends BaseREST {
|
public class Namespace extends BaseREST {
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the categories.
|
|
||||||
* @param context
|
|
||||||
* @return
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
public static List<NamespaceCategory> getNamespaceCategories() throws Exception {
|
|
||||||
DataCalogueMetadataFormatReader reader = Profile.getDataCalogueMetadataFormatReader();
|
|
||||||
return reader.getListOfNamespaceCategories();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
@Produces(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
|
@Produces(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
|
||||||
public String list() {
|
public String list() {
|
||||||
|
@ -42,7 +30,7 @@ public class Namespace extends BaseREST {
|
||||||
ArrayNode arrayNode = mapper.createArrayNode();
|
ArrayNode arrayNode = mapper.createArrayNode();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
List<NamespaceCategory> namespaces = Namespace.getNamespaceCategories();
|
List<NamespaceCategory> namespaces = MetadataUtility.getInstance().getNamespaceCategories();
|
||||||
for(NamespaceCategory namespaceCategory : namespaces) {
|
for(NamespaceCategory namespaceCategory : namespaces) {
|
||||||
ObjectNode namespace = mapper.createObjectNode();
|
ObjectNode namespace = mapper.createObjectNode();
|
||||||
namespace.put("id", namespaceCategory.getId());
|
namespace.put("id", namespaceCategory.getId());
|
||||||
|
|
|
@ -32,8 +32,9 @@ public class Organization extends REST<CKANOrganization> {
|
||||||
@GET
|
@GET
|
||||||
@Produces(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
|
@Produces(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
|
||||||
@Override
|
@Override
|
||||||
public String list() {
|
public String list(@QueryParam(BaseREST.LIMIT_PARAMETER) @DefaultValue("10") int limit,
|
||||||
return super.list();
|
@QueryParam(BaseREST.OFFSET_PARAMETER) @DefaultValue("0") int offset) {
|
||||||
|
return super.list(limit, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
@POST
|
@POST
|
||||||
|
@ -72,8 +73,6 @@ public class Organization extends REST<CKANOrganization> {
|
||||||
|
|
||||||
@DELETE
|
@DELETE
|
||||||
@Path("/{" + ORGANIZATION_ID_PARAMETER + "}")
|
@Path("/{" + ORGANIZATION_ID_PARAMETER + "}")
|
||||||
@Consumes(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
|
|
||||||
@Produces(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
|
|
||||||
@Override
|
@Override
|
||||||
public Response delete(@PathParam(ORGANIZATION_ID_PARAMETER) String id,
|
public Response delete(@PathParam(ORGANIZATION_ID_PARAMETER) String id,
|
||||||
@QueryParam(BaseREST.PURGE_QUERY_PARAMETER) @DefaultValue("false") Boolean purge) {
|
@QueryParam(BaseREST.PURGE_QUERY_PARAMETER) @DefaultValue("false") Boolean purge) {
|
||||||
|
@ -82,8 +81,6 @@ public class Organization extends REST<CKANOrganization> {
|
||||||
|
|
||||||
@PURGE
|
@PURGE
|
||||||
@Path("/{" + ORGANIZATION_ID_PARAMETER + "}")
|
@Path("/{" + ORGANIZATION_ID_PARAMETER + "}")
|
||||||
@Consumes(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
|
|
||||||
@Produces(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
|
|
||||||
public Response purge(@PathParam(ORGANIZATION_ID_PARAMETER) String id) {
|
public Response purge(@PathParam(ORGANIZATION_ID_PARAMETER) String id) {
|
||||||
return super.purge(id);
|
return super.purge(id);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,100 +1,58 @@
|
||||||
package org.gcube.gcat.rest;
|
package org.gcube.gcat.rest;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.io.StringWriter;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.cache.Cache;
|
import javax.ws.rs.Consumes;
|
||||||
|
import javax.ws.rs.DELETE;
|
||||||
import javax.ws.rs.DefaultValue;
|
import javax.ws.rs.DefaultValue;
|
||||||
import javax.ws.rs.GET;
|
import javax.ws.rs.GET;
|
||||||
import javax.ws.rs.HeaderParam;
|
import javax.ws.rs.HeaderParam;
|
||||||
import javax.ws.rs.InternalServerErrorException;
|
import javax.ws.rs.InternalServerErrorException;
|
||||||
|
import javax.ws.rs.NotFoundException;
|
||||||
|
import javax.ws.rs.PUT;
|
||||||
import javax.ws.rs.Path;
|
import javax.ws.rs.Path;
|
||||||
import javax.ws.rs.PathParam;
|
import javax.ws.rs.PathParam;
|
||||||
import javax.ws.rs.Produces;
|
import javax.ws.rs.Produces;
|
||||||
|
import javax.ws.rs.WebApplicationException;
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
import javax.ws.rs.core.Response.Status;
|
||||||
|
|
||||||
import org.gcube.common.scope.api.ScopeProvider;
|
import org.gcube.common.resources.gcore.GenericResource;
|
||||||
import org.gcube.datacatalogue.metadatadiscovery.DataCalogueMetadataFormatReader;
|
import org.gcube.common.resources.gcore.Resources;
|
||||||
import org.gcube.datacatalogue.metadatadiscovery.bean.MetadataProfile;
|
import org.gcube.datacatalogue.metadatadiscovery.reader.MetadataFormatDiscovery;
|
||||||
|
import org.gcube.datacatalogue.metadatadiscovery.reader.QueryForResourceUtil;
|
||||||
import org.gcube.gcat.ResourceInitializer;
|
import org.gcube.gcat.ResourceInitializer;
|
||||||
import org.gcube.gcat.oldutils.CachesManager;
|
import org.gcube.gcat.profile.MetadataUtility;
|
||||||
|
import org.gcube.gcat.utils.Constants;
|
||||||
|
import org.gcube.informationsystem.publisher.RegistryPublisher;
|
||||||
|
import org.gcube.informationsystem.publisher.RegistryPublisherFactory;
|
||||||
|
import org.gcube.resources.discovery.client.api.DiscoveryClient;
|
||||||
|
import org.gcube.resources.discovery.client.queries.api.Query;
|
||||||
|
import org.gcube.resources.discovery.client.queries.impl.QueryBox;
|
||||||
|
import org.gcube.resources.discovery.icclient.ICFactory;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
import org.json.XML;
|
import org.json.XML;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Luca Frosini (ISTI - CNR)
|
* @author Luca Frosini (ISTI - CNR)
|
||||||
*/
|
*/
|
||||||
@Path(BaseREST.PROFILES)
|
@Path(BaseREST.PROFILES)
|
||||||
public class Profile extends BaseREST {
|
public class Profile extends BaseREST {
|
||||||
|
|
||||||
|
private static Logger logger = LoggerFactory.getLogger(Profile.class);
|
||||||
|
|
||||||
public static final String PROFILE_NAME_PARAMETER = "PROFILE_NAME";
|
public static final String PROFILE_NAME_PARAMETER = "PROFILE_NAME";
|
||||||
|
|
||||||
public static DataCalogueMetadataFormatReader getDataCalogueMetadataFormatReader() throws Exception {
|
|
||||||
Cache<String,DataCalogueMetadataFormatReader> 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<String> getProfilesNames() throws Exception {
|
|
||||||
|
|
||||||
DataCalogueMetadataFormatReader reader = getDataCalogueMetadataFormatReader();
|
|
||||||
|
|
||||||
List<String> toReturn = new ArrayList<String>();
|
|
||||||
List<MetadataProfile> listProfiles = reader.getListOfMetadataProfiles();
|
|
||||||
|
|
||||||
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 {
|
|
||||||
|
|
||||||
DataCalogueMetadataFormatReader reader = Profile.getDataCalogueMetadataFormatReader();
|
|
||||||
|
|
||||||
List<MetadataProfile> listProfiles = reader.getListOfMetadataProfiles();
|
|
||||||
String xmlToReturn = null;
|
|
||||||
|
|
||||||
if(listProfiles != null && !listProfiles.isEmpty()) {
|
|
||||||
for(MetadataProfile profile : listProfiles) {
|
|
||||||
if(profile.getName().equals(profileName)) {
|
|
||||||
xmlToReturn = reader.getMetadataFormatForMetadataProfile(profile).getMetadataSource();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return xmlToReturn;
|
|
||||||
}
|
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
@Produces(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
public String list() {
|
public String list() {
|
||||||
setCalledMethod("GET /" + BaseREST.PROFILES);
|
setCalledMethod("GET /" + BaseREST.PROFILES);
|
||||||
|
|
||||||
|
@ -102,7 +60,7 @@ public class Profile extends BaseREST {
|
||||||
ArrayNode arrayNode = mapper.createArrayNode();
|
ArrayNode arrayNode = mapper.createArrayNode();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
List<String> names = getProfilesNames();
|
Set<String> names = MetadataUtility.getInstance().getProfilesNames();
|
||||||
for(String name : names) {
|
for(String name : names) {
|
||||||
arrayNode.add(name);
|
arrayNode.add(name);
|
||||||
}
|
}
|
||||||
|
@ -117,21 +75,165 @@ public class Profile extends BaseREST {
|
||||||
@GET
|
@GET
|
||||||
@Path("/{" + PROFILE_NAME_PARAMETER + "}")
|
@Path("/{" + PROFILE_NAME_PARAMETER + "}")
|
||||||
@Produces({MediaType.APPLICATION_XML, ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8})
|
@Produces({MediaType.APPLICATION_XML, ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8})
|
||||||
public String read(@PathParam(PROFILE_NAME_PARAMETER) String id,
|
public String read(@PathParam(PROFILE_NAME_PARAMETER) String name,
|
||||||
@DefaultValue(MediaType.APPLICATION_JSON) @HeaderParam("Accept") String accept) {
|
@DefaultValue(MediaType.APPLICATION_JSON) @HeaderParam("Accept") String accept) {
|
||||||
setCalledMethod("GET /" + BaseREST.PROFILES + "/{" + PROFILE_NAME_PARAMETER + "}");
|
setCalledMethod("GET /" + BaseREST.PROFILES + "/{" + PROFILE_NAME_PARAMETER + "}");
|
||||||
try {
|
try {
|
||||||
String profile = Profile.getProfileSource(id);
|
String profile = MetadataUtility.getInstance().getMetadataFormat(name).getMetadataSource();
|
||||||
if(accept.startsWith(MediaType.APPLICATION_XML)){
|
if(profile != null) {
|
||||||
return profile;
|
if(accept.startsWith(MediaType.APPLICATION_XML)) {
|
||||||
}else {
|
return profile;
|
||||||
JSONObject xmlJSONObj = XML.toJSONObject(profile);
|
} else {
|
||||||
String jsonString = xmlJSONObj.toString(PRETTY_PRINT_INDENT_FACTOR);
|
JSONObject xmlJSONObj = XML.toJSONObject(profile);
|
||||||
return jsonString;
|
String jsonString = xmlJSONObj.toString(PRETTY_PRINT_INDENT_FACTOR);
|
||||||
}
|
return jsonString;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new NotFoundException("Profile with name " + name + " not found");
|
||||||
|
}
|
||||||
|
} catch(WebApplicationException e) {
|
||||||
|
throw e;
|
||||||
} catch(Exception e) {
|
} catch(Exception e) {
|
||||||
throw new InternalServerErrorException(e.getMessage());
|
throw new InternalServerErrorException(e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
public static void appendXmlFragment(org.gcube.common.resources.gcore.GenericResource.Profile profile, String xml) throws Exception {
|
||||||
|
try {
|
||||||
|
DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
|
||||||
|
Element elem = profile.newBody();
|
||||||
|
Node fragmentNode = docBuilder.parse(new InputSource(new StringReader(xml))).getDocumentElement();
|
||||||
|
fragmentNode = elem.getOwnerDocument().importNode(fragmentNode, true);
|
||||||
|
elem.appendChild(fragmentNode);
|
||||||
|
} catch (Exception e) {
|
||||||
|
profile.newBody(xml);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO Check the Queries because the name in the Profile differs from the name in
|
||||||
|
* <metadataformat type="Dataset">
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected GenericResource instantiateGenericResource(String name, String xml) throws Exception {
|
||||||
|
GenericResource genericResource = new GenericResource();
|
||||||
|
org.gcube.common.resources.gcore.GenericResource.Profile profile = genericResource.newProfile();
|
||||||
|
profile.type(MetadataFormatDiscovery.DATA_CATALOGUE_METADATA_SECONDARY_TYPE);
|
||||||
|
profile.name(name);
|
||||||
|
profile.description("Profile create using " + Constants.CATALOGUE_NAME);
|
||||||
|
// appendXmlFragment(profile, xml);
|
||||||
|
profile.newBody(xml);
|
||||||
|
StringWriter stringWriter = new StringWriter();
|
||||||
|
Resources.marshal(genericResource, stringWriter);
|
||||||
|
logger.debug("The generated {} is\n{}", GenericResource.class.getSimpleName(), stringWriter.toString());
|
||||||
|
return genericResource;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void createGenericResource(String name, String xml) throws Exception {
|
||||||
|
GenericResource genericResource = instantiateGenericResource(name, xml);
|
||||||
|
RegistryPublisher registryPublisher = RegistryPublisherFactory.create();
|
||||||
|
genericResource = registryPublisher.create(genericResource);
|
||||||
|
StringWriter stringWriter = new StringWriter();
|
||||||
|
Resources.marshal(genericResource, stringWriter);
|
||||||
|
logger.trace("The {} with ID {} has been created \n{}", GenericResource.class.getSimpleName(),
|
||||||
|
genericResource.id(), stringWriter.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected GenericResource getGenericResource(String name) {
|
||||||
|
String query = QueryForResourceUtil.getGcubeGenericQueryStringForSecondaryTypeAndName(name,
|
||||||
|
MetadataFormatDiscovery.DATA_CATALOGUE_METADATA_SECONDARY_TYPE);
|
||||||
|
Query q = new QueryBox(query);
|
||||||
|
DiscoveryClient<GenericResource> client = ICFactory.clientFor(GenericResource.class);
|
||||||
|
List<GenericResource> resources = client.submit(q);
|
||||||
|
|
||||||
|
if(resources == null || resources.size() == 0) {
|
||||||
|
throw new InternalServerErrorException(
|
||||||
|
"No Resources with secondaryType '" + MetadataFormatDiscovery.DATA_CATALOGUE_METADATA_SECONDARY_TYPE
|
||||||
|
+ "' and name '" + name + "' exists in the current context");
|
||||||
|
} else {
|
||||||
|
if(resources.size() == 1) {
|
||||||
|
GenericResource genericResource = resources.get(0);
|
||||||
|
return genericResource;
|
||||||
|
} else {
|
||||||
|
throw new InternalServerErrorException("More than one Resource with secondaryType '"
|
||||||
|
+ MetadataFormatDiscovery.DATA_CATALOGUE_METADATA_SECONDARY_TYPE + "' and name '" + name
|
||||||
|
+ "' exists in the current context");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void updateGenericResource(String name, String xml) {
|
||||||
|
|
||||||
|
GenericResource genericResource = getGenericResource(name);
|
||||||
|
logger.info("The {} with ID {} is going to be updated", GenericResource.class.getSimpleName(),
|
||||||
|
genericResource.id());
|
||||||
|
|
||||||
|
genericResource.profile().newBody(xml);
|
||||||
|
RegistryPublisher registryPublisher = RegistryPublisherFactory.create();
|
||||||
|
registryPublisher.update(genericResource);
|
||||||
|
|
||||||
|
StringWriter stringWriter = new StringWriter();
|
||||||
|
Resources.marshal(genericResource, stringWriter);
|
||||||
|
logger.trace("The {} with ID {} has been updated to \n{}", GenericResource.class.getSimpleName(),
|
||||||
|
genericResource.id(), stringWriter.toString());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void removeGenericResource(String name) {
|
||||||
|
GenericResource genericResource = getGenericResource(name);
|
||||||
|
RegistryPublisher registryPublisher = RegistryPublisherFactory.create();
|
||||||
|
registryPublisher.remove(genericResource);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PUT
|
||||||
|
@Path("/{" + PROFILE_NAME_PARAMETER + "}")
|
||||||
|
@Consumes(MediaType.APPLICATION_XML)
|
||||||
|
@Produces(MediaType.APPLICATION_XML)
|
||||||
|
public String createOrUpdate(@PathParam(PROFILE_NAME_PARAMETER) String name, String xml) {
|
||||||
|
setCalledMethod("PUT /" + BaseREST.PROFILES + "/{" + PROFILE_NAME_PARAMETER + "}");
|
||||||
|
try {
|
||||||
|
MetadataUtility metadataUtility = MetadataUtility.getInstance();
|
||||||
|
metadataUtility.getDataCalogueMetadataFormatReader().validateProfile(xml);
|
||||||
|
if(metadataUtility.getMetadataFormat(name) == null) {
|
||||||
|
createGenericResource(name, xml);
|
||||||
|
} else {
|
||||||
|
updateGenericResource(name, xml);
|
||||||
|
}
|
||||||
|
return xml;
|
||||||
|
} catch(WebApplicationException e) {
|
||||||
|
throw e;
|
||||||
|
} catch(Exception e) {
|
||||||
|
throw new InternalServerErrorException(e.getMessage());
|
||||||
|
}finally {
|
||||||
|
// TOOD Actually Cache has been removed. Remove the following code if it will not be re-introduced
|
||||||
|
// Cleaning the cache
|
||||||
|
MetadataUtility.clearCache();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@DELETE
|
||||||
|
@Path("/{" + PROFILE_NAME_PARAMETER + "}")
|
||||||
|
public Response delete(@PathParam(PROFILE_NAME_PARAMETER) String name) {
|
||||||
|
setCalledMethod("DELETE /" + BaseREST.PROFILES + "/{" + PROFILE_NAME_PARAMETER + "}");
|
||||||
|
try {
|
||||||
|
MetadataUtility metadataUtility = MetadataUtility.getInstance();
|
||||||
|
if(metadataUtility.getMetadataFormat(name) == null) {
|
||||||
|
throw new NotFoundException("Profile with name " + name + " not found");
|
||||||
|
} else {
|
||||||
|
removeGenericResource(name);
|
||||||
|
return Response.status(Status.NO_CONTENT).build();
|
||||||
|
}
|
||||||
|
} catch(WebApplicationException e) {
|
||||||
|
throw e;
|
||||||
|
} catch(Exception e) {
|
||||||
|
throw new InternalServerErrorException(e.getMessage());
|
||||||
|
} finally {
|
||||||
|
// Cleaning the cache
|
||||||
|
MetadataUtility.clearCache();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,10 +29,10 @@ public class REST<C extends CKAN> extends BaseREST {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public String list() {
|
public String list(int limit, int offset) {
|
||||||
setCalledMethod("GET /" + COLLECTION_PARAMETER);
|
setCalledMethod("GET /" + COLLECTION_PARAMETER);
|
||||||
C ckan = getInstance();
|
C ckan = getInstance();
|
||||||
return ckan.list();
|
return ckan.list(limit, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Response create(String json) {
|
public Response create(String json) {
|
||||||
|
|
|
@ -79,8 +79,6 @@ public class Resource extends BaseREST {
|
||||||
|
|
||||||
@DELETE
|
@DELETE
|
||||||
@Path("/{" + RESOURCE_ID_PARAMETER + "}")
|
@Path("/{" + RESOURCE_ID_PARAMETER + "}")
|
||||||
@Consumes(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
|
|
||||||
@Produces(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
|
|
||||||
public void delete(@PathParam(ITEM_ID_PARAMETER) String itemID,
|
public void delete(@PathParam(ITEM_ID_PARAMETER) String itemID,
|
||||||
@PathParam(RESOURCE_ID_PARAMETER) String resourceID) {
|
@PathParam(RESOURCE_ID_PARAMETER) String resourceID) {
|
||||||
setCalledMethod("DELETE /" + COLLECTION + "/{" + RESOURCE_ID_PARAMETER + "}");
|
setCalledMethod("DELETE /" + COLLECTION + "/{" + RESOURCE_ID_PARAMETER + "}");
|
||||||
|
|
|
@ -25,12 +25,10 @@ public class User extends REST<CKANUser> {
|
||||||
super(BaseREST.USERS, USER_ID_PARAMETER, CKANUser.class);
|
super(BaseREST.USERS, USER_ID_PARAMETER, CKANUser.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
@Produces(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
|
@Produces(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
|
||||||
@Override
|
|
||||||
public String list() {
|
public String list() {
|
||||||
return super.list();
|
return super.list(-1,-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@POST
|
@POST
|
||||||
|
@ -60,8 +58,6 @@ public class User extends REST<CKANUser> {
|
||||||
|
|
||||||
@DELETE
|
@DELETE
|
||||||
@Path("/{" + USER_ID_PARAMETER + "}")
|
@Path("/{" + USER_ID_PARAMETER + "}")
|
||||||
@Consumes(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
|
|
||||||
@Produces(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
|
|
||||||
public Response delete(@PathParam(USER_ID_PARAMETER) String id) {
|
public Response delete(@PathParam(USER_ID_PARAMETER) String id) {
|
||||||
return super.delete(id, false);
|
return super.delete(id, false);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +1,19 @@
|
||||||
package org.gcube.gcat.social;
|
package org.gcube.gcat.social;
|
||||||
|
|
||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import javax.cache.Cache;
|
import javax.cache.Cache;
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
|
|
||||||
|
import org.gcube.common.gxhttp.request.GXHTTPStringRequest;
|
||||||
import org.gcube.datacatalogue.ckanutillibrary.server.DataCatalogue;
|
import org.gcube.datacatalogue.ckanutillibrary.server.DataCatalogue;
|
||||||
import org.gcube.gcat.oldutils.CachesManager;
|
import org.gcube.gcat.oldutils.CachesManager;
|
||||||
import org.gcube.gcat.persistence.ckan.CKAN;
|
import org.gcube.gcat.persistence.ckan.CKAN;
|
||||||
import org.gcube.gcat.utils.ApplicationMode;
|
import org.gcube.gcat.utils.Constants;
|
||||||
import org.gcube.gcat.utils.ContextUtility;
|
import org.gcube.gcat.utils.ContextUtility;
|
||||||
import org.gcube.gcat.utils.HTTPCall;
|
|
||||||
import org.gcube.gcat.utils.HTTPCall.HTTPMETHOD;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
@ -101,10 +100,15 @@ public class SocialService extends Thread {
|
||||||
return userCache.get(username);
|
return userCache.get(username);
|
||||||
else {
|
else {
|
||||||
String socialServiceBasePath = socialService.getServiceBasePath();
|
String socialServiceBasePath = socialService.getServiceBasePath();
|
||||||
HTTPCall httpCall = new HTTPCall(socialServiceBasePath);
|
|
||||||
String response = httpCall.call(SOCIAL_SERVICE_GET_USER_INFO_PATH, HTTPMETHOD.GET, (Map<String,String>) null,
|
GXHTTPStringRequest gxhttpStringRequest = GXHTTPStringRequest.newRequest(socialServiceBasePath);
|
||||||
MediaType.APPLICATION_JSON);
|
gxhttpStringRequest.header("User-Agent", Constants.CATALOGUE_NAME);
|
||||||
JsonNode jsonNode = objectMapper.readTree(response);
|
gxhttpStringRequest.header("Accept", MediaType.APPLICATION_JSON);
|
||||||
|
gxhttpStringRequest.path(SOCIAL_SERVICE_GET_USER_INFO_PATH);
|
||||||
|
HttpURLConnection httpURLConnection = gxhttpStringRequest.get();
|
||||||
|
|
||||||
|
String message = httpURLConnection.getResponseMessage();
|
||||||
|
JsonNode jsonNode = objectMapper.readTree(message);
|
||||||
userCache.put(username, jsonNode);
|
userCache.put(username, jsonNode);
|
||||||
return jsonNode;
|
return jsonNode;
|
||||||
}
|
}
|
||||||
|
@ -175,14 +179,17 @@ public class SocialService extends Thread {
|
||||||
|
|
||||||
// Do not use ApplicationMode class here because is a thread and change the current token could impact
|
// Do not use ApplicationMode class here because is a thread and change the current token could impact
|
||||||
// on the other threads.
|
// on the other threads.
|
||||||
HTTPCall httpCall = new HTTPCall(basePath);
|
|
||||||
httpCall.setgCubeTargetService(false);
|
|
||||||
httpCall.addHeader(org.gcube.common.authorization.client.Constants.TOKEN_HEADER_ENTRY,
|
|
||||||
ApplicationMode.getCatalogueApplicationToken());
|
|
||||||
String response = httpCall.call(SOCIAL_SERVICE_WRITE_APPLICATION_POST_PATH, HTTPMETHOD.POST,
|
|
||||||
objectMapper.writeValueAsString(objectNode), MediaType.APPLICATION_JSON);
|
|
||||||
|
|
||||||
JsonNode jsonNode = objectMapper.readTree(response);
|
|
||||||
|
GXHTTPStringRequest gxhttpStringRequest = GXHTTPStringRequest.newRequest(basePath);
|
||||||
|
gxhttpStringRequest.header("User-Agent", Constants.CATALOGUE_NAME);
|
||||||
|
gxhttpStringRequest.setSecurityToken(Constants.getCatalogueApplicationToken());
|
||||||
|
gxhttpStringRequest.path(SOCIAL_SERVICE_WRITE_APPLICATION_POST_PATH);
|
||||||
|
|
||||||
|
|
||||||
|
HttpURLConnection httpURLConnection = gxhttpStringRequest.post(objectMapper.writeValueAsString(objectNode));
|
||||||
|
String ret = httpURLConnection.getResponseMessage();
|
||||||
|
JsonNode jsonNode = objectMapper.readTree(ret);
|
||||||
if(jsonNode.get(SOCIAL_POST_RESPONSE_SUCCESS_KEY).asBoolean()) {
|
if(jsonNode.get(SOCIAL_POST_RESPONSE_SUCCESS_KEY).asBoolean()) {
|
||||||
logger.info("Post written : {}", message);
|
logger.info("Post written : {}", message);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,92 +0,0 @@
|
||||||
package org.gcube.gcat.utils;
|
|
||||||
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.Properties;
|
|
||||||
|
|
||||||
import javax.ws.rs.WebApplicationException;
|
|
||||||
|
|
||||||
import org.gcube.common.authorization.client.Constants;
|
|
||||||
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.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Luca Frosini (ISTI - CNR)
|
|
||||||
*/
|
|
||||||
public class ApplicationMode {
|
|
||||||
|
|
||||||
private static final Logger logger = LoggerFactory.getLogger(ApplicationMode.class);
|
|
||||||
|
|
||||||
private static final String PROPERTY_FILENAME = "config.properties";
|
|
||||||
private static final String TOKEN_VARNAME = "TOKEN";
|
|
||||||
private static final String CATALOGUE_APPLICATION_TOKEN;
|
|
||||||
|
|
||||||
public static String getCatalogueApplicationToken() {
|
|
||||||
return CATALOGUE_APPLICATION_TOKEN;
|
|
||||||
}
|
|
||||||
|
|
||||||
static {
|
|
||||||
try {
|
|
||||||
Properties properties = new Properties();
|
|
||||||
InputStream input = Constants.class.getClassLoader().getResourceAsStream(PROPERTY_FILENAME);
|
|
||||||
// load a properties file
|
|
||||||
properties.load(input);
|
|
||||||
CATALOGUE_APPLICATION_TOKEN = properties.getProperty(TOKEN_VARNAME);
|
|
||||||
}catch (Exception e) {
|
|
||||||
throw new WebApplicationException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private final String originalToken;
|
|
||||||
|
|
||||||
public ApplicationMode() {
|
|
||||||
String applicationtoken = SecurityTokenProvider.instance.get();
|
|
||||||
if(applicationtoken.compareTo(CATALOGUE_APPLICATION_TOKEN)!=0) {
|
|
||||||
this.originalToken = applicationtoken;
|
|
||||||
}else {
|
|
||||||
logger.warn("You are already in application Mode. Operation on this instance will not have any effect.");
|
|
||||||
this.originalToken = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setToken(String token) {
|
|
||||||
SecurityTokenProvider.instance.set(token);
|
|
||||||
ScopeProvider.instance.set(ContextUtility.getCurrentContext());
|
|
||||||
try {
|
|
||||||
AuthorizationEntry authorizationEntry = Constants.authorizationService().get(token);
|
|
||||||
ClientInfo clientInfo = authorizationEntry.getClientInfo();
|
|
||||||
logger.debug("User : {} - Type : {}", clientInfo.getId(), clientInfo.getType().name());
|
|
||||||
String qualifier = authorizationEntry.getQualifier();
|
|
||||||
Caller caller = new Caller(clientInfo, qualifier);
|
|
||||||
AuthorizationProvider.instance.set(caller);
|
|
||||||
}catch (Exception e) {
|
|
||||||
logger.error("Unable to set Caller");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public synchronized void start() {
|
|
||||||
if(originalToken!=null) {
|
|
||||||
setToken(CATALOGUE_APPLICATION_TOKEN);
|
|
||||||
}else {
|
|
||||||
logger.warn("You are already in application Mode. start() does not provide any effect.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized void end() {
|
|
||||||
if(originalToken!=null) {
|
|
||||||
setToken(originalToken);
|
|
||||||
}else {
|
|
||||||
logger.warn("You are already in application Mode. end() does not provide any effect.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,10 +1,35 @@
|
||||||
package org.gcube.gcat.utils;
|
package org.gcube.gcat.utils;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import javax.ws.rs.WebApplicationException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Luca Frosini (ISTI - CNR)
|
* @author Luca Frosini (ISTI - CNR)
|
||||||
*/
|
*/
|
||||||
public class Constants {
|
public class Constants {
|
||||||
|
|
||||||
public static final String CATALOGUE_NAME = "ScienceCatalogue";
|
public static final String CATALOGUE_NAME = "gCat";
|
||||||
|
|
||||||
|
|
||||||
|
private static final String PROPERTY_FILENAME = "config.properties";
|
||||||
|
private static final String TOKEN_VARNAME = "TOKEN";
|
||||||
|
private static final String CATALOGUE_APPLICATION_TOKEN;
|
||||||
|
|
||||||
|
public static String getCatalogueApplicationToken() {
|
||||||
|
return CATALOGUE_APPLICATION_TOKEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
Properties properties = new Properties();
|
||||||
|
InputStream input = Constants.class.getClassLoader().getResourceAsStream(PROPERTY_FILENAME);
|
||||||
|
// load a properties file
|
||||||
|
properties.load(input);
|
||||||
|
CATALOGUE_APPLICATION_TOKEN = properties.getProperty(TOKEN_VARNAME);
|
||||||
|
}catch (Exception e) {
|
||||||
|
throw new WebApplicationException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,61 +1,26 @@
|
||||||
package org.gcube.gcat.utils;
|
package org.gcube.gcat.utils;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.io.StringWriter;
|
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.net.HttpURLConnection;
|
import java.net.HttpURLConnection;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLEncoder;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import javax.ws.rs.InternalServerErrorException;
|
import javax.ws.rs.InternalServerErrorException;
|
||||||
import javax.ws.rs.WebApplicationException;
|
import javax.ws.rs.WebApplicationException;
|
||||||
import javax.ws.rs.core.Response.Status;
|
import javax.ws.rs.core.Response.Status;
|
||||||
|
|
||||||
import org.gcube.common.authorization.library.provider.SecurityTokenProvider;
|
|
||||||
import org.gcube.common.scope.api.ScopeProvider;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
public class HTTPCall {
|
public class HTTPCall {
|
||||||
|
|
||||||
private static final Logger logger = LoggerFactory.getLogger(HTTPCall.class);
|
|
||||||
|
|
||||||
protected static final String USER_AGENT_KEY = "User-Agent";
|
protected static final String USER_AGENT_KEY = "User-Agent";
|
||||||
protected static final String USER_AGENT_NAME = Constants.CATALOGUE_NAME;
|
protected static final String USER_AGENT_NAME = "gCat";
|
||||||
|
|
||||||
public enum HTTPMETHOD {
|
|
||||||
HEAD, GET, POST, PUT, DELETE;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return this.name();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final String PATH_SEPARATOR = "/";
|
|
||||||
public static final String PARAM_STARTER = "?";
|
|
||||||
public static final String PARAM_EQUALS = "=";
|
|
||||||
public static final String PARAM_SEPARATOR = "&";
|
|
||||||
public static final String UTF8 = "UTF-8";
|
|
||||||
|
|
||||||
protected final String address;
|
protected final String address;
|
||||||
protected final String userAgent;
|
|
||||||
|
|
||||||
protected Map<String,String> headers;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When the target service is a gCube Service it adds the HTTP header
|
* When the target service is a gCube Service it adds the HTTP header
|
||||||
* to provide gCube authorization token and/or scope
|
* to provide gCube authorization token and/or scope
|
||||||
*/
|
*/
|
||||||
protected boolean gCubeTargetService;
|
protected boolean gCubeTargetService;
|
||||||
|
|
||||||
public boolean isgCubeTargetService() {
|
public boolean isgCubeTargetService() {
|
||||||
return gCubeTargetService;
|
return gCubeTargetService;
|
||||||
}
|
}
|
||||||
|
@ -70,63 +35,7 @@ public class HTTPCall {
|
||||||
|
|
||||||
protected HTTPCall(String address, String userAgent) {
|
protected HTTPCall(String address, String userAgent) {
|
||||||
this.address = address;
|
this.address = address;
|
||||||
this.userAgent = userAgent;
|
|
||||||
this.gCubeTargetService = true;
|
this.gCubeTargetService = true;
|
||||||
this.headers = new HashMap<>();
|
|
||||||
addHeader(USER_AGENT_KEY, this.userAgent);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addHeader(String key, String value) {
|
|
||||||
headers.put(key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String getParametersDataString(Map<String,String> parameters) throws UnsupportedEncodingException {
|
|
||||||
|
|
||||||
if(parameters == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
StringBuilder result = new StringBuilder();
|
|
||||||
boolean first = true;
|
|
||||||
for(String key : parameters.keySet()) {
|
|
||||||
if(first) {
|
|
||||||
first = false;
|
|
||||||
} else {
|
|
||||||
result.append(PARAM_SEPARATOR);
|
|
||||||
}
|
|
||||||
|
|
||||||
result.append(URLEncoder.encode(key, UTF8));
|
|
||||||
result.append(PARAM_EQUALS);
|
|
||||||
result.append(URLEncoder.encode(parameters.get(key), UTF8));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return result.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected URL getURL(String address, String path, String urlParameters) throws MalformedURLException {
|
|
||||||
|
|
||||||
StringWriter stringWriter = new StringWriter();
|
|
||||||
stringWriter.append(address);
|
|
||||||
|
|
||||||
if(address.endsWith(PATH_SEPARATOR)) {
|
|
||||||
if(path.startsWith(PATH_SEPARATOR)) {
|
|
||||||
path = path.substring(1);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if(path.compareTo("") != 0 && !path.startsWith(PATH_SEPARATOR)) {
|
|
||||||
stringWriter.append(PATH_SEPARATOR);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stringWriter.append(path);
|
|
||||||
|
|
||||||
if(urlParameters != null) {
|
|
||||||
stringWriter.append(PARAM_STARTER);
|
|
||||||
stringWriter.append(urlParameters);
|
|
||||||
}
|
|
||||||
|
|
||||||
return getURL(stringWriter.toString());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected URL getURL(String urlString) throws MalformedURLException {
|
protected URL getURL(String urlString) throws MalformedURLException {
|
||||||
|
@ -137,27 +46,23 @@ public class HTTPCall {
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected HttpURLConnection getConnection(String path, String urlParameters, HTTPMETHOD method, String body,
|
|
||||||
InputStream inputStream, String contentType) throws Exception {
|
|
||||||
URL url = getURL(address, path, urlParameters);
|
|
||||||
return getConnection(url, method, body, inputStream, contentType);
|
|
||||||
}
|
|
||||||
|
|
||||||
public URL getFinalURL(URL url) {
|
public URL getFinalURL(URL url) {
|
||||||
try {
|
try {
|
||||||
URL finalURL = url;
|
URL finalURL = url;
|
||||||
|
|
||||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||||
connection.setInstanceFollowRedirects(false);
|
connection.setInstanceFollowRedirects(false);
|
||||||
|
connection.setRequestProperty(USER_AGENT_KEY, USER_AGENT_NAME);
|
||||||
|
// connection.setRequestMethod(HEAD.class.getSimpleName());
|
||||||
|
|
||||||
int responseCode = connection.getResponseCode();
|
int responseCode = connection.getResponseCode();
|
||||||
String responseMessage = connection.getResponseMessage();
|
|
||||||
|
|
||||||
if(responseCode >= Status.BAD_REQUEST.getStatusCode()) {
|
if(responseCode >= Status.BAD_REQUEST.getStatusCode()) {
|
||||||
Status status = Status.fromStatusCode(responseCode);
|
Status status = Status.fromStatusCode(responseCode);
|
||||||
|
String responseMessage = connection.getResponseMessage();
|
||||||
throw new WebApplicationException(responseMessage, status);
|
throw new WebApplicationException(responseMessage, status);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(responseCode == HttpURLConnection.HTTP_MOVED_TEMP || responseCode == HttpURLConnection.HTTP_MOVED_PERM
|
if(responseCode == HttpURLConnection.HTTP_MOVED_TEMP || responseCode == HttpURLConnection.HTTP_MOVED_PERM
|
||||||
|| responseCode == HttpURLConnection.HTTP_SEE_OTHER
|
|| responseCode == HttpURLConnection.HTTP_SEE_OTHER
|
||||||
|| responseCode == Status.TEMPORARY_REDIRECT.getStatusCode() || responseCode == 308) {
|
|| responseCode == Status.TEMPORARY_REDIRECT.getStatusCode() || responseCode == 308) {
|
||||||
|
@ -168,140 +73,6 @@ public class HTTPCall {
|
||||||
|
|
||||||
return finalURL;
|
return finalURL;
|
||||||
|
|
||||||
}catch (WebApplicationException e) {
|
|
||||||
throw e;
|
|
||||||
}catch (Exception e) {
|
|
||||||
throw new InternalServerErrorException(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected HttpURLConnection getConnection(URL url, HTTPMETHOD method, String body, InputStream inputStream,
|
|
||||||
String contentType) throws Exception {
|
|
||||||
|
|
||||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
|
||||||
|
|
||||||
if(gCubeTargetService) {
|
|
||||||
if(SecurityTokenProvider.instance.get() == null) {
|
|
||||||
if(ScopeProvider.instance.get() == null) {
|
|
||||||
throw new RuntimeException("Null Token and Scope. Please set your token first.");
|
|
||||||
}
|
|
||||||
connection.setRequestProperty("gcube-scope", ScopeProvider.instance.get());
|
|
||||||
} else {
|
|
||||||
connection.setRequestProperty(org.gcube.common.authorization.client.Constants.TOKEN_HEADER_ENTRY,
|
|
||||||
SecurityTokenProvider.instance.get());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
connection.setDoOutput(true);
|
|
||||||
|
|
||||||
connection.setRequestProperty("Content-type", contentType);
|
|
||||||
for(String key : headers.keySet()) {
|
|
||||||
connection.setRequestProperty(key, headers.get(key));
|
|
||||||
}
|
|
||||||
|
|
||||||
connection.setRequestMethod(method.toString());
|
|
||||||
|
|
||||||
if(inputStream != null && (method == HTTPMETHOD.POST || method == HTTPMETHOD.PUT)) {
|
|
||||||
|
|
||||||
DataOutputStream wr = new DataOutputStream(connection.getOutputStream());
|
|
||||||
byte[] buffer = new byte[1024];
|
|
||||||
|
|
||||||
int len;
|
|
||||||
while((len = inputStream.read(buffer)) > 0) {
|
|
||||||
wr.write(buffer, 0, len);
|
|
||||||
}
|
|
||||||
wr.flush();
|
|
||||||
wr.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
if(body != null && (method == HTTPMETHOD.POST || method == HTTPMETHOD.PUT)) {
|
|
||||||
|
|
||||||
DataOutputStream wr = new DataOutputStream(connection.getOutputStream());
|
|
||||||
wr.writeBytes(body);
|
|
||||||
wr.flush();
|
|
||||||
wr.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
int responseCode = connection.getResponseCode();
|
|
||||||
String responseMessage = connection.getResponseMessage();
|
|
||||||
logger.trace("{} {} : {} - {}", method, connection.getURL(), responseCode, responseMessage);
|
|
||||||
|
|
||||||
// 308 Permanent Redirect https://tools.ietf.org/html/rfc7538#section-3
|
|
||||||
if(responseCode == HttpURLConnection.HTTP_MOVED_TEMP || responseCode == HttpURLConnection.HTTP_MOVED_PERM
|
|
||||||
|| responseCode == HttpURLConnection.HTTP_SEE_OTHER
|
|
||||||
|| responseCode == Status.TEMPORARY_REDIRECT.getStatusCode() || responseCode == 308) {
|
|
||||||
|
|
||||||
URL redirectURL = getURL(connection.getHeaderField("Location"));
|
|
||||||
|
|
||||||
logger.trace("{} is going to be redirect to {}", url.toString(), redirectURL.toString());
|
|
||||||
|
|
||||||
connection = getConnection(redirectURL, method, body, inputStream, contentType);
|
|
||||||
}
|
|
||||||
|
|
||||||
return connection;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
protected StringBuilder getStringBuilder(InputStream inputStream) throws IOException {
|
|
||||||
StringBuilder result = new StringBuilder();
|
|
||||||
try(BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
|
|
||||||
String line;
|
|
||||||
while((line = reader.readLine()) != null) {
|
|
||||||
result.append(line);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String call(String path, HTTPMETHOD method, Map<String,String> parameters, String contentType) {
|
|
||||||
return call(path, method, parameters, null, contentType);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String call(String path, HTTPMETHOD method, String body, String contentType) {
|
|
||||||
return call(path, method, null, body, contentType);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String call(String path, HTTPMETHOD method, Map<String,String> parameters, String body, String contentType) {
|
|
||||||
return call(path, method, body, null, parameters, contentType);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String call(String path, HTTPMETHOD method, InputStream inputStream, Map<String,String> parameters,
|
|
||||||
String contentType) {
|
|
||||||
return call(path, method, null, inputStream, parameters, contentType);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String call(String path, HTTPMETHOD method, String body, InputStream inputStream,
|
|
||||||
Map<String,String> parameters, String contentType) {
|
|
||||||
HttpURLConnection connection;
|
|
||||||
try {
|
|
||||||
String urlParameters = getParametersDataString(parameters);
|
|
||||||
connection = getConnection(path, urlParameters, method, body, inputStream, contentType);
|
|
||||||
int responseCode = connection.getResponseCode();
|
|
||||||
String responseMessage = connection.getResponseMessage();
|
|
||||||
logger.info("{} {} : {} - {}", method, connection.getURL(), responseCode, responseMessage);
|
|
||||||
|
|
||||||
if(responseCode >= Status.BAD_REQUEST.getStatusCode()) {
|
|
||||||
try {
|
|
||||||
StringBuilder result = getStringBuilder(connection.getErrorStream());
|
|
||||||
String res = result.toString();
|
|
||||||
logger.trace("Server returned content : {}", res);
|
|
||||||
return res;
|
|
||||||
}catch (Exception e) {
|
|
||||||
Status status = Status.fromStatusCode(responseCode);
|
|
||||||
throw new WebApplicationException(responseMessage, status);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
StringBuilder result = getStringBuilder(connection.getInputStream());
|
|
||||||
String res = result.toString();
|
|
||||||
logger.trace("Server returned content : {}", res);
|
|
||||||
|
|
||||||
connection.disconnect();
|
|
||||||
|
|
||||||
return res;
|
|
||||||
|
|
||||||
} catch(WebApplicationException e) {
|
} catch(WebApplicationException e) {
|
||||||
throw e;
|
throw e;
|
||||||
} catch(Exception e) {
|
} catch(Exception e) {
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
package org.gcube.gcat.utils;
|
package org.gcube.gcat.utils;
|
||||||
|
|
||||||
import javax.ws.rs.WebApplicationException;
|
import java.net.HttpURLConnection;
|
||||||
import javax.ws.rs.core.MediaType;
|
|
||||||
|
|
||||||
|
import javax.ws.rs.WebApplicationException;
|
||||||
|
|
||||||
|
import org.gcube.common.gxhttp.request.GXHTTPStringRequest;
|
||||||
import org.gcube.datacatalogue.ckanutillibrary.server.DataCatalogue;
|
import org.gcube.datacatalogue.ckanutillibrary.server.DataCatalogue;
|
||||||
import org.gcube.datacatalogue.ckanutillibrary.server.utils.url.EntityContext;
|
import org.gcube.datacatalogue.ckanutillibrary.server.utils.url.EntityContext;
|
||||||
import org.gcube.gcat.persistence.ckan.CKAN;
|
import org.gcube.gcat.persistence.ckan.CKAN;
|
||||||
import org.gcube.gcat.utils.HTTPCall.HTTPMETHOD;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||||
|
@ -29,18 +30,20 @@ public class URIResolver {
|
||||||
DataCatalogue dataCatalogue = CKAN.getCatalogue();
|
DataCatalogue dataCatalogue = CKAN.getCatalogue();
|
||||||
String uriResolverURL = dataCatalogue.getUriResolverUrl();
|
String uriResolverURL = dataCatalogue.getUriResolverUrl();
|
||||||
|
|
||||||
HTTPCall httpCall = new HTTPCall(uriResolverURL);
|
|
||||||
|
|
||||||
ObjectNode requestContent = objectMapper.createObjectNode();
|
ObjectNode requestContent = objectMapper.createObjectNode();
|
||||||
requestContent.put(CATALOGUE_CONTEXT, ContextUtility.getCurrentContext());
|
requestContent.put(CATALOGUE_CONTEXT, ContextUtility.getCurrentContext());
|
||||||
requestContent.put(ENTITY_TYPE, EntityContext.PRODUCT.toString());
|
requestContent.put(ENTITY_TYPE, EntityContext.PRODUCT.toString());
|
||||||
requestContent.put(ENTITY_NAME, name);
|
requestContent.put(ENTITY_NAME, name);
|
||||||
requestContent.put(CATALOGUE_PLAIN_URL, true);
|
requestContent.put(CATALOGUE_PLAIN_URL, true);
|
||||||
|
|
||||||
String url = httpCall.call("", HTTPMETHOD.POST, objectMapper.writeValueAsString(requestContent),
|
GXHTTPStringRequest gxhttpStringRequest = GXHTTPStringRequest.newRequest(uriResolverURL);
|
||||||
MediaType.APPLICATION_JSON);
|
gxhttpStringRequest.header("User-Agent", Constants.CATALOGUE_NAME);
|
||||||
|
HttpURLConnection httpURLConnection = gxhttpStringRequest.post(objectMapper.writeValueAsString(requestContent));
|
||||||
|
|
||||||
|
String url = httpURLConnection.getResponseMessage();
|
||||||
|
|
||||||
return url;
|
return url;
|
||||||
|
|
||||||
} catch(Exception e) {
|
} catch(Exception e) {
|
||||||
throw new WebApplicationException(e);
|
throw new WebApplicationException(e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
package org.gcube.gcat.workspace;
|
||||||
|
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.gcube.common.storagehub.model.Metadata;
|
||||||
|
import org.gcube.storagehub.MetadataMatcher;
|
||||||
|
|
||||||
|
public class CatalogueMetadata implements MetadataMatcher {
|
||||||
|
|
||||||
|
public static final String ORIGINAL_URL = "OriginalURL";
|
||||||
|
public static final String ORIGINAL_NAME = "OriginalName";
|
||||||
|
|
||||||
|
public static final String CATALOGUE_ITEM_ID = "CatalogueItemID";
|
||||||
|
public static final String CATALOGUE_RESOURCE_ID = "CatalogueResourceID";
|
||||||
|
public static final String CATALOGUE_RESOURCE_REVISION_ID = "CatalogueResourceRevisionID";
|
||||||
|
|
||||||
|
protected String itemID;
|
||||||
|
|
||||||
|
public CatalogueMetadata(String itemID) {
|
||||||
|
this.itemID = itemID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean check(Metadata metadata) {
|
||||||
|
Map<String,Object> map = metadata.getMap();
|
||||||
|
if(map.get(CATALOGUE_ITEM_ID).toString().compareTo(itemID) == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Metadata getMetadata(URL url, String originalName, String resourceID) {
|
||||||
|
Map<String,Object> map = new HashMap<>();
|
||||||
|
map.put(ORIGINAL_URL, url.toString());
|
||||||
|
map.put(ORIGINAL_NAME, originalName);
|
||||||
|
map.put(CATALOGUE_ITEM_ID, itemID);
|
||||||
|
map.put(CATALOGUE_RESOURCE_ID, resourceID);
|
||||||
|
Metadata metadata = new Metadata(map);
|
||||||
|
return metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,109 @@
|
||||||
|
package org.gcube.gcat.workspace;
|
||||||
|
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.text.ParseException;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.gcube.common.gxhttp.request.GXHTTPStringRequest;
|
||||||
|
import org.gcube.common.storagehub.client.dsl.FileContainer;
|
||||||
|
import org.gcube.common.storagehub.model.Metadata;
|
||||||
|
import org.gcube.gcat.utils.Constants;
|
||||||
|
import org.gcube.storagehub.ApplicationMode;
|
||||||
|
import org.gcube.storagehub.StorageHubManagement;
|
||||||
|
import org.glassfish.jersey.media.multipart.ContentDisposition;
|
||||||
|
|
||||||
|
public class CatalogueStorageHubManagement {
|
||||||
|
|
||||||
|
protected StorageHubManagement storageHubManagement;
|
||||||
|
|
||||||
|
protected String originalFilename;
|
||||||
|
protected String mimeType;
|
||||||
|
|
||||||
|
public String getOriginalFilename() {
|
||||||
|
return originalFilename;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMimeType() {
|
||||||
|
return mimeType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CatalogueStorageHubManagement() {
|
||||||
|
this.storageHubManagement = new StorageHubManagement();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getOriginalFileName(HttpURLConnection httpURLConnection) throws ParseException {
|
||||||
|
String contentDisposition = httpURLConnection.getHeaderFields().get("Content-Disposition").get(0);
|
||||||
|
contentDisposition = contentDisposition.replaceAll("= ", "=").replaceAll(" =", "=");
|
||||||
|
ContentDisposition formDataContentDisposition = new ContentDisposition(contentDisposition);
|
||||||
|
return formDataContentDisposition.getFileName();
|
||||||
|
}
|
||||||
|
|
||||||
|
public URL ensureResourcePersistence(URL persistedURL, String itemID, String resourceID) throws Exception {
|
||||||
|
ApplicationMode applicationMode = new ApplicationMode(Constants.getCatalogueApplicationToken());
|
||||||
|
try {
|
||||||
|
applicationMode.start();
|
||||||
|
GXHTTPStringRequest gxhttpStringRequest = GXHTTPStringRequest.newRequest(persistedURL.toString());
|
||||||
|
gxhttpStringRequest.isExternalCall(true);
|
||||||
|
HttpURLConnection httpURLConnection = gxhttpStringRequest.get();
|
||||||
|
mimeType = httpURLConnection.getContentType().split(";")[0];
|
||||||
|
originalFilename = getOriginalFileName(httpURLConnection);
|
||||||
|
CatalogueMetadata catalogueMetadata = new CatalogueMetadata(itemID);
|
||||||
|
storageHubManagement.setCheckMetadata(catalogueMetadata);
|
||||||
|
Metadata metadata = catalogueMetadata.getMetadata(persistedURL, originalFilename, resourceID);
|
||||||
|
persistedURL = storageHubManagement.persistFile(httpURLConnection.getInputStream(), resourceID, mimeType, metadata);
|
||||||
|
mimeType = storageHubManagement.getMimeType();
|
||||||
|
return persistedURL;
|
||||||
|
} finally {
|
||||||
|
applicationMode.end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deleteResourcePersistence(String itemID, String resourceID, String mimeType) throws Exception {
|
||||||
|
ApplicationMode applicationMode = new ApplicationMode(Constants.getCatalogueApplicationToken());
|
||||||
|
try {
|
||||||
|
applicationMode.start();
|
||||||
|
storageHubManagement = new StorageHubManagement();
|
||||||
|
CatalogueMetadata catalogueMetadata = new CatalogueMetadata(itemID);
|
||||||
|
storageHubManagement.setCheckMetadata(catalogueMetadata);
|
||||||
|
storageHubManagement.removePersistedFile(resourceID, mimeType);
|
||||||
|
} finally {
|
||||||
|
applicationMode.end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected void internalAddRevisionID(String resourceID, String revisionID) {
|
||||||
|
FileContainer fileContainer = storageHubManagement.getCreatedFile();
|
||||||
|
Metadata metadata = fileContainer.get().getMetadata();
|
||||||
|
Map<String,Object> map = metadata.getMap();
|
||||||
|
map.put(CatalogueMetadata.CATALOGUE_RESOURCE_ID, resourceID);
|
||||||
|
map.put(CatalogueMetadata.CATALOGUE_RESOURCE_REVISION_ID, revisionID);
|
||||||
|
metadata.setMap(map);
|
||||||
|
fileContainer.setMetadata(metadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void renameFile(String resourceID, String revisionID) {
|
||||||
|
ApplicationMode applicationMode = new ApplicationMode(Constants.getCatalogueApplicationToken());
|
||||||
|
try {
|
||||||
|
applicationMode.start();
|
||||||
|
FileContainer createdfile = storageHubManagement.getCreatedFile();
|
||||||
|
createdfile.rename(resourceID);
|
||||||
|
internalAddRevisionID(resourceID, revisionID);
|
||||||
|
}finally {
|
||||||
|
applicationMode.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addRevisionID(String resourceID, String revisionID) {
|
||||||
|
ApplicationMode applicationMode = new ApplicationMode(Constants.getCatalogueApplicationToken());
|
||||||
|
try {
|
||||||
|
applicationMode.start();
|
||||||
|
internalAddRevisionID(resourceID, revisionID);
|
||||||
|
}finally {
|
||||||
|
applicationMode.end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,295 +0,0 @@
|
||||||
package org.gcube.gcat.workspace;
|
|
||||||
|
|
||||||
import java.io.StringWriter;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import javax.ws.rs.InternalServerErrorException;
|
|
||||||
|
|
||||||
import org.gcube.common.homelibrary.home.Home;
|
|
||||||
import org.gcube.common.homelibrary.home.HomeLibrary;
|
|
||||||
import org.gcube.common.homelibrary.home.HomeManager;
|
|
||||||
import org.gcube.common.homelibrary.home.HomeManagerFactory;
|
|
||||||
import org.gcube.common.homelibrary.home.User;
|
|
||||||
import org.gcube.common.homelibrary.home.workspace.Workspace;
|
|
||||||
import org.gcube.common.storagehub.client.StreamDescriptor;
|
|
||||||
import org.gcube.common.storagehub.client.dsl.ContainerType;
|
|
||||||
import org.gcube.common.storagehub.client.dsl.FileContainer;
|
|
||||||
import org.gcube.common.storagehub.client.dsl.FolderContainer;
|
|
||||||
import org.gcube.common.storagehub.client.dsl.ItemContainer;
|
|
||||||
import org.gcube.common.storagehub.client.dsl.ListResolver;
|
|
||||||
import org.gcube.common.storagehub.client.dsl.ListResolverTyped;
|
|
||||||
import org.gcube.common.storagehub.client.dsl.OpenResolver;
|
|
||||||
import org.gcube.common.storagehub.client.dsl.StorageHubClient;
|
|
||||||
import org.gcube.common.storagehub.model.Metadata;
|
|
||||||
import org.gcube.common.storagehub.model.items.AbstractFileItem;
|
|
||||||
import org.gcube.common.storagehub.model.items.Item;
|
|
||||||
import org.gcube.gcat.utils.Constants;
|
|
||||||
import org.gcube.gcat.utils.ContextUtility;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
public class StorageHubManagement {
|
|
||||||
|
|
||||||
private static final Logger logger = LoggerFactory.getLogger(StorageHubManagement.class);
|
|
||||||
|
|
||||||
public static final String ORIGINAL_URL = "OriginalURL";
|
|
||||||
public static final String ORIGINAL_NAME = "OriginalName";
|
|
||||||
|
|
||||||
public static final String CATALOGUE_ITEM_ID = "CatalogueItemID";
|
|
||||||
public static final String CATALOGUE_RESOURCE_ID = "CatalogueResourceID";
|
|
||||||
public static final String CATALOGUE_RESOURCE_REVISION_ID = "CatalogueResourceRevisionID";
|
|
||||||
|
|
||||||
public static final String CATALOGUE_FOLDER_DESCRIPTION = "Catalogue Folder used to persist Resources";
|
|
||||||
|
|
||||||
protected final StorageHubClient storageHubClient;
|
|
||||||
|
|
||||||
protected FileContainer createdFile;
|
|
||||||
protected String mimeType;
|
|
||||||
|
|
||||||
public String getMimeType() {
|
|
||||||
return mimeType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public StorageHubManagement() {
|
|
||||||
storageHubClient = new StorageHubClient();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void recursiveList(FolderContainer folder, int level) {
|
|
||||||
ListResolverTyped listResolverTyped = folder.list();
|
|
||||||
List<ItemContainer<? extends Item>> containers = listResolverTyped.getContainers();
|
|
||||||
for(ItemContainer<? extends Item> itemContainer : containers) {
|
|
||||||
Item item = itemContainer.get();
|
|
||||||
String name = item.getName();
|
|
||||||
ContainerType containerType = itemContainer.getType();
|
|
||||||
StringWriter indent = new StringWriter(level + 1);
|
|
||||||
for(int i = 0; i < level + 1; i++) {
|
|
||||||
indent.append('-');
|
|
||||||
}
|
|
||||||
logger.debug("{} {} {} (ID:{})", indent.toString(), containerType, name, itemContainer.getId());
|
|
||||||
switch(containerType) {
|
|
||||||
case FOLDER:
|
|
||||||
FolderContainer folderContainer = (FolderContainer) itemContainer;
|
|
||||||
//if(item.getName().compareTo("553095a0-a14a-4e41-b014-2e6f3a1aeac7")!=0)
|
|
||||||
recursiveList(folderContainer, level + 1);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FILE:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case GENERIC_ITEM:
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected FolderContainer getWorkspaceRoot() {
|
|
||||||
try {
|
|
||||||
return storageHubClient.getWSRoot();
|
|
||||||
}catch (Exception e) {
|
|
||||||
String username = ContextUtility.getUsername();
|
|
||||||
logger.info("Unable to obtain the Workspace Root for {}. Going to create it.", username);
|
|
||||||
try {
|
|
||||||
HomeManagerFactory factory = HomeLibrary.getHomeManagerFactory();
|
|
||||||
HomeManager manager = factory.getHomeManager();
|
|
||||||
User user = manager.createUser(username);
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
Home home = manager.getHome(user);
|
|
||||||
Workspace ws = home.getWorkspace();
|
|
||||||
ws.getRoot();
|
|
||||||
return storageHubClient.getWSRoot();
|
|
||||||
}catch (Exception ex) {
|
|
||||||
logger.info("Unable to create the Workspace Root for {}.", username);
|
|
||||||
throw new InternalServerErrorException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected FolderContainer getOrCreateFolder(FolderContainer parent, String name, String description) {
|
|
||||||
try {
|
|
||||||
FolderContainer destinationFolder = null;
|
|
||||||
ListResolverTyped listResolverTyped = parent.list();
|
|
||||||
List<ItemContainer<? extends Item>> containers = listResolverTyped.getContainers();
|
|
||||||
for(ItemContainer<? extends Item> itemContainer : containers) {
|
|
||||||
if(itemContainer instanceof FolderContainer) {
|
|
||||||
if(itemContainer.get().getName().compareTo(name) == 0) {
|
|
||||||
destinationFolder = (FolderContainer) itemContainer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(destinationFolder == null) {
|
|
||||||
destinationFolder = parent.newFolder(name, description);
|
|
||||||
}
|
|
||||||
return destinationFolder;
|
|
||||||
} catch(Exception e) {
|
|
||||||
throw new InternalServerErrorException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getFolderName() {
|
|
||||||
String currentContext = ContextUtility.getCurrentContext();
|
|
||||||
String folderName = currentContext.replaceFirst("/", "").replace("/", "_");
|
|
||||||
return folderName;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected FolderContainer getCatalogueFolder() {
|
|
||||||
FolderContainer destinationFolder = getWorkspaceRoot();
|
|
||||||
String folderName = getFolderName();
|
|
||||||
destinationFolder = getOrCreateFolder(destinationFolder, folderName, ContextUtility.getCurrentContext() + " folder");
|
|
||||||
destinationFolder = getOrCreateFolder(destinationFolder, Constants.CATALOGUE_NAME, CATALOGUE_FOLDER_DESCRIPTION);
|
|
||||||
return destinationFolder;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected FolderContainer getDestinationFolder(AbstractFileItem item) {
|
|
||||||
FolderContainer destinationFolder = getCatalogueFolder();
|
|
||||||
mimeType = item.getContent().getMimeType();
|
|
||||||
String[] splittedMimeType = mimeType.split("/");
|
|
||||||
for(String name : splittedMimeType) {
|
|
||||||
try {
|
|
||||||
destinationFolder = getOrCreateFolder(destinationFolder, name,
|
|
||||||
"Automatic Folder Created using mimetype");
|
|
||||||
} catch(Exception e) {
|
|
||||||
throw new InternalServerErrorException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return destinationFolder;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected FileContainer copyFile(FileContainer sourceFileContainer, FolderContainer destinationFolder,
|
|
||||||
String copiedFilename) {
|
|
||||||
StreamDescriptor streamDescriptor = sourceFileContainer.download("");
|
|
||||||
FileContainer createdFile = destinationFolder.uploadFile(streamDescriptor.getStream(), copiedFilename,
|
|
||||||
sourceFileContainer.get().getDescription());
|
|
||||||
/*
|
|
||||||
FileContainer copiedFile = sourceFileContainer.copy(destinationFolder, copiedFilename);
|
|
||||||
*/
|
|
||||||
return createdFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected ItemContainer<? extends Item> getContainerByStorageURL(URL url) {
|
|
||||||
URL finalURL = url;
|
|
||||||
String path = finalURL.getPath();
|
|
||||||
String fileID = path.substring(path.lastIndexOf('/') + 1);
|
|
||||||
|
|
||||||
OpenResolver openResolver = storageHubClient.open(fileID);
|
|
||||||
ItemContainer<Item> itemContainer = openResolver.asItem();
|
|
||||||
Item item = itemContainer.get();
|
|
||||||
if(item instanceof AbstractFileItem) {
|
|
||||||
logger.debug("The resource with ID {} is a file", fileID);
|
|
||||||
return openResolver.asFile();
|
|
||||||
}
|
|
||||||
return itemContainer;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected boolean isItemPersistedFile(FileContainer fileContainer, FolderContainer destinationFolder, String itemID) {
|
|
||||||
// Checking if the file is already a file of the science catalogue folder of the scope related to such an item.
|
|
||||||
ListResolver listResolver = fileContainer.getAnchestors();
|
|
||||||
List<ItemContainer<? extends Item>> itemContainers = listResolver.getContainers();
|
|
||||||
for(ItemContainer<? extends Item> itemContainer : itemContainers) {
|
|
||||||
if(itemContainer.getId().compareTo(destinationFolder.getId()) == 0) {
|
|
||||||
Metadata metadata = fileContainer.get().getPropertyMap();
|
|
||||||
Map<String,Object> map = metadata.getValues();
|
|
||||||
if(map.get(CATALOGUE_ITEM_ID).toString().compareTo(itemID) == 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isItemPersistedFile(URL url, String itemID) {
|
|
||||||
ItemContainer<? extends Item> itemContainer = getContainerByStorageURL(url);
|
|
||||||
FileContainer fileContainer;
|
|
||||||
if(itemContainer instanceof FileContainer) {
|
|
||||||
fileContainer = (FileContainer) itemContainer;
|
|
||||||
}else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
FolderContainer destinationFolder = getDestinationFolder(fileContainer.get());
|
|
||||||
return isItemPersistedFile(fileContainer, destinationFolder, itemID);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void tree(FolderContainer folderContainer) throws Exception {
|
|
||||||
logger.debug("{} (ID:{})", folderContainer.get().getName(), folderContainer.getId());
|
|
||||||
recursiveList(folderContainer, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected FileContainer getFileByID(String id) throws Exception {
|
|
||||||
OpenResolver openResolver = storageHubClient.open(id);
|
|
||||||
FileContainer fileContainer = (FileContainer) openResolver.asFile();
|
|
||||||
return fileContainer;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void deleteFileByID(String id) throws Exception {
|
|
||||||
FileContainer fileContainer = getFileByID(id);
|
|
||||||
fileContainer.delete();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public URL ensureResourcePersistence(URL url, String itemID, String resourceID, String name) {
|
|
||||||
ItemContainer<? extends Item> itemContainer = getContainerByStorageURL(url);
|
|
||||||
FileContainer fileContainer;
|
|
||||||
if(itemContainer instanceof FileContainer) {
|
|
||||||
fileContainer = (FileContainer) itemContainer;
|
|
||||||
}else {
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
|
|
||||||
FolderContainer destinationFolder = getDestinationFolder(fileContainer.get());
|
|
||||||
|
|
||||||
if(isItemPersistedFile(fileContainer, destinationFolder, itemID)) {
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
|
|
||||||
createdFile = copyFile(fileContainer, destinationFolder, resourceID);
|
|
||||||
|
|
||||||
Map<String,Object> map = new HashMap<>();
|
|
||||||
map.put(ORIGINAL_URL, url.toString());
|
|
||||||
map.put(ORIGINAL_NAME, name);
|
|
||||||
map.put(CATALOGUE_ITEM_ID, itemID);
|
|
||||||
map.put(CATALOGUE_RESOURCE_ID, resourceID);
|
|
||||||
Metadata metadata = new Metadata(map);
|
|
||||||
createdFile.setMetadata(metadata);
|
|
||||||
|
|
||||||
URL finalURL = createdFile.getPublicLink();
|
|
||||||
logger.debug("Original File URL was {} - Final URL to ensure persistency is {}", url, finalURL);
|
|
||||||
return finalURL;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void deleteResourcePersistence(URL url, String itemID) {
|
|
||||||
FileContainer fileContainer = (FileContainer) getContainerByStorageURL(url);
|
|
||||||
FolderContainer destinationFolder = getDestinationFolder(fileContainer.get());
|
|
||||||
if(isItemPersistedFile(fileContainer, destinationFolder, itemID)) {
|
|
||||||
fileContainer.delete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void addRevisionID(FileContainer fileContainer, String resourceID, String revisionID) {
|
|
||||||
Metadata metadata = fileContainer.get().getPropertyMap();
|
|
||||||
Map<String,Object> map = metadata.getValues();
|
|
||||||
map.put(CATALOGUE_RESOURCE_ID, resourceID);
|
|
||||||
map.put(CATALOGUE_RESOURCE_REVISION_ID, revisionID);
|
|
||||||
metadata.setValues(map);
|
|
||||||
fileContainer.setMetadata(metadata);;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addRevisionID(String resourceID, String revisionID) {
|
|
||||||
addRevisionID(createdFile, resourceID, revisionID);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void renameFile(String resourceID, String revisionID) {
|
|
||||||
renameFile(createdFile, resourceID);
|
|
||||||
addRevisionID(createdFile, resourceID, revisionID);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void renameFile(FileContainer fileContainer, String newName) {
|
|
||||||
fileContainer.rename(newName);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,316 +0,0 @@
|
||||||
gCube System - License
|
|
||||||
------------------------------------------------------------
|
|
||||||
|
|
||||||
European Union Public Licence V. 1.1
|
|
||||||
|
|
||||||
|
|
||||||
EUPL © the European Community 2007
|
|
||||||
|
|
||||||
|
|
||||||
This European Union Public Licence (the “EUPL”) applies to the Work or Software
|
|
||||||
(as defined below) which is provided under the terms of this Licence. Any use of
|
|
||||||
the Work, other than as authorised under this Licence is prohibited (to the
|
|
||||||
extent such use is covered by a right of the copyright holder of the Work).
|
|
||||||
|
|
||||||
The Original Work is provided under the terms of this Licence when the Licensor
|
|
||||||
(as defined below) has placed the following notice immediately following the
|
|
||||||
copyright notice for the Original Work:
|
|
||||||
|
|
||||||
Licensed under the EUPL V.1.1
|
|
||||||
|
|
||||||
or has expressed by any other mean his willingness to license under the EUPL.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
1. Definitions
|
|
||||||
|
|
||||||
In this Licence, the following terms have the following meaning:
|
|
||||||
|
|
||||||
- The Licence: this Licence.
|
|
||||||
|
|
||||||
- The Original Work or the Software: the software distributed and/or
|
|
||||||
communicated by the Licensor under this Licence, available as Source Code and
|
|
||||||
also as Executable Code as the case may be.
|
|
||||||
|
|
||||||
- Derivative Works: the works or software that could be created by the Licensee,
|
|
||||||
based upon the Original Work or modifications thereof. This Licence does not
|
|
||||||
define the extent of modification or dependence on the Original Work required
|
|
||||||
in order to classify a work as a Derivative Work; this extent is determined by
|
|
||||||
copyright law applicable in the country mentioned in Article 15.
|
|
||||||
|
|
||||||
- The Work: the Original Work and/or its Derivative Works.
|
|
||||||
|
|
||||||
- The Source Code: the human-readable form of the Work which is the most
|
|
||||||
convenient for people to study and modify.
|
|
||||||
|
|
||||||
- The Executable Code: any code which has generally been compiled and which is
|
|
||||||
meant to be interpreted by a computer as a program.
|
|
||||||
|
|
||||||
- The Licensor: the natural or legal person that distributes and/or communicates
|
|
||||||
the Work under the Licence.
|
|
||||||
|
|
||||||
- Contributor(s): any natural or legal person who modifies the Work under the
|
|
||||||
Licence, or otherwise contributes to the creation of a Derivative Work.
|
|
||||||
|
|
||||||
- The Licensee or “You”: any natural or legal person who makes any usage of the
|
|
||||||
Software under the terms of the Licence.
|
|
||||||
|
|
||||||
- Distribution and/or Communication: any act of selling, giving, lending,
|
|
||||||
renting, distributing, communicating, transmitting, or otherwise making
|
|
||||||
available, on-line or off-line, copies of the Work or providing access to its
|
|
||||||
essential functionalities at the disposal of any other natural or legal
|
|
||||||
person.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
2. Scope of the rights granted by the Licence
|
|
||||||
|
|
||||||
The Licensor hereby grants You a world-wide, royalty-free, non-exclusive,
|
|
||||||
sub-licensable licence to do the following, for the duration of copyright vested
|
|
||||||
in the Original Work:
|
|
||||||
|
|
||||||
- use the Work in any circumstance and for all usage, reproduce the Work, modify
|
|
||||||
- the Original Work, and make Derivative Works based upon the Work, communicate
|
|
||||||
- to the public, including the right to make available or display the Work or
|
|
||||||
- copies thereof to the public and perform publicly, as the case may be, the
|
|
||||||
- Work, distribute the Work or copies thereof, lend and rent the Work or copies
|
|
||||||
- thereof, sub-license rights in the Work or copies thereof.
|
|
||||||
|
|
||||||
Those rights can be exercised on any media, supports and formats, whether now
|
|
||||||
known or later invented, as far as the applicable law permits so.
|
|
||||||
|
|
||||||
In the countries where moral rights apply, the Licensor waives his right to
|
|
||||||
exercise his moral right to the extent allowed by law in order to make effective
|
|
||||||
the licence of the economic rights here above listed.
|
|
||||||
|
|
||||||
The Licensor grants to the Licensee royalty-free, non exclusive usage rights to
|
|
||||||
any patents held by the Licensor, to the extent necessary to make use of the
|
|
||||||
rights granted on the Work under this Licence.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
3. Communication of the Source Code
|
|
||||||
|
|
||||||
The Licensor may provide the Work either in its Source Code form, or as
|
|
||||||
Executable Code. If the Work is provided as Executable Code, the Licensor
|
|
||||||
provides in addition a machine-readable copy of the Source Code of the Work
|
|
||||||
along with each copy of the Work that the Licensor distributes or indicates, in
|
|
||||||
a notice following the copyright notice attached to the Work, a repository where
|
|
||||||
the Source Code is easily and freely accessible for as long as the Licensor
|
|
||||||
continues to distribute and/or communicate the Work.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
4. Limitations on copyright
|
|
||||||
|
|
||||||
Nothing in this Licence is intended to deprive the Licensee of the benefits from
|
|
||||||
any exception or limitation to the exclusive rights of the rights owners in the
|
|
||||||
Original Work or Software, of the exhaustion of those rights or of other
|
|
||||||
applicable limitations thereto.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
5. Obligations of the Licensee
|
|
||||||
|
|
||||||
The grant of the rights mentioned above is subject to some restrictions and
|
|
||||||
obligations imposed on the Licensee. Those obligations are the following:
|
|
||||||
|
|
||||||
Attribution right: the Licensee shall keep intact all copyright, patent or
|
|
||||||
trademarks notices and all notices that refer to the Licence and to the
|
|
||||||
disclaimer of warranties. The Licensee must include a copy of such notices and a
|
|
||||||
copy of the Licence with every copy of the Work he/she distributes and/or
|
|
||||||
communicates. The Licensee must cause any Derivative Work to carry prominent
|
|
||||||
notices stating that the Work has been modified and the date of modification.
|
|
||||||
|
|
||||||
Copyleft clause: If the Licensee distributes and/or communicates copies of the
|
|
||||||
Original Works or Derivative Works based upon the Original Work, this
|
|
||||||
Distribution and/or Communication will be done under the terms of this Licence
|
|
||||||
or of a later version of this Licence unless the Original Work is expressly
|
|
||||||
distributed only under this version of the Licence. The Licensee (becoming
|
|
||||||
Licensor) cannot offer or impose any additional terms or conditions on the Work
|
|
||||||
or Derivative Work that alter or restrict the terms of the Licence.
|
|
||||||
|
|
||||||
Compatibility clause: If the Licensee Distributes and/or Communicates Derivative
|
|
||||||
Works or copies thereof based upon both the Original Work and another work
|
|
||||||
licensed under a Compatible Licence, this Distribution and/or Communication can
|
|
||||||
be done under the terms of this Compatible Licence. For the sake of this clause,
|
|
||||||
“Compatible Licence” refers to the licences listed in the appendix attached to
|
|
||||||
this Licence. Should the Licensee’s obligations under the Compatible Licence
|
|
||||||
conflict with his/her obligations under this Licence, the obligations of the
|
|
||||||
Compatible Licence shall prevail.
|
|
||||||
|
|
||||||
Provision of Source Code: When distributing and/or communicating copies of the
|
|
||||||
Work, the Licensee will provide a machine-readable copy of the Source Code or
|
|
||||||
indicate a repository where this Source will be easily and freely available for
|
|
||||||
as long as the Licensee continues to distribute and/or communicate the Work.
|
|
||||||
|
|
||||||
Legal Protection: This Licence does not grant permission to use the trade names,
|
|
||||||
trademarks, service marks, or names of the Licensor, except as required for
|
|
||||||
reasonable and customary use in describing the origin of the Work and
|
|
||||||
reproducing the content of the copyright notice.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
6. Chain of Authorship
|
|
||||||
|
|
||||||
The original Licensor warrants that the copyright in the Original Work granted
|
|
||||||
hereunder is owned by him/her or licensed to him/her and that he/she has the
|
|
||||||
power and authority to grant the Licence.
|
|
||||||
|
|
||||||
Each Contributor warrants that the copyright in the modifications he/she brings
|
|
||||||
to the Work are owned by him/her or licensed to him/her and that he/she has the
|
|
||||||
power and authority to grant the Licence.
|
|
||||||
|
|
||||||
Each time You accept the Licence, the original Licensor and subsequent
|
|
||||||
Contributors grant You a licence to their contributions to the Work, under the
|
|
||||||
terms of this Licence.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
7. Disclaimer of Warranty
|
|
||||||
|
|
||||||
The Work is a work in progress, which is continuously improved by numerous
|
|
||||||
contributors. It is not a finished work and may therefore contain defects or
|
|
||||||
“bugs” inherent to this type of software development.
|
|
||||||
|
|
||||||
For the above reason, the Work is provided under the Licence on an “as is” basis
|
|
||||||
and without warranties of any kind concerning the Work, including without
|
|
||||||
limitation merchantability, fitness for a particular purpose, absence of defects
|
|
||||||
or errors, accuracy, non-infringement of intellectual property rights other than
|
|
||||||
copyright as stated in Article 6 of this Licence.
|
|
||||||
|
|
||||||
This disclaimer of warranty is an essential part of the Licence and a condition
|
|
||||||
for the grant of any rights to the Work.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
8. Disclaimer of Liability
|
|
||||||
|
|
||||||
Except in the cases of wilful misconduct or damages directly caused to natural
|
|
||||||
persons, the Licensor will in no event be liable for any direct or indirect,
|
|
||||||
material or moral, damages of any kind, arising out of the Licence or of the use
|
|
||||||
of the Work, including without limitation, damages for loss of goodwill, work
|
|
||||||
stoppage, computer failure or malfunction, loss of data or any commercial
|
|
||||||
damage, even if the Licensor has been advised of the possibility of such
|
|
||||||
damage. However, the Licensor will be liable under statutory product liability
|
|
||||||
laws as far such laws apply to the Work.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
9. Additional agreements
|
|
||||||
|
|
||||||
While distributing the Original Work or Derivative Works, You may choose to
|
|
||||||
conclude an additional agreement to offer, and charge a fee for, acceptance of
|
|
||||||
support, warranty, indemnity, or other liability obligations and/or services
|
|
||||||
consistent with this Licence. However, in accepting such obligations, You may
|
|
||||||
act only on your own behalf and on your sole responsibility, not on behalf of
|
|
||||||
the original Licensor or any other Contributor, and only if You agree to
|
|
||||||
indemnify, defend, and hold each Contributor harmless for any liability incurred
|
|
||||||
by, or claims asserted against such Contributor by the fact You have accepted
|
|
||||||
any such warranty or additional liability.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
10. Acceptance of the Licence
|
|
||||||
|
|
||||||
The provisions of this Licence can be accepted by clicking on an icon “I agree”
|
|
||||||
placed under the bottom of a window displaying the text of this Licence or by
|
|
||||||
affirming consent in any other similar way, in accordance with the rules of
|
|
||||||
applicable law. Clicking on that icon indicates your clear and irrevocable
|
|
||||||
acceptance of this Licence and all of its terms and conditions.
|
|
||||||
|
|
||||||
Similarly, you irrevocably accept this Licence and all of its terms and
|
|
||||||
conditions by exercising any rights granted to You by Article 2 of this Licence,
|
|
||||||
such as the use of the Work, the creation by You of a Derivative Work or the
|
|
||||||
Distribution and/or Communication by You of the Work or copies thereof.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
11. Information to the public
|
|
||||||
|
|
||||||
In case of any Distribution and/or Communication of the Work by means of
|
|
||||||
electronic communication by You (for example, by offering to download the Work
|
|
||||||
from a remote location) the distribution channel or media (for example, a
|
|
||||||
website) must at least provide to the public the information requested by the
|
|
||||||
applicable law regarding the Licensor, the Licence and the way it may be
|
|
||||||
accessible, concluded, stored and reproduced by the Licensee.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
12. Termination of the Licence
|
|
||||||
|
|
||||||
The Licence and the rights granted hereunder will terminate automatically upon
|
|
||||||
any breach by the Licensee of the terms of the Licence.
|
|
||||||
|
|
||||||
Such a termination will not terminate the licences of any person who has
|
|
||||||
received the Work from the Licensee under the Licence, provided such persons
|
|
||||||
remain in full compliance with the Licence.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
13. Miscellaneous
|
|
||||||
|
|
||||||
Without prejudice of Article 9 above, the Licence represents the complete
|
|
||||||
agreement between the Parties as to the Work licensed hereunder.
|
|
||||||
|
|
||||||
If any provision of the Licence is invalid or unenforceable under applicable
|
|
||||||
law, this will not affect the validity or enforceability of the Licence as a
|
|
||||||
whole. Such provision will be construed and/or reformed so as necessary to make
|
|
||||||
it valid and enforceable.
|
|
||||||
|
|
||||||
The European Commission may publish other linguistic versions and/or new
|
|
||||||
versions of this Licence, so far this is required and reasonable, without
|
|
||||||
reducing the scope of the rights granted by the Licence. New versions of the
|
|
||||||
Licence will be published with a unique version number.
|
|
||||||
|
|
||||||
All linguistic versions of this Licence, approved by the European Commission,
|
|
||||||
have identical value. Parties can take advantage of the linguistic version of
|
|
||||||
their choice.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
14. Jurisdiction
|
|
||||||
|
|
||||||
Any litigation resulting from the interpretation of this License, arising
|
|
||||||
between the European Commission, as a Licensor, and any Licensee, will be
|
|
||||||
subject to the jurisdiction of the Court of Justice of the European Communities,
|
|
||||||
as laid down in article 238 of the Treaty establishing the European Community.
|
|
||||||
|
|
||||||
Any litigation arising between Parties, other than the European Commission, and
|
|
||||||
resulting from the interpretation of this License, will be subject to the
|
|
||||||
exclusive jurisdiction of the competent court where the Licensor resides or
|
|
||||||
conducts its primary business.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
15. Applicable Law
|
|
||||||
|
|
||||||
This Licence shall be governed by the law of the European Union country where
|
|
||||||
the Licensor resides or has his registered office.
|
|
||||||
|
|
||||||
This licence shall be governed by the Belgian law if:
|
|
||||||
|
|
||||||
- a litigation arises between the European Commission, as a Licensor, and any
|
|
||||||
- Licensee; the Licensor, other than the European Commission, has no residence
|
|
||||||
- or registered office inside a European Union country.
|
|
||||||
|
|
||||||
|
|
||||||
===
|
|
||||||
|
|
||||||
|
|
||||||
Appendix
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
“Compatible Licences” according to article 5 EUPL are:
|
|
||||||
|
|
||||||
|
|
||||||
- GNU General Public License (GNU GPL) v. 2
|
|
||||||
|
|
||||||
- Open Software License (OSL) v. 2.1, v. 3.0
|
|
||||||
|
|
||||||
- Common Public License v. 1.0
|
|
||||||
|
|
||||||
- Eclipse Public License v. 1.0
|
|
||||||
|
|
||||||
- Cecill v. 2.0
|
|
|
@ -1,76 +0,0 @@
|
||||||
The gCube System - gCube Catalogue Service
|
|
||||||
--------------------------------------------------
|
|
||||||
|
|
||||||
This service allows any client to publish on the gCube Catalogue.
|
|
||||||
|
|
||||||
|
|
||||||
This software is part of the gCube Framework (https://www.gcube-system.org/): an
|
|
||||||
open-source software toolkit used for building and operating Hybrid Data
|
|
||||||
Infrastructures enabling the dynamic deployment of Virtual Research Environments
|
|
||||||
by favouring the realisation of reuse oriented policies.
|
|
||||||
|
|
||||||
The projects leading to this software have received funding from a series of
|
|
||||||
European Union programmes including:
|
|
||||||
* the Sixth Framework Programme for Research and Technological Development -
|
|
||||||
DILIGENT (grant no. 004260);
|
|
||||||
* the Seventh Framework Programme for research, technological development and
|
|
||||||
demonstration - D4Science (grant no. 212488), D4Science-II (grant no.
|
|
||||||
239019),ENVRI (grant no. 283465), EUBrazilOpenBio (grant no. 288754), iMarine
|
|
||||||
(grant no. 283644);
|
|
||||||
* the H2020 research and innovation programme - BlueBRIDGE (grant no. 675680),
|
|
||||||
EGIEngage (grant no. 654142), ENVRIplus (grant no. 654182), Parthenos (grant
|
|
||||||
no. 654119), SoBigData (grant no. 654024), AGINFRA PLUS (grant no. 731001).
|
|
||||||
|
|
||||||
|
|
||||||
Version
|
|
||||||
--------------------------------------------------
|
|
||||||
|
|
||||||
1.0.0-SNAPSHOT (2019-01-10)
|
|
||||||
|
|
||||||
Please see the file named "changelog.xml" in this directory for the release notes.
|
|
||||||
|
|
||||||
|
|
||||||
Authors
|
|
||||||
--------------------------------------------------
|
|
||||||
|
|
||||||
* Luca Frosini (luca.frosini-AT-isti.cnr.it), Istituto di Scienza e Tecnologie dell'Informazione "A. Faedo" - CNR, Pisa (Italy).
|
|
||||||
* Costantino Perciante (costantino.perciante@isti.cnr.it), Istituto di Scienza e Tecnologie dell'Informazione "A. Faedo" - CNR, Pisa (Italy).
|
|
||||||
|
|
||||||
Maintainers
|
|
||||||
-----------
|
|
||||||
|
|
||||||
* Luca Frosini (luca.frosini-AT-isti.cnr.it), Istituto di Scienza e Tecnologie dell'Informazione "A. Faedo" - CNR, Pisa (Italy).
|
|
||||||
|
|
||||||
Download information
|
|
||||||
--------------------------------------------------
|
|
||||||
|
|
||||||
Source code is available from SVN:
|
|
||||||
https://svn.d4science.research-infrastructures.eu/gcube/trunk/data-catalogue/gcat
|
|
||||||
|
|
||||||
Binaries can be downloaded from the gCube website:
|
|
||||||
https://www.gcube-system.org/
|
|
||||||
|
|
||||||
|
|
||||||
Installation
|
|
||||||
--------------------------------------------------
|
|
||||||
|
|
||||||
Installation documentation is available on-line in the gCube Wiki:
|
|
||||||
https://wiki.gcube-system.org/gcube/index.php
|
|
||||||
|
|
||||||
Documentation
|
|
||||||
--------------------------------------------------
|
|
||||||
|
|
||||||
Documentation is available on-line in the gCube Wiki:
|
|
||||||
https://wiki.gcube-system.org/gcube/index.php
|
|
||||||
|
|
||||||
Support
|
|
||||||
--------------------------------------------------
|
|
||||||
|
|
||||||
Bugs and support requests can be reported in the gCube issue tracking tool:
|
|
||||||
https://support.d4science.org/projects/gcube/
|
|
||||||
|
|
||||||
|
|
||||||
Licensing
|
|
||||||
--------------------------------------------------
|
|
||||||
|
|
||||||
This software is licensed under the terms you may find in the file named "LICENSE" in this directory.
|
|
|
@ -1,31 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE xml>
|
|
||||||
<ReleaseNotes>
|
|
||||||
<Changeset component="org.gcube.data-catalogue.catalogue-ws.1-4-0" date="2019-01-10">
|
|
||||||
<Change></Change>
|
|
||||||
</Changeset>
|
|
||||||
<Changeset component="org.gcube.data-catalogue.catalogue-ws.1-3-0" date="2018-10-10">
|
|
||||||
<Change>Complete refactoring of code</Change>
|
|
||||||
<Change>Item Port type is now RESTful (old methods are still allowed)</Change>
|
|
||||||
<Change>Added update support for Item #11516</Change>
|
|
||||||
<Change>Changed caching mechanism from ehcache API to JSR-107. Ehcache is still used as runtime library.</Change>
|
|
||||||
<Change>Solved random NullPointer Exception on catalogue-ws related to old caching mechanism #11466</Change>
|
|
||||||
<Change>Fixed normalization of the organization name #12506</Change>
|
|
||||||
<Change>Added the possibility to deny social post on catalogue-ws #12514</Change>
|
|
||||||
</Changeset>
|
|
||||||
<Changeset component="org.gcube.data-catalogue.catalogue-ws.1-1-1"
|
|
||||||
date="2018-01-11">
|
|
||||||
<Change>Item purge method enhanced</Change>
|
|
||||||
</Changeset>
|
|
||||||
<Changeset component="org.gcube.data-catalogue.catalogue-ws.1-1-0"
|
|
||||||
date="2017-06-20">
|
|
||||||
<Change>Minor fixes while checking user's permissions</Change>
|
|
||||||
<Change>Namespaces are no longer transparently managed</Change>
|
|
||||||
<Change>Fixed 'default' value for metadata</Change>
|
|
||||||
<Change>Improved exception handling</Change>
|
|
||||||
</Changeset>
|
|
||||||
<Changeset component="org.gcube.data-catalogue.catalogue-ws.1-0-0"
|
|
||||||
date="2017-05-01">
|
|
||||||
<Change>First Release</Change>
|
|
||||||
</Changeset>
|
|
||||||
</ReleaseNotes>
|
|
|
@ -1,31 +0,0 @@
|
||||||
<assembly
|
|
||||||
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"
|
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
|
|
||||||
<id>servicearchive</id>
|
|
||||||
<formats>
|
|
||||||
<format>tar.gz</format>
|
|
||||||
</formats>
|
|
||||||
<baseDirectory>/</baseDirectory>
|
|
||||||
<fileSets>
|
|
||||||
<fileSet>
|
|
||||||
<directory>/home/lucafrosini/workspace/gcat/distro</directory>
|
|
||||||
<outputDirectory>/</outputDirectory>
|
|
||||||
<useDefaultExcludes>true</useDefaultExcludes>
|
|
||||||
<includes>
|
|
||||||
<include>README</include>
|
|
||||||
<include>LICENSE</include>
|
|
||||||
<include>changelog.xml</include>
|
|
||||||
<include>profile.xml</include>
|
|
||||||
</includes>
|
|
||||||
<fileMode>755</fileMode>
|
|
||||||
<filtered>true</filtered>
|
|
||||||
</fileSet>
|
|
||||||
</fileSets>
|
|
||||||
<files>
|
|
||||||
<file>
|
|
||||||
<source>target/gcat-1.0.0-SNAPSHOT.war</source>
|
|
||||||
<outputDirectory>/gcat</outputDirectory>
|
|
||||||
</file>
|
|
||||||
</files>
|
|
||||||
</assembly>
|
|
|
@ -1,10 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE xml>
|
|
||||||
<application mode='online'>
|
|
||||||
<name>gcat</name>
|
|
||||||
<group>DataPublishing</group>
|
|
||||||
<version>1.0.0-SNAPSHOT</version>
|
|
||||||
<description>This service allows any client to publish on the gCube Catalogue.</description>
|
|
||||||
<local-persistence location='target' />
|
|
||||||
</application>
|
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE xml>
|
|
||||||
<Resource>
|
|
||||||
<ID />
|
|
||||||
<Type>Service</Type>
|
|
||||||
<Profile>
|
|
||||||
<Description>This service allows any client to publish on the gCube Catalogue.</Description>
|
|
||||||
<Class>DataPublishing</Class>
|
|
||||||
<Name>gcat</Name>
|
|
||||||
<Version>1.0.0</Version>
|
|
||||||
<Packages>
|
|
||||||
<Main>
|
|
||||||
<Description>This service allows any client to publish on the gCube Catalogue.</Description>
|
|
||||||
<Name>gcat</Name>
|
|
||||||
<Version>1.0.0-SNAPSHOT</Version>
|
|
||||||
<MavenCoordinates>
|
|
||||||
<groupId>org.gcube.data-publishing</groupId>
|
|
||||||
<artifactId>gcat</artifactId>
|
|
||||||
<version>1.0.0-SNAPSHOT</version>
|
|
||||||
</MavenCoordinates>
|
|
||||||
<Files>
|
|
||||||
<File>gcat-1.0.0-SNAPSHOT.war</File>
|
|
||||||
</Files>
|
|
||||||
</Main>
|
|
||||||
</Packages>
|
|
||||||
</Profile>
|
|
||||||
</Resource>
|
|
|
@ -1,11 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE xml>
|
|
||||||
<web-app>
|
|
||||||
<servlet>
|
|
||||||
<servlet-name>org.gcube.gcat.ResourceInitializer</servlet-name>
|
|
||||||
</servlet>
|
|
||||||
<servlet-mapping>
|
|
||||||
<servlet-name>org.gcube.gcat.ResourceInitializer</servlet-name>
|
|
||||||
<url-pattern>/*</url-pattern>
|
|
||||||
</servlet-mapping>
|
|
||||||
</web-app>
|
|
|
@ -18,7 +18,7 @@ public class CKANLicenseTest extends ContextTest {
|
||||||
@Test
|
@Test
|
||||||
public void list() throws Exception {
|
public void list() throws Exception {
|
||||||
CKANLicense license = new CKANLicense();
|
CKANLicense license = new CKANLicense();
|
||||||
String ret = license.list();
|
String ret = license.list(-1,-1);
|
||||||
ObjectMapper mapper = new ObjectMapper();
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
JsonNode gotList = mapper.readTree(ret);
|
JsonNode gotList = mapper.readTree(ret);
|
||||||
Assert.assertTrue(gotList instanceof ArrayNode);
|
Assert.assertTrue(gotList instanceof ArrayNode);
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
package org.gcube.gcat.persistence.ckan;
|
package org.gcube.gcat.persistence.ckan;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.gcube.gcat.ContextTest;
|
import org.gcube.gcat.ContextTest;
|
||||||
import org.gcube.gcat.persistence.ckan.CKAN;
|
|
||||||
import org.gcube.gcat.persistence.ckan.CKANPackage;
|
|
||||||
import org.gcube.gcat.persistence.ckan.CKANResource;
|
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
@ -27,37 +27,58 @@ public class CKANPackageTest extends ContextTest {
|
||||||
|
|
||||||
private static final String ITEM_NAME_VALUE = "restful_transaction_model";
|
private static final String ITEM_NAME_VALUE = "restful_transaction_model";
|
||||||
private static final String LICENSE_VALUE = "CC-BY-SA-4.0";
|
private static final String LICENSE_VALUE = "CC-BY-SA-4.0";
|
||||||
private static final String EXTRAS_TYPE_VALUE_VALUE = "EmptyType";
|
private static final String EXTRAS_TYPE_VALUE_VALUE = "EmptyProfile";
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void list() throws Exception {
|
public void list() throws Exception {
|
||||||
CKANPackage ckanPackage = new CKANPackage();
|
CKANPackage ckanPackage = new CKANPackage();
|
||||||
ObjectMapper mapper = new ObjectMapper();
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
String ret = ckanPackage.list();
|
String ret = ckanPackage.list(-1,0);
|
||||||
JsonNode gotList = mapper.readTree(ret);
|
JsonNode gotList = mapper.readTree(ret);
|
||||||
Assert.assertTrue(gotList instanceof ArrayNode);
|
Assert.assertTrue(gotList instanceof ArrayNode);
|
||||||
logger.debug("List :\n{}", mapper.writeValueAsString(gotList));
|
logger.debug("List :\n{}", mapper.writeValueAsString(gotList));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* DEV
|
* PRE
|
||||||
|
*
|
||||||
* Workspace(luca.frosini) > RESTful Transaction Model.pdf
|
* Workspace(luca.frosini) > RESTful Transaction Model.pdf
|
||||||
* https://data-d.d4science.org/shub/e03355cd-058a-4e3a-8d5b-cf3676a46840
|
* https://data1-d.d4science.org/shub/E_YjI4STdKKzRlNjgzMm9jQWxjcmtReDNwbDFYR3lpTHo3SjdtN1RDZ3c2OGk0ZHZhdE5iZElBKzNxUDAyTGFqZw==
|
||||||
* URL url = new URL("https://goo.gl/fSZH1o");
|
* https://goo.gl/HcUWni
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* Workspace(luca.frosini) > RESTful Transaction Model v 1.0.pdf
|
* Workspace(luca.frosini) > RESTful Transaction Model v 1.0.pdf
|
||||||
* https://data-d.d4science.org/shub/8ad187c4-8f94-4c47-a780-706d0d33c1bb
|
* https://data1-d.d4science.org/shub/E_aThRa1NpWFJpTGEydEU2bEJhMXNjZy8wK3BxekJKYnpYTy81cUkwZVdicEZ0aGFRZmY4MkRnUC8xWW0zYzVoVg==
|
||||||
* URL url = new URL("https://goo.gl/6vZSmp");
|
* https://goo.gl/J8AwQW
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* Workspace(luca.frosini) > RESTful Transaction Model v 1.1.pdf
|
* Workspace(luca.frosini) > RESTful Transaction Model v 1.1.pdf
|
||||||
* https://data-d.d4science.org/shub/7b6628e4-b397-4df9-b387-2d643ae0095c
|
* https://data1-d.d4science.org/shub/E_NkhrbVV4VTluT0RKVUtCRldobFZTQU5ySTZneFdpUzJ2UjJBNlZWNDlURDVHamo4WjY5RnlrcHZGTGNkT2prUg==
|
||||||
* URL url = new URL("https://goo.gl/jvXMcd");
|
* https://goo.gl/78ViuR
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNameRegex() {
|
||||||
|
Map<String, Boolean> stringsToTest = new HashMap<>();
|
||||||
|
stringsToTest.put("Test", false); // Fails for T
|
||||||
|
stringsToTest.put("test-test+test-test", false); // Fails for +
|
||||||
|
stringsToTest.put("t", false); // Fails because is too short. Min length is 2 characters
|
||||||
|
stringsToTest.put("te", true);
|
||||||
|
stringsToTest.put("test-test_test-test", true);
|
||||||
|
stringsToTest.put("test-test_test-test_test-test_test-test_test-test_test-test_test-test_test-test_test-test_test-test_", true);
|
||||||
|
// // Fails because is too long. Max length is 100 characters
|
||||||
|
stringsToTest.put("test-test_test-test_test-test_test-test_test-test_test-test_test-test_test-test_test-test_test-test_t", false);
|
||||||
|
|
||||||
|
for(String testString : stringsToTest.keySet()) {
|
||||||
|
boolean match = testString.matches(CKANPackage.NAME_REGEX);
|
||||||
|
logger.debug("'{}' does {}match the regex {}", testString, match ? "" : "NOT ", CKANPackage.NAME_REGEX);
|
||||||
|
Assert.assertEquals(stringsToTest.get(testString), match);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
protected CKANPackage createPackage(ObjectMapper mapper) throws Exception {
|
protected CKANPackage createPackage(ObjectMapper mapper) throws Exception {
|
||||||
|
|
||||||
|
@ -78,7 +99,7 @@ public class CKANPackageTest extends ContextTest {
|
||||||
ObjectNode resourceNode = mapper.createObjectNode();
|
ObjectNode resourceNode = mapper.createObjectNode();
|
||||||
resourceNode.put(CKANResource.NAME_KEY, "RESTful Transaction Model");
|
resourceNode.put(CKANResource.NAME_KEY, "RESTful Transaction Model");
|
||||||
// Workspace(luca.frosini) > RESTful Transaction Model v 1.0.pdf
|
// Workspace(luca.frosini) > RESTful Transaction Model v 1.0.pdf
|
||||||
resourceNode.put(CKANResource.URL_KEY, "https://goo.gl/6vZSmp");
|
resourceNode.put(CKANResource.URL_KEY, "https://goo.gl/J8AwQW");
|
||||||
resourceArrayNode.add(resourceNode);
|
resourceArrayNode.add(resourceNode);
|
||||||
|
|
||||||
ArrayNode extraArrayNode = itemObjectNode.putArray(CKANPackage.EXTRA_TYPES_KEY);
|
ArrayNode extraArrayNode = itemObjectNode.putArray(CKANPackage.EXTRA_TYPES_KEY);
|
||||||
|
@ -123,7 +144,7 @@ public class CKANPackageTest extends ContextTest {
|
||||||
ArrayNode resources = (ArrayNode) readItemObjectNode.get(CKANPackage.RESOURCES_KEY);
|
ArrayNode resources = (ArrayNode) readItemObjectNode.get(CKANPackage.RESOURCES_KEY);
|
||||||
ObjectNode objectNode = (ObjectNode) resources.get(0);
|
ObjectNode objectNode = (ObjectNode) resources.get(0);
|
||||||
// Workspace(luca.frosini) > RESTful Transaction Model v 1.1.pdf
|
// Workspace(luca.frosini) > RESTful Transaction Model v 1.1.pdf
|
||||||
objectNode.put(CKANResource.URL_KEY, "https://goo.gl/jvXMcd");
|
objectNode.put(CKANResource.URL_KEY, "https://goo.gl/78ViuR");
|
||||||
resources.set(0, objectNode);
|
resources.set(0, objectNode);
|
||||||
|
|
||||||
((ObjectNode) readItemObjectNode).replace(CKANPackage.RESOURCES_KEY, resources);
|
((ObjectNode) readItemObjectNode).replace(CKANPackage.RESOURCES_KEY, resources);
|
||||||
|
|
|
@ -4,7 +4,8 @@ import java.net.URL;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import org.gcube.gcat.ContextTest;
|
import org.gcube.gcat.ContextTest;
|
||||||
import org.gcube.gcat.persistence.ckan.CKANResource;
|
import org.gcube.gcat.utils.Constants;
|
||||||
|
import org.gcube.storagehub.ApplicationMode;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
@ -16,55 +17,64 @@ public class CKANResourceTest extends ContextTest {
|
||||||
|
|
||||||
private static final Logger logger = LoggerFactory.getLogger(CKANResourceTest.class);
|
private static final Logger logger = LoggerFactory.getLogger(CKANResourceTest.class);
|
||||||
|
|
||||||
/*
|
|
||||||
* PROD
|
|
||||||
* Workspace(luca.frosini) > RESTful Transaction Model.pdf
|
|
||||||
* https://data.d4science.org/shub/ab4daec8-2ce4-43d7-9d37-00b2051e3530
|
|
||||||
* URL url = new URL("https://goo.gl/bFME6Q");
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* DEV
|
* PRE
|
||||||
|
*
|
||||||
* Workspace(luca.frosini) > RESTful Transaction Model.pdf
|
* Workspace(luca.frosini) > RESTful Transaction Model.pdf
|
||||||
* https://data-d.d4science.org/shub/e03355cd-058a-4e3a-8d5b-cf3676a46840
|
* https://data1-d.d4science.org/shub/E_YjI4STdKKzRlNjgzMm9jQWxjcmtReDNwbDFYR3lpTHo3SjdtN1RDZ3c2OGk0ZHZhdE5iZElBKzNxUDAyTGFqZw==
|
||||||
* URL url = new URL("https://goo.gl/fSZH1o");
|
* https://goo.gl/HcUWni
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* Workspace(luca.frosini) > RESTful Transaction Model v 1.0.pdf
|
* Workspace(luca.frosini) > RESTful Transaction Model v 1.0.pdf
|
||||||
* https://data-d.d4science.org/shub/5df695ea-986a-437d-abaf-ed1542a7f5af
|
* https://data1-d.d4science.org/shub/E_aThRa1NpWFJpTGEydEU2bEJhMXNjZy8wK3BxekJKYnpYTy81cUkwZVdicEZ0aGFRZmY4MkRnUC8xWW0zYzVoVg==
|
||||||
* URL url = new URL("https://goo.gl/7ofQwn");
|
* https://goo.gl/J8AwQW
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* Workspace(luca.frosini) > RESTful Transaction Model v 1.1.pdf
|
* Workspace(luca.frosini) > RESTful Transaction Model v 1.1.pdf
|
||||||
* https://data-d.d4science.org/shub/7b6628e4-b397-4df9-b387-2d643ae0095c
|
* https://data1-d.d4science.org/shub/E_NkhrbVV4VTluT0RKVUtCRldobFZTQU5ySTZneFdpUzJ2UjJBNlZWNDlURDVHamo4WjY5RnlrcHZGTGNkT2prUg==
|
||||||
* URL url = new URL("https://goo.gl/jvXMcd");
|
* https://goo.gl/78ViuR
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
public void test() throws Exception {
|
||||||
|
ApplicationMode applicationMode = new ApplicationMode(Constants.getCatalogueApplicationToken());
|
||||||
|
applicationMode.start();
|
||||||
|
//
|
||||||
|
applicationMode.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Test
|
||||||
public void testCopyStorageResource() throws Exception {
|
public void testCopyStorageResource() throws Exception {
|
||||||
URL url = new URL("https://goo.gl/fSZH1o");
|
URL url = new URL("https://goo.gl/HcUWni");
|
||||||
|
|
||||||
String itemID = UUID.randomUUID().toString();
|
String itemID = UUID.randomUUID().toString();
|
||||||
CKANResource ckanResource = new CKANResource(itemID);
|
CKANResource ckanResource = new CKANResource(itemID);
|
||||||
ckanResource.resourceID = UUID.randomUUID().toString();
|
ckanResource.resourceID = UUID.randomUUID().toString();
|
||||||
URL finalURL = ckanResource.copyStorageResource(url);
|
URL finalURL = ckanResource.copyStorageResource(url);
|
||||||
logger.debug("Initial URL is {} - Final URL is {}", url, finalURL);
|
logger.debug("Initial URL is {} - Final URL is {}", url, finalURL);
|
||||||
ckanResource.deleteStorageResource(finalURL);
|
ckanResource.deleteStorageResource(finalURL, ckanResource.resourceID, ckanResource.mimeType);
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Test
|
@Test
|
||||||
public void testCreate() throws Exception {
|
public void testCreate() throws Exception {
|
||||||
ObjectMapper objectMapper = new ObjectMapper();
|
ObjectMapper objectMapper = new ObjectMapper();
|
||||||
ObjectNode objectNode = objectMapper.createObjectNode();
|
ObjectNode objectNode = objectMapper.createObjectNode();
|
||||||
objectNode.put(CKANResource.URL_KEY, "https://data.d4science.org/shub/ab4daec8-2ce4-43d7-9d37-00b2051e3530");
|
objectNode.put(CKANResource.NAME_KEY, "MyTestTy_rest_upload");
|
||||||
objectNode.put(CKANResource.ID_KEY, "8422b5d4-626b-46f2-9121-bbc6d443071d");
|
objectNode.put(CKANResource.URL_KEY, "https://data.d4science.org/shub/58a13287-3e91-4afd-bd80-cf4605a0edaa");
|
||||||
|
objectNode.put("description", "i uploaded this file using the REST API");
|
||||||
|
// objectNode.put(CKANResource.ID_KEY, "ba7ab7e8-c268-4219-98cd-c73470870999");
|
||||||
|
|
||||||
CKANResource ckanResource = new CKANResource("f9221556-4b1f-49f2-8951-a4c30d71cd37");
|
CKANResource ckanResource = new CKANResource("ba7ab7e8-c268-4219-98cd-c73470870999");
|
||||||
String json = ckanResource.getAsString(objectNode);
|
String json = ckanResource.getAsString(objectNode);
|
||||||
logger.debug("Going to create Resource {}", json);
|
logger.debug("Going to create Resource {}", json);
|
||||||
ckanResource.create(json);
|
ckanResource.create(objectNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Test
|
||||||
|
public void testDelete() throws Exception {
|
||||||
|
CKANResource ckanResource = new CKANResource("f0326fec-d8ac-42c7-abff-c7905b4d938e");
|
||||||
|
ckanResource.setResourceID("fcf98272-41e7-4f05-9294-fdafb1a33074");
|
||||||
|
ckanResource.delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ public class CKANUserTest extends ContextTest {
|
||||||
@Test
|
@Test
|
||||||
public void list() throws Exception {
|
public void list() throws Exception {
|
||||||
CKANUser ckanUser = getCKANUser();
|
CKANUser ckanUser = getCKANUser();
|
||||||
String ret = ckanUser.list();
|
String ret = ckanUser.list(-1,-1);
|
||||||
logger.debug("{}", ret);
|
logger.debug("{}", ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
package org.gcube.gcat.rest;
|
package org.gcube.gcat.rest;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
|
|
||||||
import org.gcube.gcat.ContextTest;
|
import org.gcube.gcat.ContextTest;
|
||||||
import org.gcube.gcat.rest.Profile;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
@ -53,4 +56,24 @@ public class ProfileTest extends ContextTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String PROFILE_EXAMPLE_FILENAME = "EmptyProfileExample.xml";
|
||||||
|
|
||||||
|
public static String PROFILE_NAME_EXAMPLE = "EmptyProfile";
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateUpdateDeleteGenericResource() throws Exception {
|
||||||
|
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(PROFILE_EXAMPLE_FILENAME);
|
||||||
|
String xml = new BufferedReader(new InputStreamReader(inputStream)).lines()
|
||||||
|
.collect(Collectors.joining("\n"));
|
||||||
|
logger.debug("Body\n{}", xml);
|
||||||
|
Profile profile = new Profile();
|
||||||
|
profile.createOrUpdate(PROFILE_NAME_EXAMPLE, xml);
|
||||||
|
/*
|
||||||
|
Thread.sleep(TimeUnit.SECONDS.toMillis(30));
|
||||||
|
profile.createOrUpdate(PROFILE_NAME_EXAMPLE, "<metadataformat type=\"" + PROFILE_NAME_EXAMPLE + "\" />");
|
||||||
|
Thread.sleep(TimeUnit.SECONDS.toMillis(30));
|
||||||
|
profile.delete(PROFILE_NAME_EXAMPLE);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,125 @@
|
||||||
|
package org.gcube.gcat.workspace;
|
||||||
|
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.gcube.common.storagehub.client.dsl.FileContainer;
|
||||||
|
import org.gcube.common.storagehub.model.Metadata;
|
||||||
|
import org.gcube.gcat.ContextTest;
|
||||||
|
import org.gcube.gcat.persistence.ckan.CKANResource;
|
||||||
|
import org.gcube.storagehub.StorageHubManagement;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public class CatalogueStorageHubManagementTest extends ContextTest {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(CatalogueStorageHubManagementTest.class);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PRE
|
||||||
|
*
|
||||||
|
* Workspace(luca.frosini) > RESTful Transaction Model.pdf
|
||||||
|
* https://data1-d.d4science.org/shub/E_YjI4STdKKzRlNjgzMm9jQWxjcmtReDNwbDFYR3lpTHo3SjdtN1RDZ3c2OGk0ZHZhdE5iZElBKzNxUDAyTGFqZw==
|
||||||
|
* https://goo.gl/HcUWni
|
||||||
|
*
|
||||||
|
* Workspace(luca.frosini) > RESTful Transaction Model v 1.0.pdf
|
||||||
|
* https://data1-d.d4science.org/shub/E_aThRa1NpWFJpTGEydEU2bEJhMXNjZy8wK3BxekJKYnpYTy81cUkwZVdicEZ0aGFRZmY4MkRnUC8xWW0zYzVoVg==
|
||||||
|
* https://goo.gl/J8AwQW
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Workspace(luca.frosini) > RESTful Transaction Model v 1.1.pdf
|
||||||
|
* https://data1-d.d4science.org/shub/E_NkhrbVV4VTluT0RKVUtCRldobFZTQU5ySTZneFdpUzJ2UjJBNlZWNDlURDVHamo4WjY5RnlrcHZGTGNkT2prUg==
|
||||||
|
* https://goo.gl/78ViuR
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
public static final String ORIGINAL_STORAGE_URL_STRING = "https://data1-d.d4science.org/shub/E_YjI4STdKKzRlNjgzMm9jQWxjcmtReDNwbDFYR3lpTHo3SjdtN1RDZ3c2OGk0ZHZhdE5iZElBKzNxUDAyTGFqZw==";
|
||||||
|
public static final URL ORIGINAL_STORAGE_URL;
|
||||||
|
|
||||||
|
public static final String SHORT_URL_STRING = "https://goo.gl/HcUWni";
|
||||||
|
public static final URL SHORT_STORAGE_URL;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static final String MIME_TYPE = "application/pdf";
|
||||||
|
|
||||||
|
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
ORIGINAL_STORAGE_URL = new URL(ORIGINAL_STORAGE_URL_STRING);
|
||||||
|
SHORT_STORAGE_URL = new URL(SHORT_URL_STRING);
|
||||||
|
}catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final String ITEM_ID = "MyItem";
|
||||||
|
public static final String RESOURCE_ID = "1234";
|
||||||
|
|
||||||
|
protected CatalogueStorageHubManagement catalogueStorageHubManagement;
|
||||||
|
protected StorageHubManagement storageHubManagement;
|
||||||
|
protected CatalogueMetadata catalogueMetadata;
|
||||||
|
|
||||||
|
|
||||||
|
public CatalogueStorageHubManagementTest() {
|
||||||
|
catalogueStorageHubManagement = new CatalogueStorageHubManagement();
|
||||||
|
storageHubManagement = catalogueStorageHubManagement.storageHubManagement;
|
||||||
|
catalogueMetadata = new CatalogueMetadata(ITEM_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getFinalURL() {
|
||||||
|
URL finalURL = CKANResource.getFinalURL(SHORT_STORAGE_URL);
|
||||||
|
Assert.assertTrue(finalURL.toString().compareTo(ORIGINAL_STORAGE_URL_STRING)==0);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void checkMetadata(FileContainer fileContainer, String version) {
|
||||||
|
Metadata gotMetadata = fileContainer.get().getMetadata();
|
||||||
|
Map<String, Object> gotMap = gotMetadata.getMap();
|
||||||
|
|
||||||
|
CatalogueMetadata catalogueMetadata = new CatalogueMetadata(ITEM_ID);
|
||||||
|
|
||||||
|
Metadata expectedMetadata = catalogueMetadata.getMetadata(ORIGINAL_STORAGE_URL, fileContainer.get().getName(), RESOURCE_ID);
|
||||||
|
Map<String, Object> expectedMap = expectedMetadata.getMap();
|
||||||
|
|
||||||
|
for(String key : gotMap.keySet()) {
|
||||||
|
String value = (String) gotMap.get(key);
|
||||||
|
if(key.compareTo(CatalogueMetadata.CATALOGUE_RESOURCE_REVISION_ID)==0) {
|
||||||
|
Assert.assertTrue(value.compareTo(version)==0);
|
||||||
|
}else {
|
||||||
|
String expectedValue = (String) expectedMap.get(key);
|
||||||
|
Assert.assertTrue(value.compareTo(expectedValue)==0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPersistence() throws Exception {
|
||||||
|
|
||||||
|
URL persistedURL = catalogueStorageHubManagement.ensureResourcePersistence(ORIGINAL_STORAGE_URL, ITEM_ID, RESOURCE_ID);
|
||||||
|
logger.debug("Publick Link of persisted file is {}", persistedURL);
|
||||||
|
|
||||||
|
Assert.assertTrue(catalogueStorageHubManagement.getMimeType().compareTo(MIME_TYPE)==0);
|
||||||
|
|
||||||
|
FileContainer createdFileContainer = storageHubManagement.getCreatedFile();
|
||||||
|
|
||||||
|
|
||||||
|
String version = "2";
|
||||||
|
catalogueStorageHubManagement.renameFile(RESOURCE_ID, version);
|
||||||
|
checkMetadata(createdFileContainer, version);
|
||||||
|
|
||||||
|
|
||||||
|
version = "3";
|
||||||
|
catalogueStorageHubManagement.addRevisionID(RESOURCE_ID, version);
|
||||||
|
checkMetadata(createdFileContainer, version);
|
||||||
|
|
||||||
|
|
||||||
|
catalogueStorageHubManagement.deleteResourcePersistence(ITEM_ID, RESOURCE_ID, MIME_TYPE);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,106 +0,0 @@
|
||||||
package org.gcube.gcat.workspace;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import org.gcube.common.homelibrary.home.Home;
|
|
||||||
import org.gcube.common.homelibrary.home.HomeLibrary;
|
|
||||||
import org.gcube.common.homelibrary.home.HomeManager;
|
|
||||||
import org.gcube.common.homelibrary.home.HomeManagerFactory;
|
|
||||||
import org.gcube.common.homelibrary.home.User;
|
|
||||||
import org.gcube.common.homelibrary.home.workspace.Workspace;
|
|
||||||
import org.gcube.common.homelibrary.home.workspace.WorkspaceFolder;
|
|
||||||
import org.gcube.common.homelibrary.home.workspace.WorkspaceItem;
|
|
||||||
import org.gcube.common.storagehub.client.dsl.FileContainer;
|
|
||||||
import org.gcube.common.storagehub.client.dsl.FolderContainer;
|
|
||||||
import org.gcube.common.storagehub.client.dsl.ItemContainer;
|
|
||||||
import org.gcube.common.storagehub.client.dsl.ListResolver;
|
|
||||||
import org.gcube.common.storagehub.model.Metadata;
|
|
||||||
import org.gcube.common.storagehub.model.items.Item;
|
|
||||||
import org.gcube.common.storagehub.model.service.Version;
|
|
||||||
import org.gcube.gcat.ContextTest;
|
|
||||||
import org.gcube.gcat.utils.ApplicationMode;
|
|
||||||
import org.gcube.gcat.utils.ContextUtility;
|
|
||||||
import org.gcube.gcat.workspace.StorageHubManagement;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
public class StorageHubManagementTest extends ContextTest {
|
|
||||||
|
|
||||||
private static final Logger logger = LoggerFactory.getLogger(StorageHubManagementTest.class);
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testHL() throws Exception {
|
|
||||||
ApplicationMode applicationMode = new ApplicationMode();
|
|
||||||
applicationMode.start();
|
|
||||||
String username = ContextUtility.getUsername();
|
|
||||||
HomeManagerFactory factory = HomeLibrary.getHomeManagerFactory();
|
|
||||||
HomeManager manager = factory.getHomeManager();
|
|
||||||
User user = manager.createUser(username);
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
Home home = manager.getHome(user);
|
|
||||||
Workspace ws = home.getWorkspace();
|
|
||||||
WorkspaceFolder workspaceFolder = ws.getRoot();
|
|
||||||
List<WorkspaceItem> workspaceItems = workspaceFolder.getChildren(true);
|
|
||||||
for(WorkspaceItem workspaceItem : workspaceItems) {
|
|
||||||
logger.debug("{} {}{}", workspaceFolder.getType(), workspaceItem.getName(), workspaceItem.isHidden()? " (hidden)":"");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void myTest() throws Exception {
|
|
||||||
String folderName = StorageHubManagement.getFolderName();
|
|
||||||
logger.debug(folderName);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void test() throws Exception {
|
|
||||||
ApplicationMode applicationMode = new ApplicationMode();
|
|
||||||
applicationMode.start();
|
|
||||||
StorageHubManagement storageHubManagement = new StorageHubManagement();
|
|
||||||
FolderContainer root = storageHubManagement.getWorkspaceRoot();
|
|
||||||
storageHubManagement.tree(root);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void listFolders() throws Exception {
|
|
||||||
ApplicationMode applicationMode = new ApplicationMode();
|
|
||||||
applicationMode.start();
|
|
||||||
StorageHubManagement storageHubManagement = new StorageHubManagement();
|
|
||||||
FolderContainer root = storageHubManagement.getWorkspaceRoot();
|
|
||||||
storageHubManagement.getCatalogueFolder();
|
|
||||||
storageHubManagement.tree(root);
|
|
||||||
applicationMode.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
// @Test
|
|
||||||
public void deleteFile() throws Exception {
|
|
||||||
StorageHubManagement storageHubManagement = new StorageHubManagement();
|
|
||||||
String id = "";
|
|
||||||
storageHubManagement.deleteFileByID(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void getFileInfo() throws Exception {
|
|
||||||
StorageHubManagement storageHubManagement = new StorageHubManagement();
|
|
||||||
String id = "";
|
|
||||||
FileContainer fileContainer = storageHubManagement.getFileByID(id);
|
|
||||||
logger.debug("StorageHub ID {} - File Name {}", id, fileContainer.get().getName());
|
|
||||||
ListResolver listResolver = fileContainer.getAnchestors();
|
|
||||||
List<ItemContainer<? extends Item>> itemContainers = listResolver.getContainers();
|
|
||||||
for(ItemContainer<? extends Item> itemContainer : itemContainers) {
|
|
||||||
logger.debug("{}", itemContainer.get().getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
Metadata metadata = fileContainer.get().getPropertyMap();
|
|
||||||
Map<String,Object> map = metadata.getValues();
|
|
||||||
logger.debug("{}", map);
|
|
||||||
|
|
||||||
List<Version> versions = fileContainer.getVersions();
|
|
||||||
for(Version version : versions){
|
|
||||||
logger.debug("Version {} {}", version.getId(), version.getName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
<metadataformat type="EmptyProfile">
|
||||||
|
<metadatafield>
|
||||||
|
<fieldName>test</fieldName>
|
||||||
|
<mandatory>false</mandatory>
|
||||||
|
<dataType>String</dataType>
|
||||||
|
<maxOccurs>1</maxOccurs>
|
||||||
|
<note>Test Field</note>
|
||||||
|
</metadatafield>
|
||||||
|
</metadataformat>
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
|
|
||||||
<logger name="org.gcube" level="ERROR" />
|
<logger name="org.gcube" level="ERROR" />
|
||||||
<logger name="org.gcube.datacatalogue" level="TRACE" />
|
<logger name="org.gcube.gcat" level="TRACE" />
|
||||||
|
|
||||||
<root level="WARN">
|
<root level="WARN">
|
||||||
<appender-ref ref="STDOUT" />
|
<appender-ref ref="STDOUT" />
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
227af25a-7631-4abd-a866-a67ff7f63276
|
|
|
@ -1,3 +0,0 @@
|
||||||
DO CANCEL THIS FILE IN PRODUCTION and DEV ENVIRONMENTS
|
|
||||||
|
|
||||||
The presence of this file indicates the home library client to look for the preprod instance of the workspace repository.
|
|
Loading…
Reference in New Issue