Service Refatored and Renamed to gCcat

Refs #12810: Refactor catalogue-ws 

Task-Url: https://support.d4science.org/issues/12810

git-svn-id: https://svn.d4science.research-infrastructures.eu/gcube/trunk/data-publishing/gcat@174532 82a268e6-3cf1-43bd-a215-b396298e98cf
migrating_to_smartgears_4
Luca Frosini 5 years ago
commit 5743fc03ed

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="target/classes" path="src/main/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>
</classpath>

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>science-catalogue</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.wst.jsdt.core.javascriptValidator</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.wst.common.project.facet.core.builder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.wst.validation.validationbuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jem.workbench.JavaEMFNature</nature>
<nature>org.eclipse.wst.common.modulecore.ModuleCoreNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.m2e.core.maven2Nature</nature>
<nature>org.eclipse.wst.common.project.facet.core.nature</nature>
<nature>org.eclipse.wst.jsdt.core.jsNature</nature>
</natures>
</projectDescription>

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src/main/webapp"/>
<classpathentry kind="src" path="target/m2e-wtp/web-resources"/>
<classpathentry kind="con" path="org.eclipse.wst.jsdt.launching.JRE_CONTAINER"/>
<classpathentry kind="con" path="org.eclipse.wst.jsdt.launching.WebProject">
<attributes>
<attribute name="hide" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.wst.jsdt.launching.baseBrowserLibrary"/>
<classpathentry kind="output" path=""/>
</classpath>

@ -0,0 +1,6 @@
eclipse.preferences.version=1
encoding//src/main/java=UTF-8
encoding//src/main/resources=UTF-8
encoding//src/test/java=UTF-8
encoding//src/test/resources=UTF-8
encoding/<project>=UTF-8

@ -0,0 +1,8 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.source=1.8

@ -0,0 +1,4 @@
activeProfiles=
eclipse.preferences.version=1
resolveWorkspaceProjects=true
version=1

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?><project-modules id="moduleCoreId" project-version="1.5.0">
<wb-module deploy-name="catalogue-ws">
<wb-resource deploy-path="/" source-path="/target/m2e-wtp/web-resources"/>
<wb-resource deploy-path="/" source-path="/src/main/webapp" tag="defaultRootSource"/>
<wb-resource deploy-path="/WEB-INF/classes" source-path="/src/main/java"/>
<wb-resource deploy-path="/WEB-INF/classes" source-path="/src/main/resources"/>
<wb-resource deploy-path="/WEB-INF/classes" source-path="/src/test/resources"/>
<dependent-module archiveName="ckan-util-library-2.5.0-SNAPSHOT.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/ckan-util-library/ckan-util-library">
<dependency-type>uses</dependency-type>
</dependent-module>
<property name="context-root" value="catalogue-ws"/>
<property name="java-output-path" value="/catalogue-ws/target/classes"/>
</wb-module>
</project-modules>

@ -0,0 +1,7 @@
<root>
<facet id="jst.jaxrs">
<node name="libprov">
<attribute name="provider-id" value="jaxrs-no-op-library-provider"/>
</node>
</facet>
</root>

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<faceted-project>
<fixed facet="wst.jsdt.web"/>
<installed facet="jst.web" version="3.0"/>
<installed facet="wst.jsdt.web" version="1.0"/>
<installed facet="jst.jaxrs" version="2.0"/>
<installed facet="java" version="1.8"/>
</faceted-project>

@ -0,0 +1 @@
org.eclipse.wst.jsdt.launching.baseBrowserLibrary

@ -0,0 +1,2 @@
disabled=06target
eclipse.preferences.version=1

@ -0,0 +1,4 @@
gCube System - License
------------------------------------------------------------
${gcube.license}

@ -0,0 +1,63 @@
The gCube System - ${name}
--------------------------------------------------
${description}
${gcube.description}
${gcube.funding}
Version
--------------------------------------------------
${version} (${buildDate})
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:
${scm.url}
Binaries can be downloaded from the gCube website:
${gcube.website}
Installation
--------------------------------------------------
Installation documentation is available on-line in the gCube Wiki:
${gcube.wikiRoot}
Documentation
--------------------------------------------------
Documentation is available on-line in the gCube Wiki:
${gcube.wikiRoot}
Support
--------------------------------------------------
Bugs and support requests can be reported in the gCube issue tracking tool:
${gcube.issueTracking}
Licensing
--------------------------------------------------
This software is licensed under the terms you may find in the file named "LICENSE" in this directory.

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xml>
<ReleaseNotes>
<Changeset component="org.gcube.data-catalogue.catalogue-ws.1-4-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>
</Changeset>
</ReleaseNotes>

@ -0,0 +1,31 @@
<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>${distroDirectory}</directory>
<outputDirectory>${file.separator}</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${file.separator}${build.finalName}.${project.packaging}</source>
<outputDirectory>${file.separator}${artifactId}</outputDirectory>
</file>
</files>
</assembly>

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xml>
<application mode='online'>
<name>${artifactId}</name>
<group>${serviceClass}</group>
<version>${version}</version>
<description>${description}</description>
<local-persistence location='target' />
</application>

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xml>
<Resource>
<ID />
<Type>Service</Type>
<Profile>
<Description>${description}</Description>
<Class>${serviceClass}</Class>
<Name>${artifactId}</Name>
<Version>1.0.0</Version>
<Packages>
<Main>
<Description>${description}</Description>
<Name>${artifactId}</Name>
<Version>${version}</Version>
<MavenCoordinates>
<groupId>${groupId}</groupId>
<artifactId>${artifactId}</artifactId>
<version>${version}</version>
</MavenCoordinates>
<Files>
<File>${build.finalName}.${project.packaging}</File>
</Files>
</Main>
</Packages>
</Profile>
</Resource>

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xml>
<web-app>
<servlet>
<servlet-name>org.gcube.datacatalogue.sciencecatalogue.ResourceInitializer</servlet-name>
</servlet>
<servlet-mapping>
<servlet-name>org.gcube.datacatalogue.sciencecatalogue.ResourceInitializer</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>

@ -0,0 +1,304 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>maven-parent</artifactId>
<groupId>org.gcube.tools</groupId>
<version>1.0.0</version>
<relativePath />
</parent>
<groupId>org.gcube.data-publishing</groupId>
<artifactId>gcat</artifactId>
<packaging>war</packaging>
<version>1.0.0-SNAPSHOT</version>
<name>gCube Catalogue Service</name>
<description>
This service allows any client to publish on the gCube Catalogue.
</description>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.gcube.distribution</groupId>
<artifactId>gcube-bom</artifactId>
<version>LATEST</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.gcube.distribution</groupId>
<artifactId>gcube-smartgears-bom</artifactId>
<version>LATEST</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.gcube.common</groupId>
<artifactId>gxRest</artifactId>
<version>1.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
</dependencyManagement>
<properties>
<version.jersey>2.13</version.jersey>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<webappDirectory>${project.basedir}/src/main/webapp/WEB-INF</webappDirectory>
<!-- webappDirectory>${project.build.directory}/${project.build.finalName}</webappDirectory -->
<distroDirectory>${project.basedir}/distro</distroDirectory>
<serviceClass>DataCatalogue</serviceClass>
</properties>
<scm>
<connection>scm:https://svn.d4science.research-infrastructures.eu/gcube/trunk/data-catalogue/${project.artifactId}</connection>
<developerConnection>scm:https://svn.d4science.research-infrastructures.eu/gcube//trunk/data-catalogue/${project.artifactId}</developerConnection>
<url>https://svn.d4science.research-infrastructures.eu/gcube/trunk/data-catalogue/${project.artifactId}</url>
</scm>
<dependencies>
<!-- ehCAChe -->
<dependency>
<groupId>javax.cache</groupId>
<artifactId>cache-api</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>3.5.2</version>
<scope>runtime</scope>
</dependency>
<!-- END ehCAChe -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.gcube.data-catalogue</groupId>
<artifactId>gcubedatacatalogue-metadata-discovery</artifactId>
<version>[3.0.0-SNAPSHOT, 4.0.0-SNAPSHOT)</version>
<exclusions>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.gcube.data-catalogue</groupId>
<artifactId>ckan-util-library</artifactId>
<version>[2.0.0-SNAPSHOT, 3.0.0-SNAPSHOT)</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>${version.jersey}</version>
</dependency>
<!-- Required with jersey 2.27
<dependency>
<groupId>org.glassfish.jersey.inject</groupId>
<artifactId>jersey-hk2</artifactId>
<version>${version.jersey}</version>
</dependency>
-->
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-multipart</artifactId>
<version>${version.jersey}</version>
</dependency>
<dependency>
<groupId>org.gcube.common</groupId>
<artifactId>storagehub-client-library</artifactId>
<version>[1.0.0-SNAPSHOT, 2.0.0-SNAPSHOT)</version>
</dependency>
<!-- Home Library dependencies MUST be removed when the storagehub add missing features -->
<dependency>
<groupId>org.gcube.common</groupId>
<artifactId>home-library-jcr</artifactId>
<version>[2.0.0-SNAPSHOT,3.0.0-SNAPSHOT)</version>
</dependency>
<dependency>
<groupId>org.gcube.common</groupId>
<artifactId>home-library</artifactId>
<version>[2.0.0-SNAPSHOT,3.0.0-SNAPSHOT)</version>
</dependency>
<!-- END of Home Library dependencies -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>
<!-- Libraries explicitly forced to provided -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.gcube.resources</groupId>
<artifactId>common-gcore-resources</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.gcube.core</groupId>
<artifactId>common-gcore-stubs</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.gcube.core</groupId>
<artifactId>common-scope</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.gcube.core</groupId>
<artifactId>common-scope-maps</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.gcube.resources.discovery</groupId>
<artifactId>discovery-client</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.gcube.core</groupId>
<artifactId>common-encryption</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.gcube.common</groupId>
<artifactId>authorization-client</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.gcube.common</groupId>
<artifactId>common-authorization</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.gcube.resources.discovery</groupId>
<artifactId>ic-client</artifactId>
<scope>provided</scope>
</dependency>
<!-- END Libraries explicitly forced to provided -->
<dependency>
<groupId>org.gcube.core</groupId>
<artifactId>common-smartgears</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>de.grundid.opendatalab</groupId>
<artifactId>geojson-jackson</artifactId>
<version>1.8</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.3</version>
</dependency>
<!-- Used to automatically convert XML to JSON -->
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20140107</version>
</dependency>
<!-- 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>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.0.13</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<executions>
<execution>
<id>copy-profile</id>
<goals>
<goal>copy-resources</goal>
</goals>
<phase>process-resources</phase>
<configuration>
<outputDirectory>${webappDirectory}</outputDirectory>
<resources>
<resource>
<directory>${distroDirectory}</directory>
<filtering>true</filtering>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<warName>${artifactId}</warName>
<failOnMissingWebXml>false</failOnMissingWebXml>
<!-- webXml>src\main\webapp\WEB-INF\web.xml</webXml -->
</configuration>
<executions>
<execution>
<id>servicearchive</id>
<phase>install</phase>
<goals>
<goal>war</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

@ -0,0 +1,21 @@
package org.gcube.gcat;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.MediaType;
import org.gcube.gcat.rest.Group;
import org.glassfish.jersey.server.ResourceConfig;
/**
* @author Luca Frosini (ISTI - CNR)
*/
@ApplicationPath("/")
public class ResourceInitializer extends ResourceConfig {
public static final String APPLICATION_JSON_CHARSET_UTF_8 = MediaType.APPLICATION_JSON + ";charset=UTF-8";
public ResourceInitializer() {
packages(Group.class.getPackage().toString());
}
}

@ -0,0 +1,14 @@
package org.gcube.gcat.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.ws.rs.HttpMethod;
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@HttpMethod("PATCH")
public @interface PATCH {
}

@ -0,0 +1,14 @@
package org.gcube.gcat.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.ws.rs.HttpMethod;
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@HttpMethod("PURGE")
public @interface PURGE {
}

@ -0,0 +1,25 @@
package org.gcube.gcat.exception;
/**
* @author Luca Frosini (ISTI - CNR)
*/
public class ScienceCatalogueException extends Exception {
/**
* Generated Serial Version UID
*/
private static final long serialVersionUID = -5449813222333935588L;
public ScienceCatalogueException(String message) {
super(message);
}
public ScienceCatalogueException(Throwable cause) {
super(cause);
}
public ScienceCatalogueException(String message, Throwable cause) {
super(message, cause);
}
}

@ -0,0 +1,67 @@
package org.gcube.gcat.oldutils;
import javax.cache.Cache;
import javax.cache.CacheManager;
import javax.cache.Caching;
import javax.cache.configuration.MutableConfiguration;
import javax.cache.expiry.CreatedExpiryPolicy;
import javax.cache.expiry.Duration;
import javax.cache.spi.CachingProvider;
import org.gcube.datacatalogue.metadatadiscovery.DataCalogueMetadataFormatReader;
import com.fasterxml.jackson.databind.JsonNode;
/**
* Handle caches via Ehcache stuff.
* @author Costantino Perciante (ISTI - CNR)
* @author Luca Frosini (ISTI - CNR)
*/
public class CachesManager {
// the following caches are declared within the ehcache.xml (no default is available, so pay attention)
public static final String PROFILES_READERS_CACHE = "profile_readers";
public static final String PROFILES_USERS_CACHE = "profile_users";
private static final CacheManager cacheManager;
private static final Cache<String, DataCalogueMetadataFormatReader> readerCache;
private static final Cache<String, JsonNode> userCache;
static {
CachingProvider provider = Caching.getCachingProvider();
cacheManager = provider.getCacheManager();
MutableConfiguration<String, DataCalogueMetadataFormatReader> readerConfiguration =
new MutableConfiguration<String, DataCalogueMetadataFormatReader>()
.setTypes(String.class, DataCalogueMetadataFormatReader.class)
.setStoreByValue(false)
.setExpiryPolicyFactory(CreatedExpiryPolicy.factoryOf(Duration.ONE_MINUTE));
readerCache = cacheManager.createCache(PROFILES_READERS_CACHE, readerConfiguration);
MutableConfiguration<String, JsonNode> userConfiguration =
new MutableConfiguration<String, JsonNode>()
.setTypes(String.class, JsonNode.class)
.setStoreByValue(false)
.setExpiryPolicyFactory(CreatedExpiryPolicy.factoryOf(Duration.ONE_MINUTE));
userCache = cacheManager.createCache(PROFILES_USERS_CACHE, userConfiguration);
}
private CachesManager() {}
public static Cache<String, DataCalogueMetadataFormatReader> getReaderCache() {
return readerCache;
}
public static Cache<String, JsonNode> getUserCache() {
return userCache;
}
@Override
protected void finalize() throws Throwable {
super.finalize();
cacheManager.close();
}
}

@ -0,0 +1,134 @@
package org.gcube.gcat.oldutils;
import org.json.simple.JSONObject;
/**
* A custom field bean. It also stores index of the category and of the metadata field associated.
* These are used to sort them before pushing the content to CKAN.
* If they are missing, indexes are set to Integer.MAX_VALUE.
* @author Costantino Perciante (ISTI - CNR)
* @author Luca Frosini (ISTI - CNR)
*/
public class CustomField implements Comparable<CustomField> {
private String key;
private String qualifiedKey;
private String value;
private int indexCategory = Integer.MAX_VALUE;
private int indexMetadataField = Integer.MAX_VALUE;
private void init(String key, String value, int indexCategory, int indexMetadataField) {
if(key == null || value == null || key.isEmpty()) {
throw new IllegalArgumentException(
"A custom field must have a key and a value! Provided values are " + key + "=" + value);
}
this.key = key;
this.qualifiedKey = key;
this.value = value;
this.indexMetadataField = indexMetadataField;
this.indexCategory = indexCategory;
if(this.indexCategory < 0) {
this.indexCategory = Integer.MAX_VALUE;
}
if(this.indexMetadataField < 0) {
this.indexMetadataField = Integer.MAX_VALUE;
}
}
public CustomField(JSONObject object) {
super();
init((String) object.get("key"), (String) object.get("value"), -1, -1);
}
/**
* @param key
* @param value
*/
public CustomField(String key, String value) {
super();
init(key, value, -1, -1);
}
/**
* @param key
* @param value
* @param indexMetadataField
* @param indexCategory
*/
public CustomField(String key, String value, int indexCategory, int indexMetadataField) {
super();
init(key, value, indexCategory, indexMetadataField);
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public String getQualifiedKey() {
return qualifiedKey;
}
public void setQualifiedKey(String qualifiedKey) {
this.qualifiedKey = qualifiedKey;
}
public int getIndexCategory() {
return indexCategory;
}
public void setIndexCategory(int indexCategory) {
this.indexCategory = indexCategory;
if(this.indexCategory < 0)
this.indexCategory = Integer.MAX_VALUE;
}
public int getIndexMetadataField() {
return indexMetadataField;
}
public void setIndexMetadataField(int indexMetadataField) {
this.indexMetadataField = indexMetadataField;
if(this.indexMetadataField < 0) {
this.indexMetadataField = Integer.MAX_VALUE;
}
}
@Override
public String toString() {
return "CustomField [key=" + key + ", qualifiedKey=" + qualifiedKey + ", value=" + value
+ ", indexMetadataField=" + indexMetadataField + ", indexCategory=" + indexCategory + "]";
}
@Override
public int compareTo(CustomField o) {
if(this.indexCategory == o.indexCategory) {
if(this.indexMetadataField == o.indexMetadataField) {
return 0;
} else {
return this.indexMetadataField > o.indexMetadataField ? 1 : -1;
}
} else {
return this.indexCategory > o.indexCategory ? 1 : -1;
}
}
}

@ -0,0 +1,633 @@
package org.gcube.gcat.oldutils;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import javax.ws.rs.BadRequestException;
import org.apache.commons.lang.math.NumberUtils;
import org.gcube.common.scope.api.ScopeProvider;
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.MetadataField;
import org.gcube.datacatalogue.metadatadiscovery.bean.jaxb.MetadataFormat;
import org.gcube.datacatalogue.metadatadiscovery.bean.jaxb.MetadataGrouping;
import org.gcube.datacatalogue.metadatadiscovery.bean.jaxb.MetadataTagging;
import org.gcube.datacatalogue.metadatadiscovery.bean.jaxb.NamespaceCategory;
import org.gcube.gcat.persistence.ckan.CKAN;
import org.gcube.gcat.persistence.ckan.CKANPackage;
import org.gcube.gcat.persistence.ckan.CKANUtility;
import org.gcube.gcat.rest.Namespace;
import org.gcube.gcat.rest.Profile;
import org.gcube.gcat.social.SocialService;
import org.geojson.GeoJsonObject;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.databind.ObjectMapper;
import eu.trentorise.opendata.jackan.model.CkanGroup;
/**
* Validate creation item requests utilities.
* @author Costantino Perciante (ISTI - CNR)
* @author Luca Frosini (ISTI - CNR)
*/
@SuppressWarnings({"rawtypes", "unchecked"})
public class Validator {
private static final Logger logger = LoggerFactory.getLogger(Validator.class);
private static final SimpleDateFormat DATE_SIMPLE = new SimpleDateFormat("yyyy-MM-dd");
private static final SimpleDateFormat DATE_HOUR_MINUTES = new SimpleDateFormat("yyyy-MM-dd HH:mm");
private static JSONObject getJSONObject(String json) {
JSONParser parser = new JSONParser();
JSONObject jsonObject;
try {
jsonObject = (JSONObject) parser.parse(json);
} catch(ParseException e) {
throw new BadRequestException(e.getMessage());
}
return jsonObject;
}
public static void validateAgainstProfile(String json, List<String> profiles) throws Exception {
JSONObject jsonObject = getJSONObject(json);
validateAgainstProfile(jsonObject, profiles);
}
/**
* This method validate the incoming json dataset wrt a metadata profile
* @param json
* @param caller
* @param profiles
* @return
* @throws Exception
*/
public static void validateAgainstProfile(JSONObject obj, List<String> profiles) throws Exception {
JSONArray extrasArrayOriginal = (JSONArray) obj.get(CKANPackage.EXTRA_TYPES_KEY);
JSONArray groupsArrayOriginal = (JSONArray) obj.get(CKANPackage.GROUPS_KEY);
JSONArray tagsArrayOriginal = (JSONArray) obj.get(CKANPackage.TAGS_KEY);
if(extrasArrayOriginal == null || extrasArrayOriginal.isEmpty()) {
throw new Exception("'extras' field is missing in context where metadata profile(s) are defined!");
}
if(groupsArrayOriginal == null) {
groupsArrayOriginal = new JSONArray();
}
if(tagsArrayOriginal == null) {
tagsArrayOriginal = new JSONArray();
}
// get the metadata profile specifying the type
CustomField metadataTypeCF = null;
List<CustomField> customFields = new ArrayList<CustomField>(extrasArrayOriginal.size());
Iterator iterator = extrasArrayOriginal.iterator();
while(iterator.hasNext()) {
JSONObject object = (JSONObject) iterator.next();
CustomField cf = new CustomField(object);
if(cf.getKey().equals(CKANPackage.EXTRA_TYPES_KEY_VALUE_SYSTEM_TYPE)) {
metadataTypeCF = cf;
} else if(cf.getKey().equals(SocialService.ITEM_URL)) {
continue;
} else {
customFields.add(cf);
}
}
if(metadataTypeCF == null) {
throw new Exception("'" + CKANPackage.EXTRA_TYPES_KEY_VALUE_SYSTEM_TYPE
+ "' extra field is missing in context where metadata profile(s) are defined!");
}
// fetch the profile by metadata type specified above
MetadataFormat profile = null;
for(String profileName : profiles) {
profile = Validator.getMetadataProfile(profileName);
if(profile.getType().equals(metadataTypeCF.getValue())) {
break;
} else {
profile = null;
}
}
if(profile == null) {
throw new Exception("'" + CKANPackage.EXTRA_TYPES_KEY_VALUE_SYSTEM_TYPE
+ "' extra field's value ('" + metadataTypeCF.getValue() +
"') specified as custom field doesn't match any of the profiles defined in this context!");
} else {
JSONArray extrasArrayUpdated = null;
List<MetadataField> metadataFields = profile.getMetadataFields();
if(metadataFields == null || metadataFields.isEmpty()) {
extrasArrayUpdated = extrasArrayOriginal;
} else {
extrasArrayUpdated = new JSONArray();
List<NamespaceCategory> categories = Namespace.getNamespaceCategories();
logger.debug("Retrieved namespaces are {}", categories);
List<String> categoriesIds = new ArrayList<String>(categories == null ? 0 : categories.size());
if(categories == null || categories.isEmpty()) {
logger.warn("No category defined in context {}", ScopeProvider.instance.get());
} else {
for(NamespaceCategory metadataCategory : categories) {
categoriesIds.add(metadataCategory.getId()); // save them later for matching with custom fields
}
}
// the list of already validated customFields
List<CustomField> validatedCustomFields = new ArrayList<CustomField>(customFields.size());
// keep track of mandatory fields and their cardinality
Map<String,Integer> fieldsMandatoryLowerBoundMap = new HashMap<String,Integer>(metadataFields.size());
Map<String,Integer> fieldsMandatoryUpperBoundMap = new HashMap<String,Integer>(metadataFields.size());
Map<String,Integer> numberFieldsMandatorySameKeyMap = new HashMap<String,Integer>(
metadataFields.size());
// keep track of the groups that must be created AFTER validation but BEFORE item creation
List<String> groupsToCreateAfterValidation = new ArrayList<String>();
// now validate fields
int metadataIndex = 0;
for(MetadataField metadataField : metadataFields) {
int categoryIdIndex = categoriesIds.indexOf(metadataField.getCategoryRef());
logger.debug("Found index for category " + metadataField.getCategoryRef() + " " + categoryIdIndex);
List<CustomField> validCFs = validateAgainstMetadataField(metadataIndex, categoryIdIndex,
customFields, tagsArrayOriginal, groupsArrayOriginal, metadataField, categories,
fieldsMandatoryLowerBoundMap, fieldsMandatoryUpperBoundMap, numberFieldsMandatorySameKeyMap,
groupsToCreateAfterValidation);
validatedCustomFields.addAll(validCFs);
metadataIndex++;
}
// check mandatory fields
Iterator<Entry<String,Integer>> iteratorLowerBounds = fieldsMandatoryLowerBoundMap.entrySet()
.iterator();
while(iteratorLowerBounds.hasNext()) {
Map.Entry<java.lang.String,java.lang.Integer> entry = (Map.Entry<java.lang.String,java.lang.Integer>) iteratorLowerBounds
.next();
int lowerBound = entry.getValue();
int upperBound = fieldsMandatoryUpperBoundMap.get(entry.getKey());
int inserted = numberFieldsMandatorySameKeyMap.get(entry.getKey());
logger.info("Field with key '" + entry.getKey() + "' has been found " + inserted
+ " times and its lower bound is " + lowerBound + " and upper bound " + upperBound);
if(inserted < lowerBound || inserted > upperBound) {
throw new Exception("Field with key '" + entry.getKey()
+ "' is mandatory, but it's not present among the provided fields or its cardinality is not respected ([min = "
+ lowerBound + ", max=" + upperBound + "]).");
}
}
// if there are no tags, throw an exception
if(tagsArrayOriginal.isEmpty()) {
throw new Exception("Please define at least one tag for this item!");
}
// sort validated custom fields and add to the extrasArrayUpdated json array
Collections.sort(validatedCustomFields);
logger.debug("Sorted list of custom fields is " + validatedCustomFields);
// add missing fields with no match (append them at the end, since no metadataIndex or categoryIndex was defined for them)
for(CustomField cf : customFields)
validatedCustomFields.add(cf);
// convert back to json
for(CustomField customField : validatedCustomFields) {
JSONObject jsonObj = new JSONObject();
jsonObj.put(CKANPackage.EXTRA_TYPES_KEY_KEY, customField.getQualifiedKey());
jsonObj.put(CKANPackage.EXTRA_TYPES_VALUE_KEY, customField.getValue());
extrasArrayUpdated.add(jsonObj);
}
// add metadata type field as last element
JSONObject metadataTypeJSON = new JSONObject();
metadataTypeJSON.put(CKANPackage.EXTRA_TYPES_KEY_KEY, metadataTypeCF.getKey());
metadataTypeJSON.put(CKANPackage.EXTRA_TYPES_VALUE_KEY, metadataTypeCF.getValue());
extrasArrayUpdated.add(metadataTypeJSON);
// create groups
for(String title : groupsToCreateAfterValidation) {
try {
createGroupAsSysAdmin(title, title, "");
} catch(Exception e) {
logger.error("Failed to create group with title " + title, e);
}
}
}
obj.put(CKANPackage.TAGS_KEY, tagsArrayOriginal);
obj.put(CKANPackage.GROUPS_KEY, groupsArrayOriginal);
obj.put(CKANPackage.EXTRA_TYPES_KEY, extrasArrayUpdated);
}
}
/**
* Retrieve an instance of the library for the scope
* @param scope if it is null it is evaluated from the session
* @return
* @throws Exception
*/
public static CkanGroup createGroupAsSysAdmin(String title, String groupName, String description) throws Exception {
return CKAN.getCatalogue().createGroup(groupName, title, description);
}
/**
* Validate this field and generate a new value (or returns the same if there is nothing to update)
* @param metadataIndex
* @param categoryIndex
* @param customFields
* @param tagsArrayOriginal
* @param groupsArrayOriginal
* @param metadataField
* @param categories
* @param numberFieldsSameKeyMap
* @param fieldsMandatoryLowerBoundMap
* @param isApplication
* @return
* @throws Exception
*/
private static List<CustomField> validateAgainstMetadataField(int metadataIndex, int categoryIndex,
List<CustomField> customFields, JSONArray tagsArrayOriginal, JSONArray groupsArrayOriginal,
MetadataField metadataField, List<NamespaceCategory> categories,
Map<String,Integer> fieldsMandatoryLowerBoundMap, Map<String,Integer> fieldsMandatoryUpperBoundMap,
Map<String,Integer> numberFieldsMandatorySameKeyMap, List<String> groupToCreate) throws Exception {
List<CustomField> toReturn = new ArrayList<CustomField>();
String metadataFieldName = metadataField.getCategoryFieldQName(); // get the qualified one, if any
int fieldsFoundWithThisKey = 0;
Iterator<CustomField> iterator = customFields.iterator();
while(iterator.hasNext()) {
CustomField cf = (CustomField) iterator.next();
if(cf.getKey().equals(metadataFieldName)) {
validate(cf, metadataField);
fieldsFoundWithThisKey++;
cf.setIndexCategory(categoryIndex);
cf.setIndexMetadataField(metadataIndex);
checkAsGroup(cf, metadataField, groupsArrayOriginal, groupToCreate);
checkAsTag(cf, metadataField, tagsArrayOriginal);
toReturn.add(cf);
iterator.remove();
}
}
// in case of mandatory fields, keep track of the number of times they appear
if(metadataField.getMandatory()) {
// lower bound
int lowerBound = 1;
if(fieldsMandatoryLowerBoundMap.containsKey(metadataFieldName))
lowerBound = fieldsMandatoryLowerBoundMap.get(metadataFieldName) + 1;
fieldsMandatoryLowerBoundMap.put(metadataFieldName, lowerBound);
// upper bound
boolean hasVocabulary = metadataField.getVocabulary() != null;
int upperBound = hasVocabulary ? (metadataField.getVocabulary().isMultiSelection()
? metadataField.getVocabulary().getVocabularyFields().size()
: 1) : 1;
if(fieldsMandatoryUpperBoundMap.containsKey(metadataFieldName))
upperBound += fieldsMandatoryUpperBoundMap.get(metadataFieldName);
fieldsMandatoryUpperBoundMap.put(metadataFieldName, upperBound);
// fields with this same key
int countPerFields = fieldsFoundWithThisKey;
if(numberFieldsMandatorySameKeyMap.containsKey(metadataFieldName))
countPerFields += numberFieldsMandatorySameKeyMap.get(metadataFieldName);
numberFieldsMandatorySameKeyMap.put(metadataFieldName, countPerFields);
}
// if there was no field with this key and it was not mandatory, just add an entry of the kind {"key": "key-value", "value" : ""}.
// Sometimes it is important to view the field as empty.
if(fieldsFoundWithThisKey == 0 && !metadataField.getMandatory()) {
toReturn.add(new CustomField(metadataFieldName, "", -1, -1));
}
return toReturn;
}
public static final int MAX_TAG_CHARS = 100;
/**
* Check if a tag must be generated
* @param fieldToValidate
* @param metadataField
* @param tagsArrayOriginal
*/
private static void checkAsTag(CustomField fieldToValidate, MetadataField metadataField,
JSONArray tagsArrayOriginal) {
MetadataTagging tagging = metadataField.getTagging();
if(tagging != null) {
String tag = "";
switch(tagging.getTaggingValue()) {
case onFieldName:
tag = metadataField.getFieldName();
break;
case onValue:
tag = fieldToValidate.getValue();
break;
case onFieldName_onValue:
tag = metadataField.getFieldName() + tagging.getSeparator() + fieldToValidate.getValue();
break;
case onValue_onFieldName:
tag = fieldToValidate.getValue() + tagging.getSeparator() + metadataField.getFieldName();
break;
default:
return;
}
tag = tag.substring(0, MAX_TAG_CHARS > tag.length() ? tag.length() : MAX_TAG_CHARS);
logger.debug("Tag is " + tag);
JSONObject tagJSON = new JSONObject();
tagJSON.put("name", tag);
tagJSON.put("display_name", tag);
tagsArrayOriginal.add(tagJSON);
}
}
/**
* Check if a group must be generated
* @param fieldToValidate
* @param metadataField
* @param groupsArrayOriginal
* @param isApplication
* @throws Exception
*/
private static void checkAsGroup(CustomField fieldToValidate, MetadataField metadataField,
JSONArray groupsArrayOriginal, List<String> groupToCreate) throws Exception {
logger.debug("Custom field is " + fieldToValidate);
logger.debug("MetadataField field is " + metadataField);
logger.debug("JSONArray field is " + groupsArrayOriginal);
MetadataGrouping grouping = metadataField.getGrouping();
if(grouping != null) {
boolean propagateUp = grouping.getPropagateUp();
final Set<String> groupNames = new HashSet<String>();
switch(grouping.getGroupingValue()) {
case onFieldName:
groupNames.add(metadataField.getFieldName());
break;
case onValue:
if(fieldToValidate.getValue() != null && !fieldToValidate.getValue().isEmpty())
groupNames.add(fieldToValidate.getValue());
break;
case onFieldName_onValue:
case onValue_onFieldName:
groupNames.add(metadataField.getFieldName());
if(fieldToValidate.getValue() != null && !fieldToValidate.getValue().isEmpty())
groupNames.add(fieldToValidate.getValue());
break;
default:
return;
}
for(String title : groupNames) {
logger.debug("Adding group to which add this item " + CatalogueUtilMethods.fromGroupTitleToName(title));
JSONObject group = new JSONObject();
group.put("name", CatalogueUtilMethods.fromGroupTitleToName(title));
if(propagateUp) {
List<String> parents = Validator.getGroupHierarchyNames(CatalogueUtilMethods.fromGroupTitleToName(title));
for(String parent : parents) {
JSONObject groupP = new JSONObject();
groupP.put("name", parent);
groupsArrayOriginal.add(groupP);
}
}
groupsArrayOriginal.add(group);
}
// force group creation if needed
if(grouping.getCreate()) {
for(String title : groupNames)
groupToCreate.add(title);
}
}
}
/**
* Validate the single field
* @param fieldToValidate
* @param metadataField
* @param isFirst
* @return
* @throws Exception
*/
private static void validate(CustomField fieldToValidate, MetadataField metadataField) throws Exception {
DataType dataType = metadataField.getDataType();
String regex = metadataField.getValidator() != null ? metadataField.getValidator().getRegularExpression()
: null;
boolean hasControlledVocabulary = metadataField.getVocabulary() != null;
String value = fieldToValidate.getValue();
String key = fieldToValidate.getKey();
String defaultValue = metadataField.getDefaultValue();
// replace key by prepending the qualified name of the category, if needed
fieldToValidate.setQualifiedKey(metadataField.getCategoryFieldQName());
if((value == null || value.isEmpty()))
if(metadataField.getMandatory() || hasControlledVocabulary)
throw new Exception("Mandatory field with name '" + key
+ "' doesn't have a value but it is mandatory or has a controlled vocabulary!");
else {
if(defaultValue != null && !defaultValue.isEmpty()) {
value = defaultValue;
fieldToValidate.setValue(defaultValue);
}
return; // there is no need to check other stuff
}
switch(dataType) {
case String:
case Text:
if(regex != null && !value.matches(regex))
throw new Exception("Field with key '" + key + "' doesn't match the provided regular expression ("
+ regex + ")!");
if(hasControlledVocabulary) {
List<String> valuesVocabulary = metadataField.getVocabulary().getVocabularyFields();
if(valuesVocabulary == null || valuesVocabulary.isEmpty())
return;
boolean match = false;
for(String valueVocabulary : valuesVocabulary) {
match = value.equals(valueVocabulary);
if(match)
break;
}
if(!match)
throw new Exception("Field with key '" + key + "' has a value '" + value
+ "' but it doesn't match any of the vocabulary's values (" + valuesVocabulary + ")!");
}
break;
case Time:
if(!isValidDate(value))
throw new Exception("Field with key '" + key + "' doesn't seem a valid time!");
break;
case Time_Interval:
String[] timeValues = value.split("/");
for(int i = 0; i < timeValues.length; i++) {
String time = timeValues[i];
if(!isValidDate(time))
throw new Exception("Field with key '" + key + "' doesn't seem a valid time interval!");
}
break;
case Times_ListOf:
String[] timeIntervals = value.split(",");
for(int i = 0; i < timeIntervals.length; i++) {
String[] timeIntervalValues = timeIntervals[i].split("/");
if(timeIntervalValues.length > 2)
throw new Exception("Field with key '" + key + "' doesn't seem a valid list of times!");
for(i = 0; i < timeIntervalValues.length; i++) {
String time = timeIntervalValues[i];
if(!isValidDate(time))
throw new Exception("Field with key '" + key + "' doesn't seem a valid list of times!");
}
}
break;
case Boolean:
if(value.equalsIgnoreCase("true") || value.equalsIgnoreCase("false")) {
} else
throw new Exception("Field with key '" + key + "' doesn't seem a valid boolean value!");
break;
case Number:
if(!NumberUtils.isNumber(value))
throw new Exception("Field's value with key '" + key + "' is not a valid number!");
break;
case GeoJSON:
try {
new ObjectMapper().readValue(fieldToValidate.getValue(), GeoJsonObject.class);
} catch(Exception e) {
throw new Exception("GeoJSON field with key '" + key + "' seems not valid!");
}
break;
default:
break;
}
}
/**
* Validate a time date against a formatter
* @param value
* @param formatter
* @return
*/
private static boolean isValidDate(String value) {
try {
DATE_HOUR_MINUTES.parse(value);
return true;
} catch(Exception e) {
logger.debug("failed to parse date with hours and minutes, trying the other one");
try {
DATE_SIMPLE.parse(value);
return true;
} catch(Exception e2) {
logger.warn("failed to parse date with simple format, returning false");
return false;
}
}
}
/**
* Get the group hierarchy
* @param groupName
* @param isApplication
* @return
* @throws Exception
*/
public static List<String> getGroupHierarchyNames(String groupName) throws Exception {
List<String> toReturn = new ArrayList<String>();
String apiKey = CKANUtility.getApiKey();
List<CkanGroup> ckanGroups = CKAN.getCatalogue().getParentGroups(groupName, apiKey);
if(ckanGroups != null && !ckanGroups.isEmpty()) {
for(CkanGroup ckanGroup : ckanGroups) {
toReturn.add(ckanGroup.getName());
}
}
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;
}
}

@ -0,0 +1,300 @@
package org.gcube.gcat.persistence.ckan;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.ws.rs.BadRequestException;
import javax.ws.rs.InternalServerErrorException;
import javax.ws.rs.NotAuthorizedException;
import javax.ws.rs.NotFoundException;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import org.gcube.datacatalogue.ckanutillibrary.server.DataCatalogue;
import org.gcube.datacatalogue.ckanutillibrary.server.DataCatalogueFactory;
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.LoggerFactory;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.NullNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
/**
* @author Luca Frosini (ISTI - CNR)
*/
public abstract class CKAN {
private static final Logger logger = LoggerFactory.getLogger(CKAN.class);
protected static final String ID_KEY = "id";
protected static final String NAME_KEY = "name";
protected static final String ERROR_KEY = "error";
protected static final String ERROR_TYPE_KEY = "__type";
protected static final String MESSAGE_KEY = "message";
protected static final String OWNER_ORG_KEY = "owner_org";
protected static final String RESULT_KEY = "result";
protected static final String SUCCESS_KEY = "success";
protected static final String NOT_FOUND_ERROR = "Not Found Error";
protected static final String AUTHORIZATION_ERROR = "Authorization Error";
protected static final String VALIDATION_ERROR = "Validation Error";
// api rest path CKAN
public final static String CKAN_API_PATH = "/api/3/action/";
// ckan header authorization
public final static String AUTH_CKAN_HEADER = "Authorization";
protected String LIST;
protected String CREATE;
protected String READ;
protected String UPDATE;
protected String PATCH;
protected String DELETE;
protected String PURGE;
protected final ObjectMapper mapper;
protected final DataCatalogue dataCatalogue;
protected String name;
protected String apiKey;
protected JsonNode result;
public String getApiKey() {
if(apiKey==null) {
try {
return CKANUtility.getApiKey();
}catch (Exception e) {
throw new InternalServerErrorException(e);
}
}
return apiKey;
}
public void setApiKey(String apiKey) {
this.apiKey = apiKey;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public ObjectMapper getMapper() {
return mapper;
}
public JsonNode getJsonNodeResult() {
return result;
}
protected CKAN() {
try {
this.mapper = new ObjectMapper();
this.dataCatalogue = getCatalogue();
}catch (Exception e) {
throw new InternalServerErrorException(e);
}
}
protected JsonNode getAsJsonNode(String json) {
try {
return mapper.readTree(json);
} catch(IOException e) {
throw new BadRequestException(e);
}
}
/**
* Retrieve an instance of the library for the current scope
* @return
* @throws Exception
*/
public static DataCatalogue getCatalogue() throws Exception {
String context = ContextUtility.getCurrentContext();
logger.debug("Discovering ckan instance in context {}", context);
return DataCatalogueFactory.getFactory().getUtilsPerScope(context);
}
/**
* Validate the CKAN response and return the
* @param json
* @return
*/
protected JsonNode validateCKANResponse(String json) {
JsonNode jsonNode = getAsJsonNode(json);
if(jsonNode.get(SUCCESS_KEY).asBoolean()) {
return jsonNode.get(RESULT_KEY);
} else {
try {
JsonNode error = jsonNode.get(ERROR_KEY);
String errorType = error.get(ERROR_TYPE_KEY).asText();
if(errorType.compareTo(VALIDATION_ERROR) == 0) {
throw new BadRequestException(getAsString(error));
}
String message = error.get(MESSAGE_KEY).asText();
if(errorType.compareTo(NOT_FOUND_ERROR) == 0) {
throw new NotFoundException(message);
}
if(errorType.compareTo(AUTHORIZATION_ERROR) == 0) {
throw new NotAuthorizedException(message);
}
// TODO parse more cases
} catch(WebApplicationException e) {
throw e;
} catch(Exception e) {
throw new BadRequestException(json);
}
throw new BadRequestException(json);
}
}
protected String getAsString(JsonNode node) {
try {
String json = mapper.writeValueAsString(node);
return json;
} catch(JsonProcessingException e) {
throw new InternalServerErrorException(e);
}
}
protected JsonNode checkName(JsonNode jsonNode) {
try {
String gotName = jsonNode.get(NAME_KEY).asText();
if(name==null) {
name = gotName;
}
if(gotName != null && gotName.compareTo(name) != 0) {
String error = String.format(
"The name (%s) does not match with the '%s' contained in the provided content (%s).",
name, NAME_KEY, gotName);
throw new BadRequestException(error);
}
return jsonNode;
} catch(BadRequestException e) {
throw e;
} catch(Exception e) {
throw new BadRequestException("Unable to obtain a correct 'name' from the provided content");
}
}
protected JsonNode checkName(String json) {
JsonNode jsonNode = getAsJsonNode(json);
checkName(jsonNode);
return jsonNode;
}
protected JsonNode createJsonNodeWithID(String id) {
ObjectNode objectNode = mapper.createObjectNode();
objectNode.put(ID_KEY, id);
return objectNode;
}
protected JsonNode createJsonNodeWithNameAsID() {
return createJsonNodeWithID(name);
}
protected Map<String,String> getMapWithNameAsID() {
return getMapWithID(name);
}
protected Map<String,String> getMapWithID(String id) {
Map<String,String> map = new HashMap<>();
map.put(ID_KEY, id);
return map;
}
public JsonNode sendRequest(HTTPMETHOD httpMethod, String path, Map<String,String> parameters, String body) {
String catalogueURL = dataCatalogue.getCatalogueUrl().endsWith("/") ? dataCatalogue.getCatalogueUrl() : dataCatalogue.getCatalogueUrl() + "/";
HTTPCall httpCall = new HTTPCall(catalogueURL);
httpCall.setgCubeTargetService(false);
httpCall.addHeader(AUTH_CKAN_HEADER, getApiKey());
String ret = httpCall.call(path, httpMethod, parameters, body, MediaType.APPLICATION_JSON);
JsonNode result = validateCKANResponse(ret);
if(result instanceof NullNode) {
result = mapper.createObjectNode();
}
return result;
}
public String sendGetRequest(String path, Map<String,String> parameters) {
result = sendRequest(HTTPMETHOD.GET, path, parameters, null);
return getAsString(result);
}
public String sendPostRequest(String path, String body) {
result = sendRequest(HTTPMETHOD.POST, path, null, body);
return getAsString(result);
}
public String sendPostRequest(String path, JsonNode jsonNode) {
return sendPostRequest(path, getAsString(jsonNode));
}
public String list() {
return sendGetRequest(LIST, null);
}
public String create(String json) {
return sendPostRequest(CREATE, json);
}
public String read() {
return sendGetRequest(READ, getMapWithNameAsID());
}
public String update(String json) {
checkName(json);
return sendPostRequest(UPDATE, json);
}
public String patch(String json) {
JsonNode jsonNode = checkName(json);
ObjectNode objectNode = ((ObjectNode) jsonNode);
objectNode.put(ID_KEY, name);
objectNode.remove(NAME_KEY);
return sendPostRequest(PATCH, objectNode);
}
protected void delete() {
sendPostRequest(DELETE, createJsonNodeWithNameAsID());
}
public void delete(boolean purge) {
if(purge) {
purge();
} else {
delete();
}
}
protected void purge() {
sendPostRequest(PURGE, createJsonNodeWithNameAsID());
}
}

@ -0,0 +1,34 @@
package org.gcube.gcat.persistence.ckan;
/**
* @author Luca Frosini (ISTI - CNR)
*/
public class CKANGroup extends CKAN {
// see http://docs.ckan.org/en/latest/api/#ckan.logic.action.get.group_list
public static final String GROUP_LIST = CKAN.CKAN_API_PATH + "group_list";
// see http://docs.ckan.org/en/latest/api/#ckan.logic.action.create.group_create
public static final String GROUP_CREATE = CKAN.CKAN_API_PATH + "group_create";
// see http://docs.ckan.org/en/latest/api/#ckan.logic.action.get.group_show
public static final String GROUP_SHOW = CKAN.CKAN_API_PATH + "group_show";
// see http://docs.ckan.org/en/latest/api/#ckan.logic.action.update.group_update
public static final String GROUP_UPDATE = CKAN.CKAN_API_PATH + "group_update";
// see http://docs.ckan.org/en/latest/api/#ckan.logic.action.patch.group_patch
public static final String GROUP_PATCH = CKAN.CKAN_API_PATH + "group_patch";
// see http://docs.ckan.org/en/latest/api/#ckan.logic.action.delete.group_delete
public static final String GROUP_DELETE = CKAN.CKAN_API_PATH + "group_delete";
// see http://docs.ckan.org/en/latest/api/#ckan.logic.action.delete.group_purge
public static final String GROUP_PURGE = CKAN.CKAN_API_PATH + "group_purge";
public CKANGroup() {
super();
LIST = GROUP_LIST;
CREATE = GROUP_CREATE;
READ = GROUP_SHOW;
UPDATE = GROUP_UPDATE;
PATCH = GROUP_PATCH;
DELETE = GROUP_DELETE;
PURGE = GROUP_PURGE;
}
}

@ -0,0 +1,16 @@
package org.gcube.gcat.persistence.ckan;
/**
* @author Luca Frosini (ISTI - CNR)
*/
public class CKANLicense extends CKAN {
// see http://docs.ckan.org/en/latest/api/#ckan.logic.action.get.license_list
public static final String LICENSES_LIST = CKAN.CKAN_API_PATH + "license_list";
public CKANLicense() {
super();
LIST = LICENSES_LIST;
}
}

@ -0,0 +1,106 @@
package org.gcube.gcat.persistence.ckan;
import java.util.Map;
import java.util.Set;
import org.gcube.common.scope.impl.ScopeBean;
import org.gcube.datacatalogue.ckanutillibrary.shared.RolesCkanGroupOrOrg;
import org.gcube.gcat.utils.ContextUtility;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
import eu.trentorise.opendata.jackan.model.CkanOrganization;
/**
* @author Luca Frosini (ISTI - CNR)
*/
public class CKANOrganization extends CKAN {
private static Logger logger = LoggerFactory.getLogger(CKANOrganization.class);
// CKAN Connector sanitize the Organization name as following
//organizationName.replaceAll(" ", "_").replace(".", "_").toLowerCase()
// see http://docs.ckan.org/en/latest/api/#ckan.logic.action.get.organization_list
public static final String ORGANIZATION_LIST = CKAN.CKAN_API_PATH + "organization_list";
// see http://docs.ckan.org/en/latest/api/#ckan.logic.action.create.organization_create
public static final String ORGANIZATION_CREATE = CKAN.CKAN_API_PATH + "organization_create";
// see http://docs.ckan.org/en/latest/api/#ckan.logic.action.get.organization_show
public static final String ORGANIZATION_SHOW = CKAN.CKAN_API_PATH + "organization_show";
// see http://docs.ckan.org/en/latest/api/#ckan.logic.action.update.organization_update
public static final String ORGANIZATION_UPDATE = CKAN.CKAN_API_PATH + "organization_update";
// see http://docs.ckan.org/en/latest/api/#ckan.logic.action.patch.organization_patch
public static final String ORGANIZATION_PATCH = CKAN.CKAN_API_PATH + "organization_patch";
// see http://docs.ckan.org/en/latest/api/#ckan.logic.action.delete.organization_delete
public static final String ORGANIZATION_DELETE = CKAN.CKAN_API_PATH + "organization_delete";
// see http://docs.ckan.org/en/latest/api/#ckan.logic.action.delete.organization_purge
public static final String ORGANIZATION_PURGE = CKAN.CKAN_API_PATH + "organization_purge";
// see https://docs.ckan.org/en/latest/api/#ckan.logic.action.create.organization_member_create
public static final String ORGANIZATION_MEMBER_CREATE = CKAN.CKAN_API_PATH + "organization_member_create";
// https://docs.ckan.org/en/latest/api/index.html#ckan.logic.action.get.organization_list_for_user
public static final String ORGANIZATION_LIST_FOR_USER = CKAN.CKAN_API_PATH + "organization_list_for_user";
protected static final String USERNAME_KEY = "username";
protected static final String ROLE_KEY = "role";
public CKANOrganization() {
super();
LIST = ORGANIZATION_LIST;
CREATE = ORGANIZATION_CREATE;
READ = ORGANIZATION_SHOW;
UPDATE = ORGANIZATION_UPDATE;
PATCH = ORGANIZATION_PATCH;
DELETE = ORGANIZATION_DELETE;
PURGE = ORGANIZATION_PURGE;
}
protected static final String ORGANIZATION_PERMISSION_KEY = "permission";
protected static final String ORGANIZATION_PERMISSION_VALUE_READ = "read";
public String getUserRole(String gCubeUsername) {
Map<String,Map<CkanOrganization,RolesCkanGroupOrOrg>> rolesPerOrganization = dataCatalogue
.getUserRoleByOrganization(gCubeUsername, CKANUtility.getApiKey(gCubeUsername));
if(rolesPerOrganization.containsKey(name)) {
Map<CkanOrganization,RolesCkanGroupOrOrg> map = rolesPerOrganization.get(name);
Set<CkanOrganization> ckanOrganizations = map.keySet();
for(CkanOrganization ckanOrganization : ckanOrganizations) {
return map.get(ckanOrganization).name().toLowerCase();
}
}
return null;
}
public void addUserToOrganisation(String gCubeUsername, String role, boolean force) {
String ckanUsername = CKANUtility.getCKANUsername(gCubeUsername);
String userRole = getUserRole(gCubeUsername);
if((userRole==null || force)) {
if(userRole!=null && userRole.toLowerCase().compareTo(role.toLowerCase())==0) {
logger.debug("User {} is already member of Organisation {} with role {}", ckanUsername, name, userRole);
return;
}
ObjectNode objectNode = mapper.createObjectNode();
objectNode.put(ID_KEY, name);
objectNode.put(USERNAME_KEY, ckanUsername);
objectNode.put(ROLE_KEY, role);
sendPostRequest(ORGANIZATION_MEMBER_CREATE, getAsString(objectNode));
logger.debug("User {} successfully added to Organisation {} with role {}", ckanUsername, name, role);
}else {
logger.debug("User {} is already member of Organisation {} with role {}", ckanUsername, name, userRole);
}
}
public static String getCKANOrganizationName() {
String context = ContextUtility.getCurrentContext();
return getCKANOrganizationName(context);
}
public static String getCKANOrganizationName(String context) {
ScopeBean scopeBean = new ScopeBean(context);
return scopeBean.name().toLowerCase();
}
}

@ -0,0 +1,346 @@
package org.gcube.gcat.persistence.ckan;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.ws.rs.BadRequestException;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.HEAD;
import javax.ws.rs.InternalServerErrorException;
import javax.ws.rs.NotAllowedException;
import javax.ws.rs.OPTIONS;
import javax.ws.rs.PUT;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response.Status;
import org.gcube.common.scope.impl.ScopeBean;
import org.gcube.common.scope.impl.ScopeBean.Type;
import org.gcube.gcat.annotation.PURGE;
import org.gcube.gcat.oldutils.Validator;
import org.gcube.gcat.social.SocialService;
import org.gcube.gcat.utils.ContextUtility;
import org.gcube.gcat.utils.URIResolver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
/**
* @author Luca Frosini (ISTI - CNR)
*/
public class CKANPackage extends CKAN {
private static final Logger logger = LoggerFactory.getLogger(CKANPackage.class);
// see https://docs.ckan.org/en/latest/api/#ckan.logic.action.get.package_list
public static final String ITEM_LIST = CKAN.CKAN_API_PATH + "package_list";
// see http://docs.ckan.org/en/latest/api/#ckan.logic.action.create.package_create
public static final String ITEM_CREATE = CKAN.CKAN_API_PATH + "package_create";
// see http://docs.ckan.org/en/latest/api/#ckan.logic.action.get.package_show
public static final String ITEM_SHOW = CKAN.CKAN_API_PATH + "package_show";
// see http://docs.ckan.org/en/latest/api/#ckan.logic.action.update.package_update
public static final String ITEM_UPDATE = CKAN.CKAN_API_PATH + "package_update";
// see http://docs.ckan.org/en/latest/api/#ckan.logic.action.patch.package_patch
public static final String ITEM_PATCH = CKAN.CKAN_API_PATH + "package_patch";
// see http://docs.ckan.org/en/latest/api/#ckan.logic.action.delete.package_delete
public static final String ITEM_DELETE = CKAN.CKAN_API_PATH + "package_delete";
// see http://docs.ckan.org/en/latest/api/#ckan.logic.action.delete.dataset_purge
public static final String ITEM_PURGE = CKAN.CKAN_API_PATH + "dataset_purge";
protected static final String LICENSE_KEY = "license_id";
protected static final String ITEM_URL_KEY = "item_url";
protected static final String AUTHOR_KEY = "author";
protected static final String AUTHOR_EMAIL_KEY = "author_email";
protected static final String OWNER_ORG_KEY = "owner_org";
protected static final String RESOURCES_KEY = "resources";
protected static final String TITLE_KEY = "title";
public static final String EXTRA_TYPES_KEY = "extras";
public static final String EXTRA_TYPES_KEY_KEY = "key";
public static final String EXTRA_TYPES_KEY_VALUE_SYSTEM_TYPE = "system:type";
public static final String EXTRA_TYPES_VALUE_KEY = "value";
public static final String GROUPS_KEY = "groups";
public static final String TAGS_KEY = "tags";
protected final List<CKANResource> managedResources;
protected String itemID;
public CKANPackage() {
super();
LIST = ITEM_LIST;
CREATE = ITEM_CREATE;
READ = ITEM_SHOW;
UPDATE = ITEM_UPDATE;
PATCH = ITEM_PATCH;
DELETE = ITEM_DELETE;
PURGE = ITEM_PURGE;
managedResources = new ArrayList<CKANResource>();
}
public ObjectNode checkBaseInformation(String json) throws Exception {
ObjectNode objectNode = (ObjectNode) mapper.readTree(json);
objectNode = (ObjectNode) checkName(objectNode);
// We need to enforce the itemID to properly manage resource persistence
if(objectNode.has(ID_KEY)) {
itemID = objectNode.get(ID_KEY).asText();
}
// check license
String licenseId = null;
if(objectNode.has(LICENSE_KEY)) {
licenseId = objectNode.get(LICENSE_KEY).asText();
}
if(licenseId == null || licenseId.isEmpty()) {
throw new BadRequestException(
"You must specify a license identifier for the item. License list can be retrieved using licence collection");
}
JsonNode userJsonNode = CKANUtility.getCKANUser();
objectNode.put(AUTHOR_KEY, userJsonNode.get(CKANUser.NAME).asText());
objectNode.put(AUTHOR_EMAIL_KEY, userJsonNode.get(CKANUser.EMAIL).asText());
// owner organization must be specified if the token belongs to a VRE
ScopeBean scopeBean = new ScopeBean(ContextUtility.getCurrentContext());
String contextName = scopeBean.name();
String gotOrganization = null;
if(objectNode.has(OWNER_ORG_KEY)) {
gotOrganization = objectNode.get(OWNER_ORG_KEY).asText();
}
if(scopeBean.is(Type.VRE)) {
String organizationFromContext = contextName.toLowerCase().replace(" ", "_");
if(gotOrganization != null) {
if(gotOrganization.compareTo(organizationFromContext) != 0) {
CKANOrganization ckanOrganization = new CKANOrganization();
ckanOrganization.setName(organizationFromContext);
ckanOrganization.read();
String organizationID = null;
if(ckanOrganization.result.has(ID_KEY)) {
organizationID = ckanOrganization.result.get(ID_KEY).asText();
}
if(organizationID == null || gotOrganization.compareTo(organizationID) != 0) {
throw new BadRequestException(
"You can only publish in the Organization associate to the current VRE");
}
}
} else {
objectNode.put(OWNER_ORG_KEY, organizationFromContext);
}
} else {
// TODO check if the requested organization context is a sub context of current context
// TODO check if the check is correct for PARTHENOS
if(gotOrganization == null) {
throw new BadRequestException("You must specify an Organization usign " + OWNER_ORG_KEY + " field");
}
}
return objectNode;
}
protected JsonNode validateJson(String json) {
try {
// check base information (and set them if needed)
ObjectNode objectNode = checkBaseInformation(json);
// Validating against profiles if any
// List<String> profiles = Profile.getProfilesNames(); TODO RESTORE THIS LINE
List<String> profiles = null; // TODO REMOVE THIS LINE
if(profiles != null && !profiles.isEmpty()) {
Validator.validateAgainstProfile(getAsString(objectNode), profiles);
}
return objectNode;
} catch(BadRequestException e) {
throw e;
} catch(Exception e) {
throw new BadRequestException(e);
}
}
// see https://docs.ckan.org/en/latest/api/#ckan.logic.action.get.package_list
@Override
public String list() {
return super.list();
}
protected void rollbackManagedResources() {
for(CKANResource ckanResource : managedResources) {
try {
ckanResource.rollback();
}catch (Exception e) {
logger.error("Unable to rollback resource {} to the original value", ckanResource.getResourceID());
}
}
}
protected ArrayNode createResources(ArrayNode resourcesToBeCreated) {
ArrayNode created = mapper.createArrayNode();
for(JsonNode resourceNode : resourcesToBeCreated) {
CKANResource ckanResource = new CKANResource(itemID);
String json = ckanResource.create(getAsString(resourceNode));
created.add(getAsJsonNode(json));
managedResources.add(ckanResource);
}
return created;
}
// see http://docs.ckan.org/en/latest/api/#ckan.logic.action.create.package_create
@Override
public String create(String json) {
try {
logger.debug("Going to create Item {}", json);
JsonNode jsonNode = validateJson(json);
ArrayNode resourcesToBeCreated = mapper.createArrayNode();
if(jsonNode.has(RESOURCES_KEY)) {
resourcesToBeCreated = (ArrayNode) jsonNode.get(RESOURCES_KEY);
((ObjectNode) jsonNode).remove(RESOURCES_KEY);
}
super.create(getAsString(jsonNode));
this.itemID = result.get(ID_KEY).asText();
ArrayNode created = createResources(resourcesToBeCreated);
((ObjectNode) result).replace(RESOURCES_KEY, created);
// Adding Item URL via Resolver
URIResolver uriResolver = new URIResolver();
String catalogueItemURL = uriResolver.getCatalogueItemURL(name);
((ObjectNode) result).put(ITEM_URL_KEY, catalogueItemURL);
// Actions performed after a package has been correctly created on ckan.
String title = result.get(TITLE_KEY).asText();
ArrayNode arrayNode = (ArrayNode) result.get(TAGS_KEY);
SocialService packagePostActions = new SocialService(catalogueItemURL, name, arrayNode, title);
packagePostActions.start();
return getAsString(result);
} catch(WebApplicationException e) {
rollbackManagedResources();
throw e;
} catch(Exception e) {
rollbackManagedResources();
throw new InternalServerErrorException(e);
}
}
// see http://docs.ckan.org/en/latest/api/#ckan.logic.action.update.package_update
@Override
public String update(String json) {
try {
JsonNode jsonNode = validateJson(json);
this.itemID = jsonNode.get(ID_KEY).asText();
read();
Map<String, CKANResource> originalResources = new HashMap<>();
ArrayNode originalResourcesarrayNode = (ArrayNode) result.get(RESOURCES_KEY);
if(originalResources!=null) {
for(JsonNode resourceNode : originalResourcesarrayNode) {
CKANResource ckanResource = new CKANResource(itemID);
ckanResource.setPreviousRepresentation(resourceNode);
String resourceID = ckanResource.getResourceID();
originalResources.put(resourceID, ckanResource);
}
}
if(jsonNode.has(RESOURCES_KEY)) {
ArrayNode resourcesToBeSend = mapper.createArrayNode();
ArrayNode receivedResources = (ArrayNode) jsonNode.get(RESOURCES_KEY);
for(JsonNode resourceNode : receivedResources) {
CKANResource ckanResource = new CKANResource(itemID);
String resourceId = CKANResource.extractResourceID(resourceNode);
if(resourceId!=null) {
if(originalResources.containsKey(resourceId)) {
ckanResource = originalResources.get(resourceId);
originalResources.remove(resourceId);
}else {
throw new BadRequestException("The content cotains a resource with id " + resourceId + " which does not exists") ;
}
}
resourceNode = ckanResource.createOrUpdate(resourceNode);
resourcesToBeSend.add(resourceNode);
managedResources.add(ckanResource);
}
((ObjectNode) jsonNode).replace(RESOURCES_KEY, resourcesToBeSend);
}
sendPostRequest(ITEM_UPDATE, getAsString(jsonNode));
for(String resourceId : originalResources.keySet()) {
CKANResource ckanResource = originalResources.get(resourceId);
ckanResource.deleteFile();
}
// Adding Item URL via Resolver
URIResolver uriResolver = new URIResolver();
String catalogueItemURL = uriResolver.getCatalogueItemURL(name);
((ObjectNode) result).put(ITEM_URL_KEY, catalogueItemURL);
return getAsString(result);
} catch(WebApplicationException e) {
rollbackManagedResources();
throw e;
} catch(Exception e) {
rollbackManagedResources();
throw new InternalServerErrorException(e);
}
}
// see http://docs.ckan.org/en/latest/api/#ckan.logic.action.patch.package_patch
@Override
public String patch(String json) {
String[] moreAllowed = new String[] {HEAD.class.getSimpleName(), GET.class.getSimpleName(),
PUT.class.getSimpleName(), DELETE.class.getSimpleName(), PURGE.class.getSimpleName()};
throw new NotAllowedException(OPTIONS.class.getSimpleName(), moreAllowed);
}
@Override
protected void delete() {
super.delete();
}
@Override
public void purge() {
try {
delete();
} catch(WebApplicationException e) {
// If the item was deleted but not purged we obtain Not Found. This is accepted. The item has to be purged
// with SysAdmin right.
Status status = Status.fromStatusCode(e.getResponse().getStatusInfo().getStatusCode());
if(status != Status.NOT_FOUND) {
throw e;
}
}
setApiKey(CKANUtility.getSysAdminAPI());
read();
if(result.has(RESOURCES_KEY)) {
itemID = result.get(ID_KEY).asText();
ArrayNode arrayNode = (ArrayNode) result.get(RESOURCES_KEY);
for(JsonNode jsonNode : arrayNode) {
CKANResource ckanResource = new CKANResource(itemID);
ckanResource.setPreviousRepresentation(jsonNode);
ckanResource.deleteFile();
}
}
super.purge();
}
}

@ -0,0 +1,409 @@
package org.gcube.gcat.persistence.ckan;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.UUID;
import javax.ws.rs.BadRequestException;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.HEAD;
import javax.ws.rs.InternalServerErrorException;
import javax.ws.rs.NotAllowedException;
import javax.ws.rs.OPTIONS;
import javax.ws.rs.PUT;
import javax.ws.rs.WebApplicationException;
import org.gcube.gcat.utils.ApplicationMode;
import org.gcube.gcat.utils.ContextUtility;
import org.gcube.gcat.utils.HTTPCall;
import org.gcube.gcat.workspace.StorageHubManagement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
/**
* @author Luca Frosini (ISTI - CNR)
*/
public class CKANResource extends CKAN {
private static final Logger logger = LoggerFactory.getLogger(CKANResource.class);
// see http://docs.ckan.org/en/latest/api/#ckan.logic.action.create.resource_create
public static final String RESOURCE_CREATE = CKAN.CKAN_API_PATH + "resource_create";
// see http://docs.ckan.org/en/latest/api/#ckan.logic.action.get.resource_show
public static final String RESOURCE_SHOW = CKAN.CKAN_API_PATH + "resource_show";
// see http://docs.ckan.org/en/latest/api/#ckan.logic.action.update.resource_update
public static final String RESOURCE_UPDATE = CKAN.CKAN_API_PATH + "resource_update";
// see http://docs.ckan.org/en/latest/api/#ckan.logic.action.patch.resource_patch
public static final String RESOURCE_PATCH = CKAN.CKAN_API_PATH + "resource_patch";
// see http://docs.ckan.org/en/latest/api/#ckan.logic.action.delete.resource_delete
public static final String RESOURCE_DELETE = CKAN.CKAN_API_PATH + "resource_delete";
/* 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_DEV = "data-d.d4science.org";
public static final String URI_RESOLVER_STORAGE_HUB_HOST;
public static final String URI_RESOLVER_STORAGE_HUB_PATH = "/shub/";
protected static final String URL_KEY = "url";
private static final String RESOURCES_KEY = "resources";
private static final String PACKAGE_ID_KEY = "package_id";
private static final String MIME_TYPE_KEY = "mimetype";
private static final String REVISION_ID_KEY = "revision_id";
private static final String TEMP = "TEMP_";
static {
String context = ContextUtility.getCurrentContext();
if(context.startsWith("/gcube")) {
URI_RESOLVER_STORAGE_HUB_HOST = URI_RESOLVER_STORAGE_HUB_HOST_DEV;
} else {
URI_RESOLVER_STORAGE_HUB_HOST = URI_RESOLVER_STORAGE_HUB_HOST_PROD;
}
}
/* TODO END Code to be Removed */
protected String itemID;
public String getItemID() {
return itemID;
}
protected String resourceID;
protected Boolean persisted;
protected URL persistedURL;
protected String mimeType;
protected JsonNode previousRepresentation;
protected StorageHubManagement storageHubManagement;
public URL getPersistedURL() {
return persistedURL;
}
public static String extractResourceID(JsonNode jsonNode) {
String resourceID = null;
if(jsonNode.has(ID_KEY)) {
resourceID = jsonNode.get(ID_KEY).asText();
}
return resourceID;
}
public String getResourceID() {
if(resourceID==null && previousRepresentation!=null) {
resourceID = CKANResource.extractResourceID(previousRepresentation);
}
return resourceID;
}
public void setResourceID(String resourceID) {
this.resourceID = resourceID;
}
public void setPreviousRepresentation(JsonNode jsonNode) {
previousRepresentation = jsonNode;
}
public JsonNode getPreviousRepresentation() {
if(previousRepresentation==null && resourceID!=null) {
super.read();
validate(result);
previousRepresentation = result;
}
return previousRepresentation;
}
public CKANResource(String itemID) {
super();
this.itemID = itemID;
CREATE = RESOURCE_CREATE;
READ = RESOURCE_SHOW;
UPDATE = RESOURCE_UPDATE;
PATCH = RESOURCE_PATCH;
DELETE = RESOURCE_DELETE;
PURGE = null;
persisted = null;
previousRepresentation = null;
}
@Override
public String list() {
CKANPackage ckanPackage = new CKANPackage();
ckanPackage.setName(itemID);
String itemJson = ckanPackage.read();
JsonNode item = getAsJsonNode(itemJson);
JsonNode resources = item.get(RESOURCES_KEY);
return getAsString(resources);
}
protected ObjectNode persistStorageFile(ObjectNode objectNode) {
if(objectNode.has(URL_KEY)) {
String urlString = objectNode.get(URL_KEY).asText();
URL url;
try {
url = new URL(urlString);
} catch(MalformedURLException e) {
throw new BadRequestException(e);
}
url = copyStorageResource(url);
if(mimeType!=null) {
objectNode.put(MIME_TYPE_KEY, mimeType);
}
objectNode.put(URL_KEY, url.toString());
return objectNode;
}
String error = String.format("The content must contains the %s property", URL_KEY);
throw new BadRequestException(error);
}
protected ObjectNode validate(String json) throws MalformedURLException {
JsonNode jsonNode = getAsJsonNode(json);
return validate(jsonNode);
}
protected ObjectNode validate(JsonNode jsonNode) {
ObjectNode objectNode = (ObjectNode) jsonNode;
if(objectNode.has(PACKAGE_ID_KEY)) {
String packageId = objectNode.get(PACKAGE_ID_KEY).asText();
if(packageId.compareTo(itemID) != 0) {
String error = String.format(
"Item ID %s does not match %s which is the value of %s contained in the representation.",
itemID, packageId, PACKAGE_ID_KEY);
throw new BadRequestException(error);
}
} else {
objectNode.put(PACKAGE_ID_KEY, itemID);
}
if(objectNode.has(ID_KEY)) {
String gotId = objectNode.get(ID_KEY).asText();
if(resourceID == null) {
resourceID = gotId;
} else {
if(resourceID.compareTo(gotId) != 0) {
String error = String.format(
"Resource ID %s does not match %s which is the value of %s contained in the representation.",
resourceID, gotId, ID_KEY);
throw new BadRequestException(error);
}
}
} else {
resourceID = TEMP + UUID.randomUUID().toString();
logger.trace(
"The id of the resource with name {} for package {} has not been provided. It has been generated : {}",
name, itemID, resourceID);
}
return objectNode;
}
protected URL getFinalURL(String url) {
try {
URL urlURL = new URL(url);
return getFinalURL(urlURL);
} catch(MalformedURLException e) {
throw new BadRequestException(e);
}
}
protected URL getFinalURL(URL url) {
HTTPCall httpCall = new HTTPCall(url.toString());
httpCall.setgCubeTargetService(false);
URL finalURL = httpCall.getFinalURL(url);
return finalURL;
}
protected boolean isStorageFile(URL url) {
if(url.getHost().compareTo(URI_RESOLVER_STORAGE_HUB_HOST) == 0) {
if(url.getPath().startsWith(URI_RESOLVER_STORAGE_HUB_PATH)) {
return true;
}
}
return false;
}
/**
* Check if the URl is a workspace URL so that is has to copy the resource to guarantee
* the resource remain persistent
* @param url the URL to check
* @return the public URL of the copied resource if any. It return the original URL otherwise
*/
protected URL copyStorageResource(URL url) {
persistedURL = getFinalURL(url);
if(isStorageFile(persistedURL)) {
ApplicationMode applicationMode = new ApplicationMode();
applicationMode.start();
storageHubManagement = new StorageHubManagement();
persistedURL = storageHubManagement.ensureResourcePersistence(persistedURL, itemID, resourceID, name);
mimeType = storageHubManagement.getMimeType();
persisted = true;
applicationMode.end();
}
return persistedURL;
}
protected void deleteStorageResource(URL url) {
persistedURL = getFinalURL(url);
if(isStorageFile(persistedURL)) {
ApplicationMode applicationMode = new ApplicationMode();
applicationMode.start();
storageHubManagement = new StorageHubManagement();
storageHubManagement.deleteResourcePersistence(persistedURL, itemID);
applicationMode.end();
}
}
public boolean isPersisted() {
if(persisted == null) {
persistedURL = getFinalURL(persistedURL);
if(isStorageFile(persistedURL)) {
ApplicationMode applicationMode = new ApplicationMode();
applicationMode.start();
storageHubManagement = new StorageHubManagement();
persisted = storageHubManagement.isItemPersistedFile(persistedURL, itemID);
applicationMode.end();
}
}
return persisted;
}
protected String create(JsonNode jsonNode) {
try {
ObjectNode objectNode = validate(jsonNode);
objectNode = persistStorageFile(objectNode);
String ret = super.create(getAsString(objectNode));
String gotResourceID = result.get(ID_KEY).asText();
if(gotResourceID.compareTo(resourceID)!=0) {
resourceID = gotResourceID;
String revisionID = result.get(REVISION_ID_KEY).asText();
storageHubManagement.renameFile(resourceID, revisionID);
}
return ret;
} catch(WebApplicationException e) {
throw e;
} catch(Exception e) {
throw new InternalServerErrorException(e);
}
}
@Override
public String create(String json) {
JsonNode jsonNode = getAsJsonNode(json);
return create(jsonNode);
}
@Override
public String read() {
return sendGetRequest(READ, getMapWithID(resourceID));
}
protected String update(JsonNode jsonNode) {
ObjectNode resourceNode = (ObjectNode) jsonNode;
// This cannot be moved outside otherwise we don't
resourceNode = validate(resourceNode);
getPreviousRepresentation();
String oldURL = previousRepresentation.get(CKANResource.URL_KEY).asText();
String newURL = resourceNode.get(CKANResource.URL_KEY).asText();
if(oldURL.compareTo(newURL)==0) {
logger.trace("The URL of the resource with id {} was not changed", resourceID);
}else {
logger.trace("The URL of resource with id {} has been changed the old URL was {}, the new URL is {}", resourceID, oldURL, newURL);
resourceNode = persistStorageFile(resourceNode);
/*
try {
URL urlOLD = new URL(oldURL);
deleteStorageResource(urlOLD);
}catch (Exception e) {
logger.error("Unable to remove old file at URL {}", oldURL);
}
*/
}
String ret = super.update(getAsString(resourceNode));
String revisionID = result.get(REVISION_ID_KEY).asText();
storageHubManagement.addRevisionID(resourceID, revisionID);
return ret;
}
@Override
public String update(String json) {
JsonNode jsonNode = getAsJsonNode(json);
return update(jsonNode);
}
@Override
public String patch(String json) {
String[] moreAllowed = new String[] {HEAD.class.getSimpleName(), GET.class.getSimpleName(),
PUT.class.getSimpleName(), DELETE.class.getSimpleName()};
throw new NotAllowedException(OPTIONS.class.getSimpleName(), moreAllowed);
}
@Override
public void delete() {
try {
deleteFile();
super.delete();
} catch(WebApplicationException e) {
throw e;
} catch(Exception e) {
throw new WebApplicationException(e);
}
}
@Override
protected void purge() {
String[] moreAllowed = new String[] {HEAD.class.getSimpleName(), GET.class.getSimpleName(),
PUT.class.getSimpleName(), DELETE.class.getSimpleName()};
throw new NotAllowedException(OPTIONS.class.getSimpleName(), moreAllowed);
}
public JsonNode createOrUpdate(JsonNode jsonNode) {
ObjectNode resourceNode = (ObjectNode) jsonNode;
if(resourceNode.has(ID_KEY)) {
update(resourceNode);
}else {
create(resourceNode);
}
return result;
}
public void deleteFile() {
try {
getPreviousRepresentation();
URL url = new URL(previousRepresentation.get(URL_KEY).asText());
deleteStorageResource(url);
} catch(Exception e) {
logger.error("Unable to delete resource {}", previousRepresentation!=null ? getAsString(previousRepresentation) : "");
}
}
public void rollback() {
if(previousRepresentation!=null) {
update(previousRepresentation);
}else {
delete();
}
}
}

@ -0,0 +1,54 @@
package org.gcube.gcat.persistence.ckan;
import org.gcube.gcat.utils.RandomString;
import com.fasterxml.jackson.databind.node.ObjectNode;
/**
* @author Luca Frosini (ISTI - CNR)
*/
public class CKANUser extends CKAN {
/* User Paths */
// see https://docs.ckan.org/en/latest/api/#ckan.logic.action.get.user_list
public static final String USER_LIST = CKAN.CKAN_API_PATH + "user_list";
// see http://docs.ckan.org/en/latest/api/#ckan.logic.action.create.user_create
public static final String USER_CREATE = CKAN.CKAN_API_PATH + "user_create";
// see http://docs.ckan.org/en/latest/api/#ckan.logic.action.get.user_show
public static final String USER_SHOW = CKAN.CKAN_API_PATH + "user_show";
// see http://docs.ckan.org/en/latest/api/#ckan.logic.action.update.user_update
public static final String USER_UPDATE = CKAN.CKAN_API_PATH + "user_update";
// see http://docs.ckan.org/en/latest/api/#ckan.logic.action.delete.user_delete
public static final String USER_DELETE = CKAN.CKAN_API_PATH + "user_delete";
public CKANUser() {
super();
LIST = USER_LIST;
CREATE = USER_CREATE;
READ = USER_SHOW;
UPDATE = USER_UPDATE;
PATCH = null;
DELETE = USER_DELETE;
PURGE = null;
}
public static final String NAME = "name";
public static final String EMAIL = "email";
public static final String PASSWORD = "password";
public String create() {
RandomString randomString = new RandomString(12);
ObjectNode objectNode = mapper.createObjectNode();
objectNode.put(NAME, name);
objectNode.put(EMAIL, name+"@gcube.ckan.org");
objectNode.put(PASSWORD, randomString.nextString());
return create(getAsString(objectNode));
}
@Override
public void delete(boolean purge) {
this.delete();
}
}

@ -0,0 +1,101 @@
package org.gcube.gcat.persistence.ckan;
import javax.ws.rs.InternalServerErrorException;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response.Status;
import org.gcube.datacatalogue.ckanutillibrary.server.DataCatalogue;
import org.gcube.datacatalogue.ckanutillibrary.server.DataCatalogueFactory;
import org.gcube.datacatalogue.ckanutillibrary.server.DataCatalogueRunningCluster;
import org.gcube.datacatalogue.ckanutillibrary.server.utils.CatalogueUtilMethods;
import org.gcube.gcat.utils.ContextUtility;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.databind.JsonNode;
/**
* @author Luca Frosini (ISTI - CNR)
*/
public class CKANUtility {
private static final Logger logger = LoggerFactory.getLogger(CKANUtility.class);
public static final String MEMBER_ROLE = "member";
private static final String API_KEY = "apikey";
public static DataCatalogue getCatalogue() throws Exception {
String context = ContextUtility.getCurrentContext();
logger.debug("Discovering ckan instance in context {}", context);
return DataCatalogueFactory.getFactory().getUtilsPerScope(context);
}
public static String getSysAdminAPI() {
try {
DataCatalogueRunningCluster catalogueRunningInstance = new DataCatalogueRunningCluster(
ContextUtility.getCurrentContext());
return catalogueRunningInstance.getSysAdminToken();
} catch(Exception e) {
throw new InternalServerErrorException(e);
}
}
protected static String getCKANUsername(String username) {
String ckanUsername = CatalogueUtilMethods.fromUsernameToCKanUsername(username);
return ckanUsername;
}
protected static String getCKANUsername() {
return getCKANUsername(ContextUtility.getUsername());
}
public static JsonNode getCKANUser() {
return createCKANUser(getCKANUsername());
}
protected static JsonNode createCKANUser(String ckanUsername) {
CKANUser ckanUser = new CKANUser();
ckanUser.setApiKey(getSysAdminAPI());
try {
ckanUser.setName(ckanUsername);
ckanUser.read();
} catch(WebApplicationException e) {
if(e.getResponse().getStatusInfo() == Status.NOT_FOUND) {
ckanUser.setName(ckanUsername);
ckanUser.create();
}else {
throw e;
}
}
JsonNode jsonNode = ckanUser.getJsonNodeResult();
addUserToOrganization(ckanUsername, MEMBER_ROLE, false);
return jsonNode;
}
protected static void addUserToOrganization(String ckanUsername, String role, boolean force) {
CKANOrganization ckanOrganization = new CKANOrganization();
ckanOrganization.setApiKey(getSysAdminAPI());
String organizationName = CKANOrganization.getCKANOrganizationName();
ckanOrganization.setName(organizationName);
ckanOrganization.addUserToOrganisation(ContextUtility.getUsername(), role, force);
}
public static String getApiKey() throws Exception {
String ckanUsername = getCKANUsername();
return getApiKey(ckanUsername);
}
protected static String getApiKey(String ckanUsername) {
try {
String apiKey = getCatalogue().getApiKeyFromUsername(ckanUsername);
if(apiKey == null) {
JsonNode jsonNode = createCKANUser(ckanUsername);
apiKey = jsonNode.get(API_KEY).asText();
}
return apiKey;
}catch (Exception e) {
throw new InternalServerErrorException(e);
}
}
}

@ -0,0 +1,45 @@
package org.gcube.gcat.rest;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.core.Response.ResponseBuilder;
import org.gcube.common.authorization.library.provider.CalledMethodProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class BaseREST {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Context
private UriInfo uriInfo;
public static final String GROUPS = "groups";
public static final String ITEMS = "items";
public static final String LICENSES = "licenses";
public static final String NAMESPACES = "namespaces";
public static final String ORGANIZATIONS = "organizations";
public static final String PROFILES = "profiles";
public static final String RESOURCES = "resources";
public static final String USERS = "users";
public static final String PURGE_QUERY_PARAMETER = "purge";
public static final String APPLICATION_JSON_CHARSET_UTF_8 = MediaType.APPLICATION_JSON + ";charset=UTF-8";
protected static final String LOCATION_HEADER = "Location";
protected void setCalledMethod(String method) {
CalledMethodProvider.instance.set(method);
logger.info("{}", uriInfo.getAbsolutePath());
}
protected ResponseBuilder addLocation(ResponseBuilder responseBuilder, String id) {
return responseBuilder.header(LOCATION_HEADER,
String.format("%s/%s", uriInfo.getAbsolutePath().toString(), id)
);
}
}

@ -0,0 +1,92 @@
package org.gcube.gcat.rest;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;
import org.gcube.gcat.ResourceInitializer;
import org.gcube.gcat.annotation.PATCH;
import org.gcube.gcat.annotation.PURGE;
import org.gcube.gcat.persistence.ckan.CKANGroup;
/**
* @author Luca Frosini (ISTI - CNR)
*/
@Path(BaseREST.GROUPS)
public class Group extends REST<CKANGroup> {
protected static final String GROUP_ID_PARAMETER = "GROUP_ID";
public Group() {
super(BaseREST.GROUPS, GROUP_ID_PARAMETER, CKANGroup.class);
}
@GET
@Produces(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
@Override
public String list() {
return super.list();
}
@POST
@Consumes(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
@Produces(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
@Override
public Response create(String json) {
return super.create(json);
}
@GET
@Path("/{" + GROUP_ID_PARAMETER + "}")
@Produces(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
@Override
public String read(@PathParam(GROUP_ID_PARAMETER) String id) {
return super.read(id);
}
@PUT
@Path("/{" + GROUP_ID_PARAMETER + "}")
@Consumes(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
@Produces(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
@Override
public String update(@PathParam(GROUP_ID_PARAMETER) String id, String json) {
return super.update(id, json);
}
@PATCH
@Path("/{" + GROUP_ID_PARAMETER + "}")
@Consumes(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
@Produces(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
@Override
public String patch(@PathParam(GROUP_ID_PARAMETER) String id, String json) {
return super.patch(id, json);
}
@DELETE
@Path("/{" + GROUP_ID_PARAMETER + "}")
@Consumes(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
@Produces(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
@Override
public Response delete(@PathParam(GROUP_ID_PARAMETER) String id,
@QueryParam(BaseREST.PURGE_QUERY_PARAMETER) @DefaultValue("false") Boolean purge) {
return super.delete(id, purge);
}
@PURGE
@Path("/{" + GROUP_ID_PARAMETER + "}")
@Consumes(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
@Produces(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
@Override
public Response purge(@PathParam(GROUP_ID_PARAMETER) String id) {
return delete(id, true);
}
}

@ -0,0 +1,93 @@
package org.gcube.gcat.rest;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;
import org.gcube.gcat.ResourceInitializer;
import org.gcube.gcat.annotation.PURGE;
import org.gcube.gcat.persistence.ckan.CKANPackage;
/**
* @author Luca Frosini (ISTI - CNR)
*/
@Path(BaseREST.ITEMS)
public class Item extends REST<CKANPackage> {
public static final String ITEM_ID_PARAMETER = "ITEM_ID";
public Item() {
super(BaseREST.ITEMS, ITEM_ID_PARAMETER, CKANPackage.class);
}
@GET
@Produces(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
@Override
public String list() {
return super.list();
}
@POST
@Consumes(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
@Produces(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
@Override
public Response create(String json) {
return super.create(json);
}
@GET
@Path("/{" + ITEM_ID_PARAMETER + "}")
@Produces(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
@Override
public String read(@PathParam(ITEM_ID_PARAMETER) String id) {
return super.read(id);
}
@PUT
@Path("/{" + ITEM_ID_PARAMETER + "}")
@Consumes(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
@Produces(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
@Override
public String update(@PathParam(ITEM_ID_PARAMETER) String id, String json) {
return super.update(id, json);
}
/*
@PATCH
@Path("/{" + ITEM_ID_PARAMETER + "}")
@Consumes(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
@Produces(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
@Override
public String patch(@PathParam(ITEM_ID_PARAMETER) String id, String json) {
return super.patch(id, json);
}
*/
@DELETE
@Path("/{" + ITEM_ID_PARAMETER + "}")
@Consumes(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
@Produces(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
@Override
public Response delete(@PathParam(ITEM_ID_PARAMETER) String id,
@QueryParam(BaseREST.PURGE_QUERY_PARAMETER) @DefaultValue("false") Boolean purge) {
return super.delete(id, purge);
}
@PURGE
@Path("/{" + ITEM_ID_PARAMETER + "}")
@Consumes(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
@Produces(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
@Override
public Response purge(@PathParam(ITEM_ID_PARAMETER) String id) {
return super.purge(id);
}
}

@ -0,0 +1,27 @@
package org.gcube.gcat.rest;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import org.gcube.gcat.ResourceInitializer;
import org.gcube.gcat.persistence.ckan.CKANLicense;
/**
* @author Luca Frosini (ISTI - CNR)
*/
@Path(BaseREST.LICENSES)
public class License extends REST<CKANLicense> {
public License() {
super(BaseREST.LICENSES, null, CKANLicense.class);
}
@GET
@Produces(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
@Override
public String list() {
return super.list();
}
}

@ -0,0 +1,60 @@
package org.gcube.gcat.rest;
import java.util.List;
import javax.ws.rs.GET;
import javax.ws.rs.InternalServerErrorException;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import org.gcube.datacatalogue.metadatadiscovery.DataCalogueMetadataFormatReader;
import org.gcube.datacatalogue.metadatadiscovery.bean.jaxb.NamespaceCategory;
import org.gcube.gcat.ResourceInitializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
/**
* @author Luca Frosini (ISTI - CNR)
*/
@Path(BaseREST.NAMESPACES)
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
@Produces(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
public String list() {
setCalledMethod("GET /" + BaseREST.NAMESPACES);
ObjectMapper mapper = new ObjectMapper();
ArrayNode arrayNode = mapper.createArrayNode();
try {
List<NamespaceCategory> namespaces = Namespace.getNamespaceCategories();
for(NamespaceCategory namespaceCategory : namespaces) {
ObjectNode namespace = mapper.createObjectNode();
namespace.put("id", namespaceCategory.getId());
namespace.put("title", namespaceCategory.getTitle());
namespace.put("name", namespaceCategory.getNamespaceCategoryQName());
namespace.put("description", namespaceCategory.getDescription());
arrayNode.add(namespace);
}
return mapper.writeValueAsString(arrayNode);
} catch(Exception e) {
throw new InternalServerErrorException(e.getMessage());
}
}
}

@ -0,0 +1,91 @@
package org.gcube.gcat.rest;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;
import org.gcube.gcat.ResourceInitializer;
import org.gcube.gcat.annotation.PATCH;
import org.gcube.gcat.annotation.PURGE;
import org.gcube.gcat.persistence.ckan.CKANOrganization;
/**
* @author Luca Frosini (ISTI - CNR)
*/
@Path(BaseREST.ORGANIZATIONS)
public class Organization extends REST<CKANOrganization> {
public static final String ORGANIZATION_ID_PARAMETER = "ORGANIZATION_ID";
public Organization() {
super(BaseREST.ORGANIZATIONS, ORGANIZATION_ID_PARAMETER, CKANOrganization.class);
}
@GET
@Produces(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
@Override
public String list() {
return super.list();
}
@POST
@Consumes(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
@Produces(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
@Override
public Response create(String json) {
return super.create(json);
}
@GET
@Path("/{" + ORGANIZATION_ID_PARAMETER + "}")
@Produces(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
@Override
public String read(@PathParam(ORGANIZATION_ID_PARAMETER) String id) {
return super.read(id);
}
@PUT
@Path("/{" + ORGANIZATION_ID_PARAMETER + "}")
@Consumes(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
@Produces(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
@Override
public String update(@PathParam(ORGANIZATION_ID_PARAMETER) String id, String json) {
return super.update(id, json);
}
@PATCH
@Path("/{" + ORGANIZATION_ID_PARAMETER + "}")
@Consumes(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
@Produces(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
@Override
public String patch(@PathParam(ORGANIZATION_ID_PARAMETER) String id, String json) {
return super.patch(id, json);
}
@DELETE
@Path("/{" + ORGANIZATION_ID_PARAMETER + "}")
@Consumes(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
@Produces(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
@Override
public Response delete(@PathParam(ORGANIZATION_ID_PARAMETER) String id,
@QueryParam(BaseREST.PURGE_QUERY_PARAMETER) @DefaultValue("false") Boolean purge) {
return super.delete(id, purge);
}
@PURGE
@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) {
return super.purge(id);
}
}

@ -0,0 +1,137 @@
package org.gcube.gcat.rest;
import java.util.ArrayList;
import java.util.List;
import javax.cache.Cache;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.InternalServerErrorException;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.gcube.common.scope.api.ScopeProvider;
import org.gcube.datacatalogue.metadatadiscovery.DataCalogueMetadataFormatReader;
import org.gcube.datacatalogue.metadatadiscovery.bean.MetadataProfile;
import org.gcube.gcat.ResourceInitializer;
import org.gcube.gcat.oldutils.CachesManager;
import org.json.JSONObject;
import org.json.XML;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
/**
* @author Luca Frosini (ISTI - CNR)
*/
@Path(BaseREST.PROFILES)
public class Profile extends BaseREST {
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
@Produces(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
public String list() {
setCalledMethod("GET /" + BaseREST.PROFILES);
ObjectMapper mapper = new ObjectMapper();
ArrayNode arrayNode = mapper.createArrayNode();
try {
List<String> names = getProfilesNames();
for(String name : names) {
arrayNode.add(name);
}
return mapper.writeValueAsString(arrayNode);
} catch(Exception e) {
throw new InternalServerErrorException(e.getMessage());
}
}
public static int PRETTY_PRINT_INDENT_FACTOR = 4;
@GET
@Path("/{" + PROFILE_NAME_PARAMETER + "}")
@Produces({MediaType.APPLICATION_XML, ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8})
public String read(@PathParam(PROFILE_NAME_PARAMETER) String id,
@DefaultValue(MediaType.APPLICATION_JSON) @HeaderParam("Accept") String accept) {
setCalledMethod("GET /" + BaseREST.PROFILES + "/{" + PROFILE_NAME_PARAMETER + "}");
try {
String profile = Profile.getProfileSource(id);
if(accept.startsWith(MediaType.APPLICATION_XML)){
return profile;
}else {
JSONObject xmlJSONObj = XML.toJSONObject(profile);
String jsonString = xmlJSONObj.toString(PRETTY_PRINT_INDENT_FACTOR);
return jsonString;
}
} catch(Exception e) {
throw new InternalServerErrorException(e.getMessage());
}
}
}

@ -0,0 +1,87 @@
package org.gcube.gcat.rest;
import javax.ws.rs.InternalServerErrorException;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.ResponseBuilder;
import javax.ws.rs.core.Response.Status;
import org.gcube.gcat.ResourceInitializer;
import org.gcube.gcat.persistence.ckan.CKAN;
public class REST<C extends CKAN> extends BaseREST {
protected final String COLLECTION_PARAMETER;
protected final String ID_PARAMETER;
protected final Class<C> reference;
public REST(String collection_name, String id_name, Class<C> reference) {
this.COLLECTION_PARAMETER = collection_name;
this.ID_PARAMETER = id_name;
this.reference = reference;
}
protected C getInstance() {
try {
C ckan = reference.newInstance();
return ckan;
} catch(Exception e) {
throw new InternalServerErrorException();
}
}
public String list() {
setCalledMethod("GET /" + COLLECTION_PARAMETER);
C ckan = getInstance();
return ckan.list();
}
public Response create(String json) {
setCalledMethod("POST /" + COLLECTION_PARAMETER);
C ckan = getInstance();
String ret = ckan.create(json);
ResponseBuilder responseBuilder = Response.status(Status.CREATED).entity(ret);
responseBuilder = addLocation(responseBuilder, ckan.getName());
return responseBuilder.type(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8).build();
}
public String read(String id) {
setCalledMethod("GET /" + COLLECTION_PARAMETER + "/{" + ID_PARAMETER + "}");
C ckan = getInstance();
ckan.setName(id);
return ckan.read();
}
public String update(String id, String json) {
setCalledMethod("PUT /" + COLLECTION_PARAMETER + "/{" + ID_PARAMETER + "}");
C ckan = getInstance();
ckan.setName(id);
return ckan.update(json);
}
public String patch(String id, String json) {
setCalledMethod("PATCH /" + COLLECTION_PARAMETER + "/{" + ID_PARAMETER + "}");
C ckan = getInstance();
ckan.setName(id);
return ckan.patch(json);
}
public Response delete(String id, Boolean purge) {
if(purge) {
setCalledMethod("PURGE /" + COLLECTION_PARAMETER + "/{" + ID_PARAMETER + "}");
} else {
setCalledMethod("DELETE /" + COLLECTION_PARAMETER + "/{" + ID_PARAMETER + "}");
}
C ckan = getInstance();
ckan.setName(id);
ckan.delete(purge);
return Response.status(Status.NO_CONTENT).build();
}
public Response purge(String id) {
return delete(id, true);
}
}

@ -0,0 +1,92 @@
package org.gcube.gcat.rest;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import org.gcube.gcat.ResourceInitializer;
import org.gcube.gcat.annotation.PATCH;
import org.gcube.gcat.persistence.ckan.CKANResource;
/**
* @author Luca Frosini (ISTI - CNR)
*/
@Path(BaseREST.ITEMS + "/{" + Resource.ITEM_ID_PARAMETER + "}/" + BaseREST.RESOURCES)
public class Resource extends BaseREST {
protected static final String ITEM_ID_PARAMETER = "ITEM_ID";
protected static final String RESOURCE_ID_PARAMETER = "RESOURCE_ID";
protected static final String COLLECTION = BaseREST.ITEMS + "/{" + Resource.ITEM_ID_PARAMETER + "}/" + BaseREST.RESOURCES;
@GET
@Produces(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
public String list(@PathParam(ITEM_ID_PARAMETER) String itemID) {
setCalledMethod("GET /" + COLLECTION);
CKANResource ckanResource = new CKANResource(itemID);
ckanResource.setName(itemID);
return ckanResource.list();
}
@POST
@Consumes(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
@Produces(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
public String create(@PathParam(ITEM_ID_PARAMETER) String itemID, String json) {
setCalledMethod("POST /" + COLLECTION);
CKANResource ckanResource = new CKANResource(itemID);
return ckanResource.create(json);
}
@GET
@Path("/{" + RESOURCE_ID_PARAMETER + "}")
@Produces(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
public String read(@PathParam(ITEM_ID_PARAMETER) String itemID,
@PathParam(RESOURCE_ID_PARAMETER) String resourceID) {
setCalledMethod("GET /" + COLLECTION + "/{" + RESOURCE_ID_PARAMETER + "}");
CKANResource ckanResource = new CKANResource(itemID);
ckanResource.setName(resourceID);
return ckanResource.read();
}
@PUT
@Path("/{" + RESOURCE_ID_PARAMETER + "}")
@Consumes(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
@Produces(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
public String update(@PathParam(ITEM_ID_PARAMETER) String itemID,
@PathParam(RESOURCE_ID_PARAMETER) String resourceID, String json) {
setCalledMethod("PUT /" + COLLECTION + "/{" + RESOURCE_ID_PARAMETER + "}");
CKANResource ckanResource = new CKANResource(itemID);
ckanResource.setName(resourceID);
return ckanResource.update(json);
}
@PATCH
@Path("/{" + RESOURCE_ID_PARAMETER + "}")
@Consumes(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
@Produces(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
public String patch(@PathParam(ITEM_ID_PARAMETER) String itemID,
@PathParam(RESOURCE_ID_PARAMETER) String resourceID, String json) {
setCalledMethod("PATCH /" + COLLECTION + "/{" + RESOURCE_ID_PARAMETER + "}");
CKANResource ckanResource = new CKANResource(itemID);
ckanResource.setName(resourceID);
return ckanResource.patch(json);
}
@DELETE
@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,
@PathParam(RESOURCE_ID_PARAMETER) String resourceID) {
setCalledMethod("DELETE /" + COLLECTION + "/{" + RESOURCE_ID_PARAMETER + "}");
CKANResource ckanResource = new CKANResource(itemID);
ckanResource.setName(resourceID);
ckanResource.delete(false);
}
}

@ -0,0 +1,32 @@
package org.gcube.gcat.rest;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;
/**
* @author Luca Frosini (ISTI - CNR)
*/
@Provider
public class ScienceCatalogueExceptionMapper implements ExceptionMapper<Exception> {
@Override
public Response toResponse(Exception exception) {
Status status = Status.INTERNAL_SERVER_ERROR;
String exceptionMessage = exception.getMessage();
MediaType mediaType = MediaType.TEXT_PLAIN_TYPE;
if(WebApplicationException.class.isAssignableFrom(exception.getClass())) {
Response gotResponse = ((WebApplicationException) exception).getResponse();
status = Status.fromStatusCode(gotResponse.getStatusInfo().getStatusCode());
}
return Response.status(status).entity(exceptionMessage).type(mediaType).build();
}
}

@ -0,0 +1,69 @@
package org.gcube.gcat.rest;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Response;
import org.gcube.gcat.ResourceInitializer;
import org.gcube.gcat.persistence.ckan.CKANUser;
/**
* @author Luca Frosini (ISTI - CNR)
*/
@Path(BaseREST.USERS)
public class User extends REST<CKANUser> {
protected static final String USER_ID_PARAMETER = "USER_ID";
public User() {
super(BaseREST.USERS, USER_ID_PARAMETER, CKANUser.class);
}
@GET
@Produces(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
@Override
public String list() {
return super.list();
}
@POST
@Consumes(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
@Produces(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
@Override
public Response create(String json) {
return super.create(json);
}
@GET
@Path("/{" + USER_ID_PARAMETER + "}")
@Produces(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
@Override
public String read(@PathParam(USER_ID_PARAMETER) String id) {
return super.read(id);
}
@PUT
@Path("/{" + USER_ID_PARAMETER + "}")
@Consumes(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
@Produces(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
@Override
public String update(@PathParam(USER_ID_PARAMETER) String id, String json) {
return super.update(id, json);
}
@DELETE
@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) {
return super.delete(id, false);
}
}

@ -0,0 +1,74 @@
package org.gcube.gcat.social;
import static org.gcube.resources.discovery.icclient.ICFactory.client;
import static org.gcube.resources.discovery.icclient.ICFactory.queryFor;
import java.util.List;
import org.gcube.common.resources.gcore.GCoreEndpoint;
import org.gcube.gcat.utils.ContextUtility;
import org.gcube.resources.discovery.client.api.DiscoveryClient;
import org.gcube.resources.discovery.client.queries.api.SimpleQuery;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Discover the Social Networking Service in the Infrastructure.
* @author Costantino Perciante (ISTI - CNR)
* @author Luca Frosini (ISTI - CNR)
*/
public class GcoreEndpointReaderSNL {
private static final String RESOURCE = "jersey-servlet";
private static final String SERVICE_NAME = "SocialNetworking";
private static final String SERVICE_CLASSE = "Portal";
private static Logger logger = LoggerFactory.getLogger(GcoreEndpointReaderSNL.class);
private String serviceBasePath;
/**
* Discover the gcore endpoint for the social networking service.
* @throws Exception the exception
*/
public GcoreEndpointReaderSNL() throws Exception {
try {
SimpleQuery query = queryFor(GCoreEndpoint.class);
query.addCondition(String.format("$resource/Profile/ServiceClass/text() eq '%s'", SERVICE_CLASSE));
query.addCondition("$resource/Profile/DeploymentData/Status/text() eq 'ready'");
query.addCondition(String.format("$resource/Profile/ServiceName/text() eq '%s'", SERVICE_NAME));
query.setResult(
"$resource/Profile/AccessPoint/RunningInstanceInterfaces//Endpoint[@EntryName/string() eq \""
+ RESOURCE + "\"]/text()");
DiscoveryClient<String> client = client();
List<String> endpoints = client.submit(query);
if(endpoints == null || endpoints.isEmpty()) {
throw new Exception("Cannot retrieve the GCoreEndpoint SERVICE_NAME: " + SERVICE_NAME
+ ", SERVICE_CLASSE: " + SERVICE_CLASSE + ", in scope: " + ContextUtility.getCurrentContext());
}
this.serviceBasePath = endpoints.get(0);
if(serviceBasePath == null)
throw new Exception("Endpoint:" + RESOURCE + ", is null for SERVICE_NAME: " + SERVICE_NAME
+ ", SERVICE_CLASSE: " + SERVICE_CLASSE + ", in scope: " + ContextUtility.getCurrentContext());
serviceBasePath = serviceBasePath.endsWith("/") ? serviceBasePath : serviceBasePath + "/";
} catch(Exception e) {
String error = "An error occurred during GCoreEndpoint discovery, SERVICE_NAME: " + SERVICE_NAME
+ ", SERVICE_CLASSE: " + SERVICE_CLASSE + ", in scope: " + ContextUtility.getCurrentContext() + ".";
logger.error(error, e);
throw new Exception(error);
}
}
/**
* @return the base path of the service
*/
public String getServiceBasePath() {
return serviceBasePath;
}
}

@ -0,0 +1,197 @@
package org.gcube.gcat.social;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.cache.Cache;
import javax.ws.rs.core.MediaType;
import org.gcube.datacatalogue.ckanutillibrary.server.DataCatalogue;
import org.gcube.gcat.oldutils.CachesManager;
import org.gcube.gcat.persistence.ckan.CKAN;
import org.gcube.gcat.utils.ApplicationMode;
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.LoggerFactory;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
/**
* @author Luca Frosini (ISTI - CNR)
*/
public class SocialService extends Thread {
private static final Logger logger = LoggerFactory.getLogger(SocialService.class);
public static final String ITEM_URL = "Item URL";
// https://wiki.gcube-system.org/gcube/Social_Networking_Service#Write_application_post_2
protected static final String SOCIAL_SERVICE_WRITE_APPLICATION_POST_PATH = "/2/posts/write-post-app";
// https://wiki.gcube-system.org/gcube/Social_Networking_Service
protected static final String SOCIAL_SERVICE_GET_USER_INFO_PATH = "2/users/get-profile";
// String.format(NOTIFICATION_MESSAGE, title, fullName, url)
protected static final String NOTIFICATION_MESSAGE = "Dear members,<br>The item '%s' has been just published by %s.<br>You can find it at: %s <br>";
protected static final String RESULT_KEY = "result";
protected static final String FULLNAME_IN_PROFILE_KEY = "fullname";
protected static final String SOCIAL_POST_TEXT_KEY = "text";
protected static final String SOCIAL_POST_ENABLE_NOTIFICATION_KEY = "enable_notification";
protected static final String SOCIAL_POST_RESPONSE_SUCCESS_KEY = "success";
protected static final String SOCIAL_POST_RESPONSE_MESSAGE_KEY = "message";
protected String id;
protected String url;
protected String title;
protected List<String> tags;
protected final GcoreEndpointReaderSNL socialService;
protected final ObjectMapper objectMapper;
public SocialService() throws Exception {
super();
this.socialService = new GcoreEndpointReaderSNL();
this.objectMapper = new ObjectMapper();
}
public SocialService(String id, String url, List<String> tags, String title) throws Exception {
this();
this.id = id;
this.url = url;
this.tags = tags;
this.title = title;
}
public SocialService(String id, String url, ArrayNode arrayNode, String title) throws Exception {
this();
this.id = id;
this.url = url;
this.tags = new ArrayList<>();
if(arrayNode != null && arrayNode.size() > 0) {
for(int i = 0; i < arrayNode.size(); i++) {
String tagName = arrayNode.get(i).get("display_name").asText();
tags.add(tagName);
}
}
this.title = title;
}
/**
* Execute the GET http request at this url, and return the result as string
* @return
* @throws Exception
*/
public JsonNode getGCubeUserProfile() throws Exception {
String username = ContextUtility.getUsername();
return getGCubeUserProfile(username);
}
public JsonNode getGCubeUserProfile(String username) throws Exception {
Cache<String,JsonNode> userCache = CachesManager.getUserCache();
if(userCache.containsKey(username))
return userCache.get(username);
else {
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,
MediaType.APPLICATION_JSON);
JsonNode jsonNode = objectMapper.readTree(response);
userCache.put(username, jsonNode);
return jsonNode;
}
}
public String getFullName() throws Exception {
if(!ContextUtility.isApplication()) {
JsonNode jsonNode = getGCubeUserProfile();
JsonNode result = jsonNode.get(RESULT_KEY);
return result.get(FULLNAME_IN_PROFILE_KEY).asText();
} else {
return ContextUtility.getUsername();
}
}
@Override
public void run() {
try {
DataCatalogue dataCatalogue = CKAN.getCatalogue();
if(!dataCatalogue.isSocialPostEnabled()) {
logger.info("Social Post are disabled in the context {}", ContextUtility.getCurrentContext());
return;
}
logger.info("Going to send Social Post about the Item {} available at {}", id, url);
boolean notifyUsers = dataCatalogue.isNotificationToUsersEnabled();
// write notification post
sendSocialPost(notifyUsers);
} catch(Exception e) {
logger.error("Error while executing post creation actions", e);
}
}
public void sendSocialPost(boolean notifyUsers) {
try {
String fullName = getFullName();
String basePath = socialService.getServiceBasePath();
if(basePath == null) {
logger.info("Unable to write a post because there is no social networking service available");
return;
}
basePath = basePath.endsWith("/") ? basePath : basePath + "/";
StringWriter messageWriter = new StringWriter();
messageWriter.append(String.format(NOTIFICATION_MESSAGE, title, fullName, url));
for(String tag : tags) {
tag = tag.trim();
tag = tag.replaceAll(" ", "_").replace("_+", "_");
if(tag.endsWith("_")) {
tag = tag.substring(0, tag.length() - 1);
}
messageWriter.append(" #");
messageWriter.append(tag);
}
String message = messageWriter.toString();
logger.debug("The post that is going to be written is {} " + message);
ObjectNode objectNode = objectMapper.createObjectNode();
objectNode.put(SOCIAL_POST_TEXT_KEY, message);
objectNode.put(SOCIAL_POST_ENABLE_NOTIFICATION_KEY, notifyUsers);
// Do not use ApplicationMode class here because is a thread and change the current token could impact
// 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);
if(jsonNode.get(SOCIAL_POST_RESPONSE_SUCCESS_KEY).asBoolean()) {
logger.info("Post written : {}", message);
} else {
logger.info("Failed to write the post {}. Reason {}", message,
jsonNode.get(SOCIAL_POST_RESPONSE_MESSAGE_KEY).asText());
}
} catch(Exception e) {
logger.error("Unable to send Social Post", e);
}
}
}

@ -0,0 +1,92 @@
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.");
}
}
}

@ -0,0 +1,10 @@
package org.gcube.gcat.utils;
/**
* @author Luca Frosini (ISTI - CNR)
*/
public class Constants {
public static final String CATALOGUE_NAME = "ScienceCatalogue";
}

@ -0,0 +1,83 @@
package org.gcube.gcat.utils;
import javax.ws.rs.InternalServerErrorException;
import org.gcube.common.authorization.client.Constants;
import org.gcube.common.authorization.client.exceptions.ObjectNotFound;
import org.gcube.common.authorization.library.AuthorizationEntry;
import org.gcube.common.authorization.library.ClientType;
import org.gcube.common.authorization.library.provider.AuthorizationProvider;
import org.gcube.common.authorization.library.provider.ClientInfo;
import org.gcube.common.authorization.library.provider.SecurityTokenProvider;
import org.gcube.common.authorization.library.utils.Caller;
import org.gcube.common.scope.api.ScopeProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author Luca Frosini (ISTI - CNR)
*/
public class ContextUtility {
private static Logger logger = LoggerFactory.getLogger(ContextUtility.class);
public static void setContext(String token) throws ObjectNotFound, Exception{
SecurityTokenProvider.instance.set(token);
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);
ScopeProvider.instance.set(getCurrentContext());
}
public static String getCurrentContext() {
try {
String token = SecurityTokenProvider.instance.get();
return Constants.authorizationService().get(token).getContext();
}catch (Exception e) {
String context = ScopeProvider.instance.get();
if(context!=null) {
return context;
}
throw new InternalServerErrorException(e);
}
}
public static ClientInfo getClientInfo() {
try {
Caller caller = AuthorizationProvider.instance.get();
if(caller!=null){
return caller.getClient();
}else{
String token = SecurityTokenProvider.instance.get();
AuthorizationEntry authorizationEntry = Constants.authorizationService().get(token);
return authorizationEntry.getClientInfo();
}
}catch (Exception e) {
throw new InternalServerErrorException(e);
}
}
private static final String GET_USERNAME_ERROR = "Unable to retrieve user";
public static String getUsername() {
try {
return getClientInfo().getId();
} catch (Exception e) {
logger.error(GET_USERNAME_ERROR);
throw new InternalServerErrorException(GET_USERNAME_ERROR, e);
}
}
public static boolean isApplication() {
try {
ClientInfo clientInfo = getClientInfo();
return clientInfo.getType() == ClientType.EXTERNALSERVICE ;
}catch (Exception e) {
throw new InternalServerErrorException(e);
}
}
}

@ -0,0 +1,313 @@
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.MalformedURLException;
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.WebApplicationException;
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 {
private static final Logger logger = LoggerFactory.getLogger(HTTPCall.class);
protected static final String USER_AGENT_KEY = "User-Agent";
protected static final String USER_AGENT_NAME = Constants.CATALOGUE_NAME;
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 userAgent;
protected Map<String,String> headers;
/**
* When the target service is a gCube Service it adds the HTTP header
* to provide gCube authorization token and/or scope
*/
protected boolean gCubeTargetService;
public boolean isgCubeTargetService() {
return gCubeTargetService;
}
public void setgCubeTargetService(boolean gCubeTargetService) {
this.gCubeTargetService = gCubeTargetService;
}
public HTTPCall(String address) {
this(address, HTTPCall.USER_AGENT_NAME);
}
protected HTTPCall(String address, String userAgent) {
this.address = address;
this.userAgent = userAgent;
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 {
URL url = new URL(urlString);
if(url.getProtocol().compareTo("https") == 0) {
url = new URL(url.getProtocol(), url.getHost(), url.getDefaultPort(), url.getFile());
}
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) {
try {
URL finalURL = url;
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setInstanceFollowRedirects(false);
int responseCode = connection.getResponseCode();
String responseMessage = connection.getResponseMessage();
if(responseCode >= Status.BAD_REQUEST.getStatusCode()) {
Status status = Status.fromStatusCode(responseCode);
throw new WebApplicationException(responseMessage, status);
}
if(responseCode == HttpURLConnection.HTTP_MOVED_TEMP || responseCode == HttpURLConnection.HTTP_MOVED_PERM
|| responseCode == HttpURLConnection.HTTP_SEE_OTHER
|| responseCode == Status.TEMPORARY_REDIRECT.getStatusCode() || responseCode == 308) {
finalURL = getURL(connection.getHeaderField("Location"));
finalURL = getFinalURL(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) {
throw e;
} catch(Exception e) {
throw new InternalServerErrorException(e);
}
}
}

@ -0,0 +1,36 @@
package org.gcube.gcat.utils;
import java.util.Random;
/**
* @author Lucio Lelii (ISTI - CNR)
*/
public class RandomString {
private static final char[] symbols;
static {
StringBuilder tmp = new StringBuilder();
for (char ch = '0'; ch <= '9'; ++ch)
tmp.append(ch);
for (char ch = 'a'; ch <= 'z'; ++ch)
tmp.append(ch);
symbols = tmp.toString().toCharArray();
}
private final Random random = new Random();
private final char[] buf;
public RandomString(int length) {
if (length < 1)
throw new IllegalArgumentException("length < 1: " + length);
buf = new char[length];
}
public String nextString() {
for (int idx = 0; idx < buf.length; ++idx)
buf[idx] = symbols[random.nextInt(symbols.length)];
return new String(buf);
}
}

@ -0,0 +1,49 @@
package org.gcube.gcat.utils;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import org.gcube.datacatalogue.ckanutillibrary.server.DataCatalogue;
import org.gcube.datacatalogue.ckanutillibrary.server.utils.url.EntityContext;
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.node.ObjectNode;
public class URIResolver {
private static final String CATALOGUE_CONTEXT = "gcube_scope";
private static final String ENTITY_TYPE = "entity_context";
private static final String ENTITY_NAME = "entity_name";
private static final String CATALOGUE_PLAIN_URL = "clear_url";
protected ObjectMapper objectMapper;
public URIResolver() {
this.objectMapper = new ObjectMapper();
}
public String getCatalogueItemURL(String name) {
try {
DataCatalogue dataCatalogue = CKAN.getCatalogue();
String uriResolverURL = dataCatalogue.getUriResolverUrl();
HTTPCall httpCall = new HTTPCall(uriResolverURL);
ObjectNode requestContent = objectMapper.createObjectNode();
requestContent.put(CATALOGUE_CONTEXT, ContextUtility.getCurrentContext());
requestContent.put(ENTITY_TYPE, EntityContext.PRODUCT.toString());
requestContent.put(ENTITY_NAME, name);
requestContent.put(CATALOGUE_PLAIN_URL, true);
String url = httpCall.call("", HTTPMETHOD.POST, objectMapper.writeValueAsString(requestContent),
MediaType.APPLICATION_JSON);
return url;
} catch(Exception e) {
throw new WebApplicationException(e);
}
}
}

@ -0,0 +1,295 @@
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);
}
}

@ -0,0 +1,316 @@
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 Licensees 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

@ -0,0 +1,76 @@
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 (2018-12-04)
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.

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xml>
<ReleaseNotes>
<Changeset component="org.gcube.data-catalogue.catalogue-ws.1-4-0" date="2018-12-04">
<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>

@ -0,0 +1,31 @@
<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>

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xml>
<application mode='online'>
<name>gcat</name>
<group>DataCatalogue</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>

@ -0,0 +1,27 @@
<?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>DataCatalogue</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>

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xml>
<web-app>
<servlet>
<servlet-name>org.gcube.datacatalogue.sciencecatalogue.ResourceInitializer</servlet-name>
</servlet>
<servlet-mapping>
<servlet-name>org.gcube.datacatalogue.sciencecatalogue.ResourceInitializer</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>

@ -0,0 +1,122 @@
/**
*
*/
package org.gcube.gcat;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import org.gcube.common.authorization.client.Constants;
import org.gcube.common.authorization.client.exceptions.ObjectNotFound;
import org.gcube.common.authorization.library.AuthorizationEntry;
import org.gcube.common.authorization.library.provider.AuthorizationProvider;
import org.gcube.common.authorization.library.provider.ClientInfo;
import org.gcube.common.authorization.library.provider.SecurityTokenProvider;
import org.gcube.common.authorization.library.utils.Caller;
import org.gcube.common.scope.api.ScopeProvider;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author Luca Frosini (ISTI - CNR)
*
*/
public class ContextTest {
private static final Logger logger = LoggerFactory.getLogger(ContextTest.class);
protected static final String PROPERTIES_FILENAME = "token.properties";
private static final String GCUBE_VARNAME = "GCUBE";
public static final String GCUBE;
private static final String GCUBE_DEVNEXT_VARNAME = "GCUBE_DEVNEXT";
public static final String GCUBE_DEVNEXT;
private static final String GCUBE_DEVNEXT_NEXTNEXT_VARNAME = "GCUBE_DEVNEXT_NEXTNEXT";
public static final String GCUBE_DEVNEXT_NEXTNEXT;
public static final String GCUBE_DEVSEC_VARNAME = "GCUBE_DEVSEC";
public static final String GCUBE_DEVSEC;
public static final String GCUBE_DEVSEC_DEVVRE_VARNAME = "GCUBE_DEVSEC_DEVVRE";
public static final String GCUBE_DEVSEC_DEVVRE;
private static final String GCUBE_DEVNEXT_ANOTHER_USER_VARNAME = "GCUBE_DEVNEXT_ANOTHER_USER";
public static final String GCUBE_DEVNEXT_ANOTHER_USER;
public static final String DEFAULT_TEST_SCOPE;
public static final String GCUBE_PRE_PROD_PREVRE_VARNAME = "GCUBE_PRE_PROD_PREVRE";
public static final String GCUBE_PRE_PROD_PREVRE;
public static final String GCUBE_PRE_PROD_PARTHENOS_REGISTRY_VARNAME = "GCUBE_PRE_PROD_PARTHENOS_REGISTRY";
public static final String GCUBE_PRE_PROD_PARTHENOS_REGISTRY;
public static final String ROOT_VARNAME = "ROOT";
public static final String ROOT;
static {
Properties properties = new Properties();
InputStream input = ContextTest.class.getClassLoader().getResourceAsStream(PROPERTIES_FILENAME);
try {
// load the properties file
properties.load(input);
} catch (IOException e) {
throw new RuntimeException(e);
}
GCUBE = properties.getProperty(GCUBE_VARNAME);
GCUBE_DEVNEXT = properties.getProperty(GCUBE_DEVNEXT_VARNAME);
GCUBE_DEVNEXT_NEXTNEXT = properties.getProperty(GCUBE_DEVNEXT_NEXTNEXT_VARNAME);
GCUBE_DEVSEC = properties.getProperty(GCUBE_DEVSEC_VARNAME);
GCUBE_DEVSEC_DEVVRE = properties.getProperty(GCUBE_DEVSEC_DEVVRE_VARNAME);
GCUBE_DEVNEXT_ANOTHER_USER = properties.getProperty(GCUBE_DEVNEXT_ANOTHER_USER_VARNAME);
GCUBE_PRE_PROD_PARTHENOS_REGISTRY = properties.getProperty(GCUBE_PRE_PROD_PARTHENOS_REGISTRY_VARNAME);
GCUBE_PRE_PROD_PREVRE = properties.getProperty(GCUBE_PRE_PROD_PREVRE_VARNAME);
ROOT = properties.getProperty(ROOT_VARNAME);
DEFAULT_TEST_SCOPE = GCUBE_PRE_PROD_PREVRE;
}
public static String getCurrentScope(String token) throws ObjectNotFound, Exception{
AuthorizationEntry authorizationEntry = Constants.authorizationService().get(token);
String context = authorizationEntry.getContext();
logger.info("Context of token {} is {}", token, context);
return context;
}
public static void setContext(String token) throws ObjectNotFound, Exception{
SecurityTokenProvider.instance.set(token);
AuthorizationEntry authorizationEntry = Constants.authorizationService().get(token);
ClientInfo clientInfo = authorizationEntry.getClientInfo();
logger.debug("User : {} - Type : {}", clientInfo.getId(), clientInfo.getType().name());
String qualifier = authorizationEntry.getQualifier();
Caller caller = new Caller(clientInfo, qualifier);
AuthorizationProvider.instance.set(caller);
ScopeProvider.instance.set(getCurrentScope(token));
}
@BeforeClass
public static void beforeClass() throws Exception{
setContext(DEFAULT_TEST_SCOPE);
}
@AfterClass
public static void afterClass() throws Exception{
SecurityTokenProvider.instance.reset();
ScopeProvider.instance.reset();
}
}

@ -0,0 +1,28 @@
package org.gcube.gcat.persistence.ckan;
import org.gcube.gcat.ContextTest;
import org.gcube.gcat.persistence.ckan.CKANLicense;
import org.junit.Assert;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
public class CKANLicenseTest extends ContextTest {
private static Logger logger = LoggerFactory.getLogger(CKANLicenseTest.class);
@Test
public void list() throws Exception {
CKANLicense license = new CKANLicense();
String ret = license.list();
ObjectMapper mapper = new ObjectMapper();
JsonNode gotList = mapper.readTree(ret);
Assert.assertTrue(gotList instanceof ArrayNode);
logger.debug("List :\n{}", mapper.writeValueAsString(gotList));
}
}

@ -0,0 +1,23 @@
package org.gcube.gcat.persistence.ckan;
import org.gcube.gcat.ContextTest;
import org.gcube.gcat.persistence.ckan.CKANOrganization;
import org.gcube.gcat.persistence.ckan.CKANUtility;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class CKANOrganizationTest extends ContextTest {
private static Logger logger = LoggerFactory.getLogger(CKANOrganizationTest.class);
@Test
public void getUserRole() throws Exception {
CKANOrganization ckanOrganization = new CKANOrganization();
ckanOrganization.setApiKey(CKANUtility.getSysAdminAPI());
ckanOrganization.setName(CKANOrganization.getCKANOrganizationName());
String ret = ckanOrganization.getUserRole("luca.frosini");
logger.debug("{}", ret);
}
}

@ -0,0 +1,185 @@
package org.gcube.gcat.persistence.ckan;
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.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
/**
* @author Luca Frosini (ISTI - CNR)
*/
public class CKANPackageTest extends ContextTest {
private static Logger logger = LoggerFactory.getLogger(CKANPackageTest.class);
private static final String NOTES_KEY = "notes";
private static final String URL_KEY = "url";
private static final String PRIVATE_KEY = "private";
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 EXTRAS_TYPE_VALUE_VALUE = "EmptyType";
@Test
public void list() throws Exception {
CKANPackage ckanPackage = new CKANPackage();
ObjectMapper mapper = new ObjectMapper();
String ret = ckanPackage.list();
JsonNode gotList = mapper.readTree(ret);
Assert.assertTrue(gotList instanceof ArrayNode);
logger.debug("List :\n{}", mapper.writeValueAsString(gotList));
}
/*
* DEV
* Workspace(luca.frosini) > RESTful Transaction Model.pdf
* https://data-d.d4science.org/shub/e03355cd-058a-4e3a-8d5b-cf3676a46840
* URL url = new URL("https://goo.gl/fSZH1o");
*
*
* Workspace(luca.frosini) > RESTful Transaction Model v 1.0.pdf
* https://data-d.d4science.org/shub/8ad187c4-8f94-4c47-a780-706d0d33c1bb
* URL url = new URL("https://goo.gl/6vZSmp");
*
*
* Workspace(luca.frosini) > RESTful Transaction Model v 1.1.pdf
* https://data-d.d4science.org/shub/7b6628e4-b397-4df9-b387-2d643ae0095c
* URL url = new URL("https://goo.gl/jvXMcd");
*
*/
protected CKANPackage createPackage(ObjectMapper mapper) throws Exception {
ObjectNode itemObjectNode = mapper.createObjectNode();
itemObjectNode.put(CKAN.NAME_KEY, ITEM_NAME_VALUE);
itemObjectNode.put(CKANPackage.TITLE_KEY, "RESTful Transaction Model");
itemObjectNode.put(CKANPackage.LICENSE_KEY, LICENSE_VALUE);
itemObjectNode.put(PRIVATE_KEY, false);
itemObjectNode.put(NOTES_KEY, "A research of Luca Frosini");
itemObjectNode.put(URL_KEY, "http://www.d4science.org");
ArrayNode tagArrayNode = itemObjectNode.putArray(CKANPackage.TAGS_KEY);
ObjectNode tagNode = mapper.createObjectNode();
tagNode.put(CKANPackage.NAME_KEY, "REST");
tagArrayNode.add(tagNode);
ArrayNode resourceArrayNode = itemObjectNode.putArray(CKANPackage.RESOURCES_KEY);
ObjectNode resourceNode = mapper.createObjectNode();
resourceNode.put(CKANResource.NAME_KEY, "RESTful Transaction Model");
// Workspace(luca.frosini) > RESTful Transaction Model v 1.0.pdf
resourceNode.put(CKANResource.URL_KEY, "https://goo.gl/6vZSmp");
resourceArrayNode.add(resourceNode);
ArrayNode extraArrayNode = itemObjectNode.putArray(CKANPackage.EXTRA_TYPES_KEY);
ObjectNode extraNode = mapper.createObjectNode();
extraNode.put(CKANPackage.EXTRA_TYPES_KEY_KEY, CKANPackage.EXTRA_TYPES_KEY_VALUE_SYSTEM_TYPE);
extraNode.put(CKANPackage.EXTRA_TYPES_VALUE_KEY, EXTRAS_TYPE_VALUE_VALUE);
extraArrayNode.add(extraNode);
CKANPackage ckanPackage = new CKANPackage();
ckanPackage.setName(ITEM_NAME_VALUE);
//ckanPackage.setApiKey(CKANUtility.getSysAdminAPI());
String createdItem = ckanPackage.create(mapper.writeValueAsString(itemObjectNode));
logger.debug(createdItem);
return ckanPackage;
}
@Test
public void create() throws Exception {
ObjectMapper mapper = new ObjectMapper();
createPackage(mapper);
}
@Test
public void createReadUpdateUpdatePurge() throws Exception {
ObjectMapper mapper = new ObjectMapper();
createPackage(mapper);
CKANPackage ckanPackage = new CKANPackage();
ckanPackage.setName(ITEM_NAME_VALUE);
String readItem = ckanPackage.read();
JsonNode readItemObjectNode = mapper.readTree(readItem);
String readID = readItemObjectNode.get(CKANPackage.NAME_KEY).asText();
Assert.assertNotNull(readID);
Assert.assertTrue(ITEM_NAME_VALUE.compareTo(readID)==0);
String updatedNotes = "A research of Luca Frosini made during the PhD";
((ObjectNode) readItemObjectNode).put(NOTES_KEY, updatedNotes);
ArrayNode resources = (ArrayNode) readItemObjectNode.get(CKANPackage.RESOURCES_KEY);
ObjectNode objectNode = (ObjectNode) resources.get(0);
// Workspace(luca.frosini) > RESTful Transaction Model v 1.1.pdf
objectNode.put(CKANResource.URL_KEY, "https://goo.gl/jvXMcd");
resources.set(0, objectNode);
((ObjectNode) readItemObjectNode).replace(CKANPackage.RESOURCES_KEY, resources);
ckanPackage = new CKANPackage();
ckanPackage.setName(ITEM_NAME_VALUE);
String updatedItem = ckanPackage.update(mapper.writeValueAsString(readItemObjectNode));
logger.trace(updatedItem);
JsonNode updatedItemObjectNode = mapper.readTree(updatedItem);
String gotUpdatedNotes = updatedItemObjectNode.get(NOTES_KEY).asText();
Assert.assertTrue(gotUpdatedNotes.compareTo(updatedNotes)==0);
ckanPackage = new CKANPackage();
ckanPackage.setName(ITEM_NAME_VALUE);
((ObjectNode) updatedItemObjectNode).remove(CKANPackage.RESOURCES_KEY);
String secondUpdateItem = ckanPackage.update(mapper.writeValueAsString(updatedItemObjectNode));
logger.trace(secondUpdateItem);
/*
ObjectNode patchObjectNode = mapper.createObjectNode();
String patchedNotes = updatedNotes + " in October 2018";
patchObjectNode.put(NOTES_KEY, patchedNotes);
patchObjectNode.put(CKANPackage.NAME_KEY, ITEM_NAME_VALUE);
ckanPackage = new CKANPackage();
ckanPackage.setName(ITEM_NAME_VALUE);
String patchedItem = ckanPackage.patch(mapper.writeValueAsString(patchObjectNode));
logger.trace(patchedItem);
JsonNode patchedItemObjectNode = mapper.readTree(patchedItem);
String gotPatchedNotes = patchedItemObjectNode.get(NOTES_KEY).asText();
Assert.assertTrue(gotPatchedNotes.compareTo(patchedNotes)==0);
*/
ckanPackage = new CKANPackage();
ckanPackage.setName(ITEM_NAME_VALUE);
ckanPackage.purge();
logger.debug("Item {} purge successfully", ITEM_NAME_VALUE);
}
@Test
//(expected = NotFoundException.class)
public void read() throws Exception {
CKANPackage ckanPackage = new CKANPackage();
ckanPackage.setName(ITEM_NAME_VALUE);
String ret = ckanPackage.read();
logger.debug(ret);
}
@Test
//(expected = NotFoundException.class)
public void delete() throws Exception {
CKANPackage ckanPackage = new CKANPackage();
ckanPackage.setName(ITEM_NAME_VALUE);
ckanPackage.delete(true);
}
}

@ -0,0 +1,70 @@
package org.gcube.gcat.persistence.ckan;
import java.net.URL;
import java.util.UUID;
import org.gcube.gcat.ContextTest;
import org.gcube.gcat.persistence.ckan.CKANResource;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
public class CKANResourceTest extends ContextTest {
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
* Workspace(luca.frosini) > RESTful Transaction Model.pdf
* https://data-d.d4science.org/shub/e03355cd-058a-4e3a-8d5b-cf3676a46840
* URL url = new URL("https://goo.gl/fSZH1o");
*
*
* Workspace(luca.frosini) > RESTful Transaction Model v 1.0.pdf
* https://data-d.d4science.org/shub/5df695ea-986a-437d-abaf-ed1542a7f5af
* URL url = new URL("https://goo.gl/7ofQwn");
*
*
* Workspace(luca.frosini) > RESTful Transaction Model v 1.1.pdf
* https://data-d.d4science.org/shub/7b6628e4-b397-4df9-b387-2d643ae0095c
* URL url = new URL("https://goo.gl/jvXMcd");
*
*/
@Test
public void testCopyStorageResource() throws Exception {
URL url = new URL("https://goo.gl/fSZH1o");
String itemID = UUID.randomUUID().toString();
CKANResource ckanResource = new CKANResource(itemID);
ckanResource.resourceID = UUID.randomUUID().toString();
URL finalURL = ckanResource.copyStorageResource(url);
logger.debug("Initial URL is {} - Final URL is {}", url, finalURL);
ckanResource.deleteStorageResource(finalURL);
}
// @Test
public void testCreate() throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
ObjectNode objectNode = objectMapper.createObjectNode();
objectNode.put(CKANResource.URL_KEY, "https://data.d4science.org/shub/ab4daec8-2ce4-43d7-9d37-00b2051e3530");
objectNode.put(CKANResource.ID_KEY, "8422b5d4-626b-46f2-9121-bbc6d443071d");
CKANResource ckanResource = new CKANResource("f9221556-4b1f-49f2-8951-a4c30d71cd37");
String json = ckanResource.getAsString(objectNode);
logger.debug("Going to create Resource {}", json);
ckanResource.create(json);
}
}

@ -0,0 +1,69 @@
package org.gcube.gcat.persistence.ckan;
import org.gcube.gcat.ContextTest;
import org.gcube.gcat.persistence.ckan.CKANUser;
import org.gcube.gcat.persistence.ckan.CKANUtility;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
public class CKANUserTest extends ContextTest {
private static Logger logger = LoggerFactory.getLogger(CKANUserTest.class);
private static final String USERNAME = "pippo";
private CKANUser getCKANUser() {
CKANUser user = new CKANUser();
user.setApiKey(CKANUtility.getSysAdminAPI());
user.setName(USERNAME);
return user;
}
@Test
public void list() throws Exception {
CKANUser ckanUser = getCKANUser();
String ret = ckanUser.list();
logger.debug("{}", ret);
}
@Test
public void create() throws Exception {
CKANUser ckanUser = getCKANUser();
String ret = ckanUser.create();
logger.debug("{}", ret);
}
@Test
public void read() throws Exception {
CKANUser ckanUser = getCKANUser();
String ret = ckanUser.read();
logger.debug("{}", ret);
}
public final static String DISPLAY_NAME = "display_name";
@Test
public void update() throws Exception {
CKANUser ckanUser = getCKANUser();
String ret = ckanUser.read();
ObjectMapper mapper = new ObjectMapper();
JsonNode readUser = mapper.readTree(ret);
((ObjectNode) readUser).put(CKANUser.EMAIL, USERNAME+"@gcube.ckan.org");
((ObjectNode) readUser).put("state", "active");
ret = ckanUser.update(ckanUser.getAsString(readUser));
logger.debug("{}", ret);
}
@Test
public void delete() throws Exception {
CKANUser ckanUser = getCKANUser();
ckanUser.delete(false);
}
}

@ -0,0 +1,37 @@
package org.gcube.gcat.persistence.ckan;
import org.gcube.gcat.ContextTest;
import org.gcube.gcat.persistence.ckan.CKANUtility;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author Luca Frosini (ISTI - CNR)
*/
public class CKANUtilityTest extends ContextTest {
private static Logger logger = LoggerFactory.getLogger(CKANPackageTest.class);
private static final String USERNAME = "luca_frosini";
@Test
public void testGetApiKey() throws Exception {
String ckanAPI = CKANUtility.getApiKey(USERNAME);
logger.debug("User {} has the following API key {}", USERNAME, ckanAPI);
}
@Test
public void testAddUserToOrganization() throws Exception {
CKANUtility.addUserToOrganization(USERNAME, CKANUtility.MEMBER_ROLE, true);
}
@Test
public void testAddSpecialUserToOrganization() throws Exception {
CKANUtility.addUserToOrganization("luca_frosini", "editor", true);
}
}

@ -0,0 +1,20 @@
package org.gcube.gcat.rest;
import org.gcube.gcat.ContextTest;
import org.gcube.gcat.rest.Namespace;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class NamespaceTest extends ContextTest {
private static Logger logger = LoggerFactory.getLogger(NamespaceTest.class);
@Test
public void list() throws Exception {
Namespace namespace = new Namespace();
String ret = namespace.list();
logger.debug("{}", ret);
}
}

@ -0,0 +1,56 @@
package org.gcube.gcat.rest;
import java.util.Iterator;
import javax.ws.rs.core.MediaType;
import org.gcube.gcat.ContextTest;
import org.gcube.gcat.rest.Profile;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
public class ProfileTest extends ContextTest {
private static Logger logger = LoggerFactory.getLogger(ProfileTest.class);
@Test
public void list() throws Exception {
Profile profile = new Profile();
String ret = profile.list();
logger.debug("{}", ret);
}
@Test
public void read() throws Exception {
String profileID = "SoBigData.eu: Dataset Metadata NextNext";
Profile profile = new Profile();
String ret = profile.read(profileID, MediaType.APPLICATION_XML);
logger.debug("XML :\n{}", ret);
ret = profile.read(profileID, MediaType.APPLICATION_JSON);
logger.debug("JSON : \n{}", ret);
}
@Test
public void listRead() throws Exception {
Profile profile = new Profile();
String ret = profile.list();
ObjectMapper mapper = new ObjectMapper();
ArrayNode arrayNode = (ArrayNode) mapper.readTree(ret);
logger.debug("Found {} profiles", arrayNode.size());
Iterator<JsonNode> iterator = arrayNode.iterator();
while(iterator.hasNext()) {
String profileID = iterator.next().asText();
ret = profile.read(profileID, MediaType.APPLICATION_XML);
logger.debug("XML :\n{}", ret);
ret = profile.read(profileID, MediaType.APPLICATION_JSON);
logger.debug("JSON : \n{}", ret);
}
}
}

@ -0,0 +1,24 @@
package org.gcube.gcat.social;
import org.gcube.gcat.ContextTest;
import org.gcube.gcat.social.SocialService;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
public class SocialServiceTest extends ContextTest {
private static final Logger logger = LoggerFactory.getLogger(SocialServiceTest.class);
@Test
public void testGetUserProfile() throws Exception {
SocialService socialService = new SocialService();
JsonNode jsonNode = socialService.getGCubeUserProfile();
ObjectMapper objectMapper = new ObjectMapper();
logger.debug("gCube User Profile is {}", objectMapper.writeValueAsString(jsonNode));
}
}

@ -0,0 +1,106 @@
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,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xml>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{0}: %msg%n</pattern>
</encoder>
</appender>
<logger name="org.gcube" level="ERROR" />
<logger name="org.gcube.datacatalogue" level="TRACE" />
<root level="WARN">
<appender-ref ref="STDOUT" />
</root>
</configuration>
Loading…
Cancel
Save