initial commit

This commit is contained in:
Francesco Mangiacrapa 2020-06-01 16:00:23 +02:00
commit bffb8f3d98
95 changed files with 7178 additions and 0 deletions

38
.classpath Normal file
View File

@ -0,0 +1,38 @@
<?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"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources">
<attributes>
<attribute name="maven.pomderived" value="true"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7">
<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="output" path="target/classes"/>
</classpath>

23
.project Normal file
View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>catalogue-util-library</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.m2e.core.maven2Nature</nature>
</natures>
</projectDescription>

View File

@ -0,0 +1,15 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.7
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore
org.eclipse.jdt.core.compiler.release=disabled
org.eclipse.jdt.core.compiler.source=1.7

View File

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

228
pom.xml Normal file
View File

@ -0,0 +1,228 @@
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>maven-parent</artifactId>
<groupId>org.gcube.tools</groupId>
<version>1.1.0</version>
<relativePath />
</parent>
<groupId>org.gcube.datacatalogue</groupId>
<artifactId>catalogue-util-library</artifactId>
<version>0.1.0-SNAPSHOT</version>
<name>CKan utility library</name>
<description>
Utility library to retrieve users information, organizations information and so on from the ckan d4science datacatalogue
</description>
<scm>
<connection>scm:git:https://code-repo.d4science.org/gCubeSystem/${project.artifactId}.git</connection>
<developerConnection>scm:git:https://code-repo.d4science.org/gCubeSystem/${project.artifactId}.git</developerConnection>
<url>https://code-repo.d4science.org/gCubeSystem/${project.artifactId}</url>
</scm>
<properties>
<serviceClass>data-catalogue</serviceClass>
<jackanVersion>0.4.2</jackanVersion>
<postgresVersion>9.4.1208.jre7</postgresVersion>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<gwtVersion>2.7.0</gwtVersion>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.gcube.distribution</groupId>
<artifactId>maven-portal-bom</artifactId>
<version>LATEST</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.google.gwt</groupId>
<artifactId>gwt-user</artifactId>
<scope>provided</scope>
</dependency>
<!-- CKAN client library -->
<dependency>
<groupId>eu.trentorise.opendata</groupId>
<artifactId>jackan</artifactId>
<version>${jackanVersion}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.gcube.data-publishing</groupId>
<artifactId>gcat-client</artifactId>
<version>[1.0.0, 2.0.0-SNAPSHOT)</version>
<scope>compile</scope>
</dependency>
<!-- <dependency> -->
<!-- <groupId>org.apache.httpcomponents</groupId> -->
<!-- <artifactId>fluent-hc</artifactId> -->
<!-- <version>4.5.3</version> -->
<!-- <scope>provided</scope> -->
<!-- </dependency> -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.gcube.common.portal</groupId>
<artifactId>portal-manager</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.gcube.resources.discovery</groupId>
<artifactId>ic-client</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.gcube.core</groupId>
<artifactId>common-scope-maps</artifactId>
<scope>provided</scope>
<!-- put at provided for deploying -->
</dependency>
<dependency>
<groupId>org.gcube.core</groupId>
<artifactId>common-encryption</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.gcube.dvos</groupId>
<artifactId>usermanagement-core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>net.htmlparser.jericho</groupId>
<artifactId>jericho-html</artifactId>
<version>3.3</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<dependency>
<groupId>com.googlecode.json-simple</groupId>
<artifactId>json-simple</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.solr</groupId>
<artifactId>solr-solrj</artifactId>
<version>[4.10.2,5.0.0)</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.*</include>
</includes>
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.2</version>
<executions>
<execution>
<goals>
<goal>test-jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.12</version>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.5</version>
<executions>
<execution>
<id>copy-profile</id>
<phase>install</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>target</outputDirectory>
<resources>
<resource>
<directory>${distroDirectory}</directory>
<filtering>true</filtering>
<includes>
<include>profile.xml</include>
</includes>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptors>
<descriptor>${distroDirectory}/descriptor.xml</descriptor>
</descriptors>
<archive>
<manifest>
<mainClass>fully.qualified.MainClass</mainClass>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<id>servicearchive</id>
<phase>install</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<module rename-to='ckanutilitylibrary'>
<!-- Inherit the core Web Toolkit stuff. -->
<inherits name='com.google.gwt.user.User' />
<!-- Specify the paths for translatable code -->
<source path='client' />
<source path='shared' />
</module>

View File

@ -0,0 +1,240 @@
/**
*
*/
package org.gcube.datacatalogue.ckanutillibrary.ckan;
import static com.google.common.base.Preconditions.checkNotNull;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URLEncoder;
import java.util.Arrays;
import javax.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Charsets;
import com.google.common.io.CharStreams;
import eu.trentorise.opendata.jackan.CheckedCkanClient;
import eu.trentorise.opendata.jackan.exceptions.CkanException;
import eu.trentorise.opendata.jackan.exceptions.JackanException;
import eu.trentorise.opendata.jackan.internal.org.apache.http.client.fluent.Request;
import eu.trentorise.opendata.jackan.internal.org.apache.http.client.fluent.Response;
import eu.trentorise.opendata.jackan.model.CkanGroup;
import eu.trentorise.opendata.jackan.model.CkanOrganization;
import eu.trentorise.opendata.jackan.model.CkanResponse;
/**
* The Class ExtendCkanClient.
*
* @author Francesco Mangiacrapa at ISTI-CNR (francesco.mangiacrapa@isti.cnr.it)
*
* Jun 14, 2019
*/
public class ExtendCkanClient extends CheckedCkanClient implements PatchedCkan{
private static final Logger logger = LoggerFactory.getLogger(ExtendCkanClient.class);
@Nullable
private static ObjectMapper objectMapper;
private String catalogueURL;
private String ckanToken;
private int extendTimeout = 120000; //in milliseconds
/**
* Instantiates a new extend ckan client.
*
* @param catalogueURL the catalogue url
*/
public ExtendCkanClient(String catalogueURL) {
super(catalogueURL);
this.catalogueURL = catalogueURL;
}
/**
* Instantiates a new extend ckan client.
*
* @param catalogueURL the catalogue url
* @param ckanToken the ckan token
*/
public ExtendCkanClient(String catalogueURL, @Nullable String ckanToken) {
super(catalogueURL, ckanToken);
this.catalogueURL = catalogueURL;
this.ckanToken = ckanToken;
}
/**
* Instantiates a new extend ckan client.
*
* @param catalogueURL the catalogue url
* @param ckanToken the ckan token
* @param timeout the timeout
*/
public ExtendCkanClient(String catalogueURL, @Nullable String ckanToken, int timeout) {
super(catalogueURL, ckanToken);
this.catalogueURL = catalogueURL;
this.ckanToken = ckanToken;
this.extendTimeout = timeout;
}
/**
* Configures the request. Should work both for GETs and POSTs.
*
* @param request the request
* @return the request
*/
@Override
protected Request configureRequest(Request request) {
request = super.configureRequest(request);
logger.debug("Setting timeout to {}", extendTimeout);
request.socketTimeout(this.extendTimeout)
.connectTimeout(this.extendTimeout);
return request;
}
/**
* Gets the catalogue url.
*
* @return the catalogueURL
*/
public String getCatalogueURL() {
return catalogueURL;
}
/**
* Gets the ckan token.
*
* @return the ckanToken
*/
@Override
public String getCkanToken() {
return ckanToken;
}
/**
* Gets the timeout.
*
* @return the timeout
*/
public int getTimeout() {
return extendTimeout;
}
/* (non-Javadoc)
* @see eu.trentorise.opendata.jackan.CkanClient#getOrganization(java.lang.String)
*/
public synchronized CkanOrganization getOrganization(String idOrName) {
checkNotNull(idOrName, "Need a valid id or name!");
logger.info("Patched read organization for id/name: {}", idOrName);
return getHttp(OrganizationResponse.class, "/api/3/action/organization_show", "id", idOrName,
"include_datasets", "false", "include_users", "true").result;
}
/* (non-Javadoc)
* @see eu.trentorise.opendata.jackan.CkanClient#getGroup(java.lang.String)
*/
public synchronized CkanGroup getGroup(String idOrName) {
checkNotNull(idOrName, "Need a valid id or name!");
logger.info("Patched read group for id/name: {}", idOrName);
return getHttp(GroupResponse.class, "/api/3/action/group_show", "id", idOrName, "include_datasets",
"false", "include_users", "true").result;
}
/**
* Retrieves the Jackson object mapper for reading operations. Internally,
* Object mapper is initialized at first call.
*
* @return the object mapper
*/
static ObjectMapper getObjectMapper() {
if (objectMapper == null) {
objectMapper = new ObjectMapper();
configureObjectMapper(objectMapper);
}
return objectMapper;
}
/* (non-Javadoc)
* @see org.gcube.datacatalogue.ckanutillibrary.server.patch.PatchedCkan#getHttp(java.lang.Class, java.lang.String, java.lang.Object[])
*/
public <T extends CkanResponse> T getHttp(Class<T> responseType, String path, Object... params) {
checkNotNull(responseType);
checkNotNull(path);
String fullUrl = calcFullUrl(path, params);
T ckanResponse;
String returnedText;
try {
logger.debug("getting {}", fullUrl);
Request request = Request.Get(fullUrl);
configureRequest(request);
Response response = request.execute();
InputStream stream = response.returnResponse()
.getEntity()
.getContent();
try (InputStreamReader reader = new InputStreamReader(stream, Charsets.UTF_8)) {
returnedText = CharStreams.toString(reader);
}
logger.trace("returnedText {}", returnedText);
} catch (Exception ex) {
throw new CkanException("Error while performing GET. Request url was: " + fullUrl, this, ex);
}
try {
ckanResponse = getObjectMapper().readValue(returnedText, responseType);
} catch (Exception ex) {
throw new CkanException(
"Couldn't interpret json returned by the server! Returned text was: " + returnedText, this, ex);
}
if (!ckanResponse.isSuccess()) {
throwCkanException("Error while performing GET. Request url was: " + fullUrl, ckanResponse);
}
return ckanResponse;
}
/* (non-Javadoc)
* @see org.gcube.datacatalogue.ckanutillibrary.server.patch.PatchedCkan#calcFullUrl(java.lang.String, java.lang.Object[])
*/
public String calcFullUrl(String path, Object[] params) {
checkNotNull(path);
try {
StringBuilder sb = new StringBuilder().append(catalogueURL)
.append(path);
for (int i = 0; i < params.length; i += 2) {
sb.append(i == 0 ? "?" : "&")
.append(URLEncoder.encode(params[i].toString(), "UTF-8"))
.append("=")
.append(URLEncoder.encode(params[i + 1].toString(), "UTF-8"));
}
return sb.toString();
} catch (Exception ex) {
throw new JackanException("Error while building url to perform GET! \n path: " + path + " \n params: "
+ Arrays.toString(params), ex);
}
}
}

View File

@ -0,0 +1,113 @@
package org.gcube.datacatalogue.ckanutillibrary.ckan;
import eu.trentorise.opendata.jackan.CkanClient;
import eu.trentorise.opendata.jackan.exceptions.CkanException;
import eu.trentorise.opendata.jackan.exceptions.JackanException;
import eu.trentorise.opendata.jackan.model.CkanGroup;
import eu.trentorise.opendata.jackan.model.CkanOrganization;
import eu.trentorise.opendata.jackan.model.CkanResponse;
/**
* The Interface PatchedCkan.
*
* @author Francesco Mangiacrapa at ISTI-CNR (francesco.mangiacrapa@isti.cnr.it)
*
* Jun 14, 2019
*/
public interface PatchedCkan {
/**
*
* This Class is private in {@link CkanClient} so I need to rewrite it
*
* The Class OrganizationResponse.
*
* @author Francesco Mangiacrapa at ISTI-CNR (francesco.mangiacrapa@isti.cnr.it)
*
* Jun 7, 2019
*/
static class OrganizationResponse extends CkanResponse {
public CkanOrganization result;
}
/**
*
*
* This Class is private in {@link CkanClient} so I need to rewrite it
*
*
* The Class GroupResponse.
*
* @author Francesco Mangiacrapa at ISTI-CNR (francesco.mangiacrapa@isti.cnr.it)
*
* Jun 7, 2019
*/
static class GroupResponse extends CkanResponse {
public CkanGroup result;
/**
* Instantiates a new group response.
*/
public GroupResponse() {
}
}
/**
*
* This method is private in {@link CkanClient} so I need to rewrite it
*
*
*
* Performs HTTP GET on server. If {@link CkanResponse#isSuccess()} is false
* throws {@link CkanException}.
*
* @param <T> the generic type
* @param responseType a descendant of CkanResponse
* @param path something like /api/3/package_show
* @param params list of key, value parameters. They must be not be url
* encoded. i.e. "id","laghi-monitorati-trento"
* @return the http
* @throws CkanException on error
*/
public <T extends CkanResponse> T getHttp(Class<T> responseType, String path, Object... params);
/**
*
* This method is private in {@link CkanClient} so I need to rewrite it
*
*
* Calculates a full url out of the provided params.
*
* @param path something like /api/3/package_show
* @param params list of key, value parameters. They must be not be url encoded.
* i.e. "id","laghi-monitorati-trento"
* @return the full url to be called.
* @throws JackanException if there is any error building the url
*/
public String calcFullUrl(String path, Object[] params);
// WE NEED TO OVERRIDE THE FOLLOWING METHODS
/**
* Gets the organization.
*
* @param idOrName the id or name
* @return the organization
*/
public CkanOrganization getOrganization(String idOrName);
/**
* Gets the group.
*
* @param idOrName the id or name
* @return the group
*/
public CkanGroup getGroup(String idOrName);
}

View File

@ -0,0 +1,168 @@
package org.gcube.datacatalogue.ckanutillibrary.ckan;
import static com.google.common.base.Preconditions.checkNotNull;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URLEncoder;
import java.util.Arrays;
import javax.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Charsets;
import com.google.common.io.CharStreams;
import eu.trentorise.opendata.jackan.CkanClient;
import eu.trentorise.opendata.jackan.exceptions.CkanException;
import eu.trentorise.opendata.jackan.exceptions.JackanException;
import eu.trentorise.opendata.jackan.internal.org.apache.http.client.fluent.Request;
import eu.trentorise.opendata.jackan.internal.org.apache.http.client.fluent.Response;
import eu.trentorise.opendata.jackan.model.CkanGroup;
import eu.trentorise.opendata.jackan.model.CkanOrganization;
import eu.trentorise.opendata.jackan.model.CkanResponse;
/**
* The Class SimpleExtendCkanClient.
*
* @author Francesco Mangiacrapa at ISTI-CNR (francesco.mangiacrapa@isti.cnr.it)
*
* Jun 7, 2019
*/
public class SimpleExtendCkanClient extends CkanClient implements PatchedCkan{
private String catalogueURL;
@Nullable
private static ObjectMapper objectMapper;
private static final Logger logger = LoggerFactory.getLogger(SimpleExtendCkanClient.class);
/**
* Instantiates a new simple extend ckan client.
*
* @param catalogueURL the catalogue URL
*/
public SimpleExtendCkanClient(String catalogueURL) {
super(catalogueURL);
this.catalogueURL = catalogueURL;
}
/* (non-Javadoc)
* @see eu.trentorise.opendata.jackan.CkanClient#getOrganization(java.lang.String)
*/
public synchronized CkanOrganization getOrganization(String idOrName) {
checkNotNull(idOrName, "Need a valid id or name!");
logger.info("Patched read organization for id/name: {}", idOrName);
return getHttp(OrganizationResponse.class, "/api/3/action/organization_show", "id", idOrName,
"include_datasets", "false", "include_users", "true").result;
}
/* (non-Javadoc)
* @see eu.trentorise.opendata.jackan.CkanClient#getGroup(java.lang.String)
*/
public synchronized CkanGroup getGroup(String idOrName) {
checkNotNull(idOrName, "Need a valid id or name!");
logger.info("Patched read group for id/name: {}", idOrName);
return getHttp(GroupResponse.class, "/api/3/action/group_show", "id", idOrName, "include_datasets",
"false", "include_users", "true").result;
}
/**
* Retrieves the Jackson object mapper for reading operations. Internally,
* Object mapper is initialized at first call.
*
* @return the object mapper
*/
public static ObjectMapper getObjectMapper() {
if (objectMapper == null) {
objectMapper = new ObjectMapper();
configureObjectMapper(objectMapper);
}
return objectMapper;
}
/* (non-Javadoc)
* @see org.gcube.datacatalogue.ckanutillibrary.server.patch.PatchedCkan#getHttp(java.lang.Class, java.lang.String, java.lang.Object[])
*/
public <T extends CkanResponse> T getHttp(Class<T> responseType, String path, Object... params) {
checkNotNull(responseType);
checkNotNull(path);
String fullUrl = calcFullUrl(path, params);
T ckanResponse;
String returnedText;
try {
logger.debug("getting {}", fullUrl);
Request request = Request.Get(fullUrl);
configureRequest(request);
Response response = request.execute();
InputStream stream = response.returnResponse()
.getEntity()
.getContent();
try (InputStreamReader reader = new InputStreamReader(stream, Charsets.UTF_8)) {
returnedText = CharStreams.toString(reader);
}
logger.trace("returnedText {}", returnedText);
} catch (Exception ex) {
throw new CkanException("Error while performing GET. Request url was: " + fullUrl, this, ex);
}
try {
ckanResponse = getObjectMapper().readValue(returnedText, responseType);
} catch (Exception ex) {
throw new CkanException(
"Couldn't interpret json returned by the server! Returned text was: " + returnedText, this, ex);
}
if (!ckanResponse.isSuccess()) {
throwCkanException("Error while performing GET. Request url was: " + fullUrl, ckanResponse);
}
return ckanResponse;
}
/* (non-Javadoc)
* @see org.gcube.datacatalogue.ckanutillibrary.server.patch.PatchedCkan#calcFullUrl(java.lang.String, java.lang.Object[])
*/
public String calcFullUrl(String path, Object[] params) {
checkNotNull(path);
try {
StringBuilder sb = new StringBuilder().append(catalogueURL)
.append(path);
for (int i = 0; i < params.length; i += 2) {
sb.append(i == 0 ? "?" : "&")
.append(URLEncoder.encode(params[i].toString(), "UTF-8"))
.append("=")
.append(URLEncoder.encode(params[i + 1].toString(), "UTF-8"));
}
return sb.toString();
} catch (Exception ex) {
throw new JackanException("Error while building url to perform GET! \n path: " + path + " \n params: "
+ Arrays.toString(params), ex);
}
}
/**
* Gets the catalogue url.
*
* @return the catalogueURL
*/
public String getCatalogueURL() {
return catalogueURL;
}
}

View File

@ -0,0 +1,209 @@
package org.gcube.datacatalogue.ckanutillibrary.db;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import org.gcube.datacatalogue.ckanutillibrary.shared.RolesCkanGroupOrOrg;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class DBCaller {
private static final Logger LOG = LoggerFactory.getLogger(DBCaller.class);
private String CKAN_DB_URL;
private Integer CKAN_DB_PORT;
private String CKAN_DB_NAME;
private String CKAN_DB_USER;
private String CKAN_DB_PASSWORD;
public DBCaller() {
}
public DBCaller(String cKAN_DB_URL, Integer cKAN_DB_PORT, String cKAN_DB_NAME, String cKAN_DB_USER,
String cKAN_DB_PASSWORD) {
CKAN_DB_URL = cKAN_DB_URL;
CKAN_DB_PORT = cKAN_DB_PORT;
CKAN_DB_NAME = cKAN_DB_NAME;
CKAN_DB_USER = cKAN_DB_USER;
CKAN_DB_PASSWORD = cKAN_DB_PASSWORD;
}
/**
* Retrieve connection from the pool
* @return a connection available within the pool
* @throws SQLException
* @throws ClassNotFoundException
*/
private Connection getConnection() throws SQLException, ClassNotFoundException{
LOG.debug("CONNECTION REQUEST");
// create db connection
Class.forName("org.postgresql.Driver");
String dbBaseConnectionURL = String.format("jdbc:postgresql://%s", CKAN_DB_URL);
if(CKAN_DB_PORT!=null)
dbBaseConnectionURL+=":" + CKAN_DB_PORT;
dbBaseConnectionURL+="/" + CKAN_DB_NAME;
Connection connection = DriverManager.getConnection(dbBaseConnectionURL, CKAN_DB_USER, CKAN_DB_PASSWORD);
// Connection connection = DriverManager.getConnection(
// "jdbc:postgresql://" + CKAN_DB_URL + ":" + CKAN_DB_PORT + "/" + CKAN_DB_NAME, CKAN_DB_USER, CKAN_DB_PASSWORD);
return connection;
}
/**
* Retrieve the map (groups id, capacity) with the groups to which the user belongs by querying directly the database.
* @param username
* @return
* @throws SQLException
* @throws ClassNotFoundException
*/
public Map<String, RolesCkanGroupOrOrg> getGroupsByUserFromDB(String userId){
checkNotNull(userId);
//couples (groups id, capacity) of the user in the group
Map<String, RolesCkanGroupOrOrg> toReturn = new HashMap<String, RolesCkanGroupOrOrg>();
Connection connection = null;
try{
connection = getConnection();
ResultSet rs;
String joinQuery = "SELECT \"group_id\",\"capacity\" FROM \"public\".\"member\" "
+ "JOIN \"public\".\"group\" ON \"member\".\"group_id\" = \"group\".\"id\" where \"table_id\"=?"
+ " and \"table_name\"='user' and \"member\".\"state\"='active' and \"group\".\"state\"='active' and \"group\".\"is_organization\"=?;";
PreparedStatement preparedStatement = connection.prepareStatement(joinQuery);
preparedStatement.setString(1, userId);
preparedStatement.setBoolean(2, false);
rs = preparedStatement.executeQuery();
while (rs.next()) {
toReturn.put(rs.getString("group_id"), RolesCkanGroupOrOrg.convertFromCapacity(rs.getString("capacity")));
}
}catch(Exception e){
LOG.error("Failed to retrieve the groups to whom the user belongs. Error is " + e.getMessage());
return null;
}finally{
closeConnection(connection);
}
return toReturn;
}
/**
* Retrieve the map (organisation id, capacity) with the organisations to which the user belongs by querying directly the database.
* @param username
* @return
* @throws SQLException
* @throws ClassNotFoundException
*/
public Map<String, RolesCkanGroupOrOrg> getOrganizationsByUserFromDB(String userId){
checkNotNull(userId);
Map<String, RolesCkanGroupOrOrg> toReturn = new HashMap<String, RolesCkanGroupOrOrg>();
Connection connection = null;
try{
connection = getConnection();
ResultSet rs;
String joinQuery = "SELECT \"group_id\",\"capacity\" FROM \"public\".\"member\" "
+ "JOIN \"public\".\"group\" ON \"member\".\"group_id\" = \"group\".\"id\" where \"table_id\"=?"
+ " and \"table_name\"='user' and \"member\".\"state\"='active' and \"group\".\"state\"='active' and \"group\".\"is_organization\"=?;";
PreparedStatement preparedStatement = connection.prepareStatement(joinQuery);
preparedStatement.setString(1, userId);
preparedStatement.setBoolean(2, true);
rs = preparedStatement.executeQuery();
while (rs.next()) {
toReturn.put(rs.getString("group_id"), RolesCkanGroupOrOrg.convertFromCapacity(rs.getString("capacity")));
}
}catch(Exception e){
LOG.error("Failed to retrieve the groups to whom the user belongs. Error is " + e.getMessage());
return null;
}finally{
closeConnection(connection);
}
return toReturn;
}
public String getApiKeyFromUsername(String username, String state) {
LOG.debug("Request api key for user = " + username);
// checks
checkNotNull(username);
checkArgument(!username.isEmpty());
// the connection
Connection connection = null;
String apiToReturn = null;
try{
connection = getConnection();
String query = "SELECT \"apikey\" FROM \"user\" WHERE \"name\"=? and \"state\"=?;";
PreparedStatement preparedStatement = connection.prepareStatement(query);
preparedStatement.setString(1, username);
preparedStatement.setString(2, state);
ResultSet rs = preparedStatement.executeQuery();
while (rs.next()) {
apiToReturn = rs.getString("apikey");
LOG.debug("Api key "+apiToReturn.substring(0,10)+" MASKED-TOKEN retrieved for user " + username);
break;
}
return apiToReturn;
}catch(Exception e){
LOG.error("Unable to retrieve key for user " + username, e);
}finally{
closeConnection(connection);
}
return null;
}
/**
* Tries to close a connection
* @param connection
*/
private void closeConnection(Connection connection){
if(connection != null){
try{
connection.close();
}catch(Exception e){
LOG.error("Unable to close this connection ", e);
}
}
}
}

View File

@ -0,0 +1,69 @@
package org.gcube.datacatalogue.ckanutillibrary.gcat;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.List;
import org.gcube.datacatalogue.ckanutillibrary.ckan.SimpleExtendCkanClient;
import org.gcube.gcat.client.Item;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import eu.trentorise.opendata.jackan.model.CkanDataset;
import eu.trentorise.opendata.jackan.model.CkanLicense;
// TODO: Auto-generated Javadoc
/**
* The Class GCatCaller.
*
* @author Francesco Mangiacrapa at ISTI-CNR Pisa (Italy)
* May 29, 2020
*/
public class GCatCaller {
private SimpleExtendCkanClient jackanCkanClient;
private String catalogueURL;
private static final Logger LOG = LoggerFactory.getLogger(GCatCaller.class);
/**
* Instantiates a new g cat caller.
*/
public GCatCaller(String catalogueURL) {
this.catalogueURL = catalogueURL;
this.jackanCkanClient = new SimpleExtendCkanClient(catalogueURL);
}
/**
* Gets the dataset for name.
*
* @param datasetIdOrName the dataset id or name
* @return the dataset for name
* @throws JsonParseException the json parse exception
* @throws JsonMappingException the json mapping exception
* @throws IOException Signals that an I/O exception has occurred.
*/
public CkanDataset getDatasetForName(String datasetIdOrName) throws JsonParseException, JsonMappingException, IOException {
LOG.debug("Get dataset for name "+datasetIdOrName+ "called");
String json = new Item().read(datasetIdOrName);
return SimpleExtendCkanClient.getObjectMapper().readValue(json, CkanDataset.class);
}
/**
* TODO gCAT missing
* @return
* @throws MalformedURLException
*/
public List<CkanLicense> getLicenseList() {
LOG.debug("Get linces list called");
return jackanCkanClient.getLicenseList();
}
}

View File

@ -0,0 +1,105 @@
package org.gcube.datacatalogue.ckanutillibrary.server;
import static org.gcube.resources.discovery.icclient.ICFactory.client;
import java.io.StringReader;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.gcube.common.portal.PortalContext;
import org.gcube.common.resources.gcore.utils.XPathHelper;
import org.gcube.common.scope.api.ScopeProvider;
import org.gcube.datacatalogue.ckanutillibrary.shared.ex.ApplicationProfileNotFoundException;
import org.gcube.resources.discovery.client.api.DiscoveryClient;
import org.gcube.resources.discovery.client.queries.api.Query;
import org.gcube.resources.discovery.client.queries.impl.QueryBox;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;
/**
* This class has a method that tries to read the application profile whose structure contains
* couples Scope/Current_Url to check where the the needed information needs to be discovered according to the current
* portlet url. It means that the scope in which the ckan related information will be discovered could be different wrt the running one.
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
*/
public class ApplicationProfileScopePerUrlReader {
private static final Logger logger = LoggerFactory.getLogger(ApplicationProfileScopePerUrlReader.class);
private final static String APPLICATION_PROFILE_NAME = "DataCatalogueMapScopesUrls";
private final static String QUERY = "for $profile in collection('/db/Profiles/GenericResource')//Resource " +
"where $profile/Profile/SecondaryType/string() eq 'ApplicationProfile' and $profile/Profile/Name/string() " +
" eq '" + APPLICATION_PROFILE_NAME + "'" +
"return $profile";
/**
* Get the scope in which discover for this url. If the Application Profile doesn't contain it, the current scope (taken
* from ScopeProvider is returned).
* @param url
* @return the scope to be used for the given url
*/
public static String getScopePerUrl(String url){
logger.info("Request scope for ckan portlet at url " + url);
String scope = ScopeProvider.instance.get();
String scopeToReturn = scope;
String rootScopeForInfrastructure = "/" + PortalContext.getConfiguration().getInfrastructureName();
if(url == null || url.isEmpty()){
logger.info("The url passed is null or empty! Returning current scope [" + scope + "]");
return scope;
}
// set this scope
ScopeProvider.instance.set(rootScopeForInfrastructure);
logger.debug("Trying to fetch applicationProfile profile from the infrastructure for " + APPLICATION_PROFILE_NAME + " scope: " + rootScopeForInfrastructure);
try {
Query q = new QueryBox(QUERY);
DiscoveryClient<String> client = client();
List<String> appProfile = client.submit(q);
if (appProfile == null || appProfile.size() == 0)
throw new ApplicationProfileNotFoundException("Your applicationProfile is not registered in the infrastructure");
else{
String elem = appProfile.get(0);
DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Node node = docBuilder.parse(new InputSource(new StringReader(elem))).getDocumentElement();
XPathHelper helper = new XPathHelper(node);
List<String> urls = helper.evaluate("/Resource/Profile/Body/EndPoint/URL/text()");
if (urls != null && urls.size() > 0) {
boolean foundScope = false;
for (int i = 0; i < urls.size(); i++) {
if (urls.get(i).trim().compareTo(url) == 0) { // url found
scopeToReturn = helper.evaluate("/Resource/Profile/Body/EndPoint/Scope/text()").get(i);
logger.debug("Found, returning " + scopeToReturn);
foundScope = true;
break;
}
}
if (!foundScope || scopeToReturn == null || scopeToReturn.isEmpty()){
logger.debug("Scope is missing for url " + url + ". Returning " + scope);
}
}
else
throw
new ApplicationProfileNotFoundException("Your applicationProfile EndPoint was not found in the profile, consider adding <EndPoint><Scope> element in <Body>");
}
} catch (Exception e) {
logger.error("Error while trying to fetch applicationProfile profile from the infrastructure", e);
}finally{
ScopeProvider.instance.set(scope);
}
return scopeToReturn;
}
}

View File

@ -0,0 +1,44 @@
package org.gcube.datacatalogue.ckanutillibrary.server;
// TODO: Auto-generated Javadoc
/**
* The Class CKANTokenBean.
*
* @author Francesco Mangiacrapa at ISTI-CNR Pisa (Italy)
* Jun 1, 2020
*/
public class CKANTokenBean {
protected String apiKey;
protected long timestamp;
/**
* Instantiates a new CKAN token bean.
*
* @param apiKey the api key
* @param timestamp the timestamp
*/
public CKANTokenBean(String apiKey, long timestamp) {
super();
this.apiKey = apiKey;
this.timestamp = timestamp;
}
public String getApiKey() {
return apiKey;
}
public void setApiKey(String apiKey) {
this.apiKey = apiKey;
}
public long getTimestamp() {
return timestamp;
}
public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}
}

View File

@ -0,0 +1,200 @@
package org.gcube.datacatalogue.ckanutillibrary.server;
import java.util.List;
import java.util.Map;
import org.gcube.datacatalogue.ckanutillibrary.shared.ResourceBean;
import org.gcube.datacatalogue.ckanutillibrary.shared.RolesCkanGroupOrOrg;
import eu.trentorise.opendata.jackan.model.CkanDataset;
import eu.trentorise.opendata.jackan.model.CkanGroup;
import eu.trentorise.opendata.jackan.model.CkanLicense;
import eu.trentorise.opendata.jackan.model.CkanOrganization;
public interface DataCatalogue {
/**
* Finds the id associated to the chosen license
*
* @param chosenLicense
* @return the id on success, null otherwise
*/
String findLicenseIdByLicenseTitle(String chosenLicense);
/**
* Given the id or the name of the dataset it returns its current url by
* contacting the uri resolver. If no uri resolver is available, an url that is
* not guaranteed to be long term valid will be generated. Information are not
* encrypted.
*
* @param datasetId
* @return The url of the dataset on success, null otherwise
*/
String getUnencryptedUrlFromDatasetIdOrName(String datasetIdOrName);
/**
* Create a dataset with those information. The method allows to have multiple
* values for the same custom field key. NOTE: unfortunately java doesn't
* support overload in java interface methods (that's way I cannot use the same
* name for the method)
*
* @param title
* @param name (unique identifier)
* @param organizationNameOrId
* @param author
* @param authorMail
* @param maintainer
* @param maintainerMail
* @param version
* @param description
* @param licenseId
* @param tags
* @param customFields
* @param resources
* @param setPublic (manage visibility: Admin role is needed)
* @return the id of the dataset on success, null otherwise
* @throws Exception
*/
String createCKanDatasetMultipleCustomFields(String title, String name, String organizationNameOrId, String author,
String authorMail, String maintainer, String maintainerMail, long version, String description,
String licenseId, List<String> tags, Map<String, List<String>> customFields, List<ResourceBean> resources,
boolean setPublic) throws Exception;
/**
* Patch a product with product id productId by using the couples in
* customFieldsToChange. NOTE: only the specified custom fields will be changed.
* If a custom field with a given key already exists, and removeOld is set to
* false, the new values are added at the end of the list. Otherwise they are
* lost.
*
* @param productId
* @param customFieldsToChange
* @param removeOld
* @return
*/
boolean patchProductCustomFields(String productId, Map<String, List<String>> customFieldsToChange,
boolean removeOld);
/**
* Add a resource described by the bean to the dataset id into
* resource.datasetId
*
* @param resource
* @return String the id of the resource on success, null otherwise
*/
String addResourceToDataset(ResourceBean resource) throws Exception;
/**
* Remove the resource with id resourceId from the dataset in which it is.
*
* @param resourceId
* @return true on success, false otherwise.
*/
boolean deleteResourceFromDataset(String resourceId);
/**
* Create a dataset with those information.
*
* @param apiKey
* @param title
* @param name (unique identifier)
* @param organizationNameOrId
* @param author
* @param authorMail
* @param maintainer
* @param maintainerMail
* @param version
* @param description
* @param licenseId
* @param tags
* @param customFields
* @param resources
* @param setPublic (manage visibility: Admin role is needed)
* @return the id of the dataset on success, null otherwise
* @throws Exception
*/
/**
* Checks if a product with such name already exists. Please remember that the
* name is unique.
*
* @param nameOrId the name or the id of the dataset to check
* @return
*/
boolean existProductWithNameOrId(String nameOrId);
/**
* The method returns the role the user has in the groups he/she belongs to (it
* uses the db, so it is much faster)
*
* @param username
* @param apiKey
* @return
*/
Map<String, Map<CkanGroup, RolesCkanGroupOrOrg>> getUserRoleByGroup(String username, String apiKey);
/**
* Get the list of licenses' titles.
*
* @return the list of licenses' titles
*/
List<String> getLicenseTitles();
/**
* Retrieve ckan licenses
*
* @return
*/
List<CkanLicense> getLicenses();
/**
* Retrieve the url of the uri resolver for this catalogue instance/scope
*
* @return
*/
String getUriResolverUrl();
/**
* Return the manage product property
*
* @return the manage product property
*/
boolean isManageProductEnabled();
/**
* Return the catalogue portlet for this context(i.e. scope)
*
* @return
*/
String getPortletUrl();
/**
* Return the ckan catalogue url in this scope.
*
* @return the catalogue url
*/
String getCatalogueUrl();
/**
* Returns the list of organizations to whom the user belongs (with any role)
* @param username
* @return a list of organizations
*/
List<CkanOrganization> getOrganizationsByUser(String username);
/**
* Returns the list of groups to whom the user belongs (with any role)
* @param username
* @return a list of groups
*/
List<CkanGroup> getGroupsByUser(String username);
/**
* Retrieve a ckan dataset given its id
* @param datasetId
* @return
*/
CkanDataset getDataset(String datasetId, String apiKey);
}

View File

@ -0,0 +1,78 @@
package org.gcube.datacatalogue.ckanutillibrary.server;
import java.util.concurrent.ConcurrentHashMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Please invoke this method to retrieve an object of this kind per scope.
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
*/
public class DataCatalogueFactory {
private static final Logger logger = LoggerFactory.getLogger(DataCatalogueFactory.class);
private static final long MAX_LIFETIME = 1000 * 60 * 30; // 30 MINUTES
private static DataCatalogueFactory instance = new DataCatalogueFactory();
private static ConcurrentHashMap<String, CacheBean> cache;
private class CacheBean{
DataCatalogueImpl utils;
long ttl;
public CacheBean(long ttl, DataCatalogueImpl utils){
this.ttl = ttl;
this.utils = utils;
}
}
/**
* Private constructor
*/
private DataCatalogueFactory(){
logger.debug("Ckan factory object build");
cache = new ConcurrentHashMap<String, CacheBean>();
}
/**
* Get the factory instance
* @return
*/
public static DataCatalogueFactory getFactory(){
logger.debug("Factory requested");
return instance;
}
/**
* Retrieve the ckan utils information for the given scope
* @param scope
* @return
* @throws Exception
*/
public DataCatalogueImpl getUtilsPerScope(String scope) throws Exception{
if(scope == null || scope.isEmpty())
throw new IllegalArgumentException("Invalid scope given!");
if(cache.containsKey(scope) && !expired(cache.get(scope))){
return cache.get(scope).utils;
}
else{
logger.info("Creating CKAN LIB utils for scope " + scope);
DataCatalogueImpl utils = new DataCatalogueImpl(scope);
cache.put(scope, new CacheBean(System.currentTimeMillis(), utils));
return utils;
}
}
/**
* Check if the ckan information must be retrieved again.
* @param cacheBean
* @return
*/
private boolean expired(CacheBean cacheBean) {
return (cacheBean.ttl + MAX_LIFETIME < System.currentTimeMillis());
}
}

View File

@ -0,0 +1,543 @@
package org.gcube.datacatalogue.ckanutillibrary.server;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.gcube.common.authorization.library.provider.SecurityTokenProvider;
import org.gcube.common.scope.impl.ScopeBean;
import org.gcube.common.scope.impl.ScopeBean.Type;
import org.gcube.datacatalogue.ckanutillibrary.ckan.ExtendCkanClient;
import org.gcube.datacatalogue.ckanutillibrary.ckan.SimpleExtendCkanClient;
import org.gcube.datacatalogue.ckanutillibrary.db.DBCaller;
import org.gcube.datacatalogue.ckanutillibrary.gcat.GCatCaller;
import org.gcube.datacatalogue.ckanutillibrary.server.DataCatalogueRunningCluster.ACCESS_LEVEL_TO_CATALOGUE_PORTLET;
import org.gcube.datacatalogue.ckanutillibrary.server.utils.CatalogueUtilMethods;
import org.gcube.datacatalogue.ckanutillibrary.server.utils.url.EntityContext;
import org.gcube.datacatalogue.ckanutillibrary.shared.ResourceBean;
import org.gcube.datacatalogue.ckanutillibrary.shared.RolesCkanGroupOrOrg;
import org.gcube.datacatalogue.ckanutillibrary.shared.State;
import org.json.simple.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import eu.trentorise.opendata.jackan.internal.org.apache.http.HttpResponse;
import eu.trentorise.opendata.jackan.internal.org.apache.http.client.methods.HttpPost;
import eu.trentorise.opendata.jackan.internal.org.apache.http.entity.ContentType;
import eu.trentorise.opendata.jackan.internal.org.apache.http.entity.StringEntity;
import eu.trentorise.opendata.jackan.internal.org.apache.http.impl.client.CloseableHttpClient;
import eu.trentorise.opendata.jackan.internal.org.apache.http.impl.client.HttpClientBuilder;
import eu.trentorise.opendata.jackan.internal.org.apache.http.util.EntityUtils;
import eu.trentorise.opendata.jackan.model.CkanDataset;
import eu.trentorise.opendata.jackan.model.CkanGroup;
import eu.trentorise.opendata.jackan.model.CkanLicense;
import eu.trentorise.opendata.jackan.model.CkanOrganization;
import eu.trentorise.opendata.jackan.model.CkanUser;
public class DataCatalogueImpl implements DataCatalogue {
private static final Logger LOG = LoggerFactory.getLogger(DataCatalogueImpl.class);
private String CKAN_CATALOGUE_URL;
private String CKAN_DB_NAME;
private String CKAN_DB_USER;
private String CKAN_DB_PASSWORD;
private String CKAN_DB_URL;
private Integer CKAN_DB_PORT;
private String PORTLET_URL_FOR_SCOPE;
private String SOLR_URL;
private String CKAN_TOKEN_SYS;
private String CKAN_EMAIL;
private String URI_RESOLVER_URL;
private boolean MANAGE_PRODUCT_BUTTON;
private boolean SOCIAL_POST;
private boolean ALERT_USERS_ON_POST_CREATION;
private String CONTEXT;
private Map<String, String> extendRoleInOrganization;
public Map<ACCESS_LEVEL_TO_CATALOGUE_PORTLET, String> mapAccessURLToCatalogue;
private static final String CATALOGUE_TAB_ENDING_URL = "/catalogue";
// gCat client
private GCatCaller gCatCaller;
// db client
private DBCaller dbCaller;
// ckan client
private SimpleExtendCkanClient ckanCaller;
// hashmap for ckan api keys
private ConcurrentHashMap<String, CKANTokenBean> apiKeysMap;
// apikey bean expires after X minutes in the above map
private static final int EXPIRE_KEY_TIME = 60 * 60 * 1000;
/**
* The ckan catalogue url and database will be discovered in this scope
* @param scope
* @throws Exception if unable to find datacatalogue info
*/
public DataCatalogueImpl(String scope) throws Exception{
DataCatalogueRunningCluster runningInstance = new DataCatalogueRunningCluster(scope);
// save information
CKAN_DB_URL = runningInstance.getDatabaseHosts().get(0).trim();
CKAN_DB_PORT = runningInstance.getDatabasePorts().get(0);
CKAN_DB_NAME = runningInstance.getDataBaseName().trim();
CKAN_DB_USER = runningInstance.getDataBaseUser().trim();
CKAN_DB_PASSWORD = runningInstance.getDataBasePassword().trim();
//CKAN_TOKEN_SYS = runningInstance.getSysAdminToken().trim();
CKAN_EMAIL = runningInstance.getEmailCatalogue().trim();
CKAN_CATALOGUE_URL = runningInstance.getDataCatalogueUrl().get(0).trim();
PORTLET_URL_FOR_SCOPE = runningInstance.getPortletUrl().trim();
mapAccessURLToCatalogue = runningInstance.getMapAccessURLToCatalogue();
MANAGE_PRODUCT_BUTTON = runningInstance.isManageProductEnabled();
URI_RESOLVER_URL = runningInstance.getUrlResolver();
SOCIAL_POST = runningInstance.isSocialPostEnabled();
ALERT_USERS_ON_POST_CREATION = runningInstance.isAlertEnabled();
SOLR_URL = runningInstance.getUrlSolr();
LOG.info("In the scope: "+scope+", I read the catalogue URL: " + CKAN_CATALOGUE_URL);
// build the clients
gCatCaller = new GCatCaller(CKAN_CATALOGUE_URL);
dbCaller = new DBCaller(CKAN_DB_URL, CKAN_DB_PORT, CKAN_DB_NAME, CKAN_DB_USER, CKAN_DB_PASSWORD);
ckanCaller = new SimpleExtendCkanClient(CKAN_CATALOGUE_URL);
// init map
apiKeysMap = new ConcurrentHashMap<String, CKANTokenBean>();
// save the context
CONTEXT = scope;
// extended roles
extendRoleInOrganization = runningInstance.getExtendRoleInOrganization();
}
@Override
public String getCatalogueUrl() {
return CKAN_CATALOGUE_URL;
}
@Override
public String getPortletUrl() {
//PATCHED By Francesco
ScopeBean context = new ScopeBean(CONTEXT);
if(context.is(Type.INFRASTRUCTURE)) {
LOG.info("Working with the {} scope returning the path read from GR 'Ckan-Porltet': {}", Type.INFRASTRUCTURE.toString(), PORTLET_URL_FOR_SCOPE);
return PORTLET_URL_FOR_SCOPE;
}
String vreNameLower = context.name().toLowerCase();
//CHECKING IF THE PORTLET URL CONTAINS THE VRE NAME INTO URL
if(PORTLET_URL_FOR_SCOPE.toLowerCase().contains(vreNameLower)){
//THE PORLTET URL READ FROM GENERIC RESOUCE 'CkanPortlet' SHOULD BE ALREADY VALID, POITING TO CKAN PORTLET
return PORTLET_URL_FOR_SCOPE;
}else{
//ADDING VRE getApiKeyFromUsernameNAME AND THE SUFFIX 'CATALOGUE_TAB_ENDING_URL' TO URL
String buildedUrl = PORTLET_URL_FOR_SCOPE.endsWith("/") ? PORTLET_URL_FOR_SCOPE : PORTLET_URL_FOR_SCOPE + "/";
String defaultSuffix = vreNameLower + CATALOGUE_TAB_ENDING_URL;
buildedUrl+= defaultSuffix;
LOG.warn("The Portlet URL read from Generic Resource 'Ckan-Porltet' does not contain the portlet suffix, so I added the default: "+defaultSuffix);
return buildedUrl;
}
}
@Override
public String findLicenseIdByLicenseTitle(String chosenLicense) {
LOG.debug("Requested license id");
// checks
checkNotNull(chosenLicense);
//retrieve the list of available licenses
List<CkanLicense> licenses = ckanCaller.getLicenseList();
for (CkanLicense ckanLicense : licenses) {
if(ckanLicense.getTitle().equals(chosenLicense))
return ckanLicense.getId();
}
return null;
}
@Override
public List<String> getLicenseTitles() {
LOG.debug("Request for CKAN licenses");
// get the url and the api key of the user
List<String> result = new ArrayList<String>();
//retrieve the list of available licenses
List<CkanLicense> licenses = ckanCaller.getLicenseList();
for (CkanLicense ckanLicense : licenses) {
result.add(ckanLicense.getTitle());
LOG.debug("License is " + ckanLicense.getTitle() + " and id " + ckanLicense.getId());
}
return result;
}
@Override
public List<CkanLicense> getLicenses() {
LOG.debug("Request for CKAN licenses (original jackan objects are going to be retrieved)");
//retrieve the list of available licenses
return ckanCaller.getLicenseList();
}
@Override
public CkanDataset getDataset(String datasetId, String apiKey) {
LOG.info("Request ckan dataset with id " + datasetId);
// checks
checkNotNull(datasetId);
checkArgument(!datasetId.isEmpty());
try{
if(apiKey!=null && !apiKey.isEmpty()) {
LOG.info("API-KEY found. Calling the "+ExtendCkanClient.class.getSimpleName());
ExtendCkanClient client = new ExtendCkanClient(CKAN_CATALOGUE_URL, apiKey);
return client.getDataset(datasetId);
}
String authzToken = SecurityTokenProvider.instance.get();
if(authzToken!=null && !authzToken.isEmpty()) {
LOG.info("gcube-token found. Calling the gCat client");
return gCatCaller.getDatasetForName(datasetId);
}
LOG.info("No api-key or gcube-token found. Calling Ckan Client without API-KEY");
return ckanCaller.getDataset(datasetId);
}catch(Exception e){
LOG.error("Unable to retrieve such dataset, returning null ...", e);
}
return null;
}
@Override
public String getUnencryptedUrlFromDatasetIdOrName(String datasetIdOrName) {
LOG.debug("Request coming for getting dataset url (not encrypted) of dataset with name/id " + datasetIdOrName);
// checks
checkNotNull(datasetIdOrName);
checkArgument(!datasetIdOrName.isEmpty());
String url = null;
try{
// get the dataset from name
ExtendCkanClient client = new ExtendCkanClient(CKAN_CATALOGUE_URL, CKAN_TOKEN_SYS);
CkanDataset dataset = client.getDataset(datasetIdOrName);
String name = dataset.getName();
if(dataset != null){
if(getUriResolverUrl() != null)
url = getUrlForProduct(CONTEXT, EntityContext.DATASET, name);
if(url == null || url.isEmpty())
url = getPortletUrl() + "?" + URLEncoder.encode("path=/dataset/" + name, "UTF-8");
}
}catch(Exception e){
LOG.error("Error while retrieving dataset with id/name=" + datasetIdOrName, e);
} //requestEntity.put("clear_url", Boolean.toString(unencrypted));
return url;
}
public String createCKanDatasetMultipleCustomFields(String title, String name, String organizationNameOrId,
String author, String authorMail, String maintainer, String maintainerMail, long version,
String description, String licenseId, List<String> tags, Map<String, List<String>> customFields,
List<ResourceBean> resources, boolean setPublic) throws Exception {
return null;
}
@Override
public Map<String, Map<CkanGroup, RolesCkanGroupOrOrg>> getUserRoleByGroup(
String username, String apiKey) {
checkNotNull(username);
checkNotNull(apiKey);
checkNotNull(username);
checkNotNull(apiKey);
Map<String, Map<CkanGroup, RolesCkanGroupOrOrg>> toReturn = new HashMap<String, Map<CkanGroup,RolesCkanGroupOrOrg>>();
try{
String ckanUsername = CatalogueUtilMethods.fromUsernameToCKanUsername(username);
Map<String, RolesCkanGroupOrOrg> partialResult = dbCaller.getGroupsByUserFromDB(ckanUsername);
for (String groupID : partialResult.keySet()) {
CkanGroup group = ckanCaller.getGroup(groupID);
HashMap<CkanGroup, RolesCkanGroupOrOrg> subMap = new HashMap<CkanGroup, RolesCkanGroupOrOrg>();
subMap.put(group, partialResult.get(groupID));
toReturn.put(groupID, subMap);
}
LOG.debug("Returning map " + toReturn);
}catch(Exception e){
LOG.error("Failed to retrieve roles of user in his/her own groups",e);
}
return toReturn;
}
/**
* Retrieve an url for the tuple scope, entity, entity name
* @param context
* @param entityContext
* @param entityName
*/
private String getUrlForProduct(String context, EntityContext entityContext, String entityName){
String toReturn = null;
try (CloseableHttpClient httpClient = HttpClientBuilder.create().build()) {
HttpPost httpPostRequest = new HttpPost(getUriResolverUrl());
JSONObject requestEntity = new JSONObject();
requestEntity.put("gcube_scope", context);
requestEntity.put("entity_context", entityContext.toString());
requestEntity.put("entity_name", entityName);
StringEntity params = new StringEntity(requestEntity.toJSONString(), ContentType.APPLICATION_JSON);
httpPostRequest.setEntity(params);
HttpResponse response = httpClient.execute(httpPostRequest);
if(response.getStatusLine().getStatusCode() != 200)
throw new Exception("There was an error while creating an url " + response.getStatusLine());
toReturn = EntityUtils.toString(response.getEntity());
LOG.debug("Result is " + toReturn);
}catch(Exception e){
LOG.error("Failed to get an url for this product", e);
}
return toReturn;
}
@Override
public String getUriResolverUrl() {
return URI_RESOLVER_URL;
}
/**
* Check if the manage product is enabled
* @return
*/
@Override
public boolean isManageProductEnabled() {
return MANAGE_PRODUCT_BUTTON;
}
@Override
public List<CkanOrganization> getOrganizationsByUser(String username) {
LOG.debug("Requested organizations for user " + username);
// checks
checkNotNull(username);
// in order to avoid errors, the username is always converted
String ckanUsername = CatalogueUtilMethods.fromUsernameToCKanUsername(username);
// list to return
List<CkanOrganization> toReturn = new ArrayList<CkanOrganization>();
try{
// get the list of all organizations
List<CkanOrganization> organizations = ckanCaller.getOrganizationList();
// iterate over them
for (CkanOrganization ckanOrganization : organizations) {
// get the list of users in it (if you try ckanOrganization.getUsers() it returns null.. maybe a bug TODO)
List<CkanUser> users = ckanCaller.getOrganization(ckanOrganization.getName()).getUsers();
// check if the current user is among them
for (CkanUser ckanUser : users) {
if(ckanUser.getName().equals(ckanUsername)){
LOG.debug("User " + ckanUsername + " is into " + ckanOrganization.getName());
toReturn.add(ckanOrganization);
break;
}
}
}
}catch(Exception e){
LOG.error("Unable to get user's organizations", e);
}
return toReturn;
}
@Override
public List<CkanGroup> getGroupsByUser(String username) {
LOG.debug("Requested groups for user " + username);
// checks
checkNotNull(username);
// in order to avoid errors, the username is always converted
String ckanUsername = CatalogueUtilMethods.fromUsernameToCKanUsername(username);
// list to return
List<CkanGroup> toReturn = new ArrayList<CkanGroup>();
try{
// get the list of all organizations
List<CkanGroup> groups = ckanCaller.getGroupList();
// iterate over them
for (CkanGroup ckanGroup : groups) {
List<CkanUser> users = ckanCaller.getGroup(ckanGroup.getName()).getUsers();
// check if the current user is among them
for (CkanUser ckanUser : users) {
if(ckanUser.getName().equals(ckanUsername)){
LOG.debug("User " + ckanUsername + " is into " + ckanGroup.getName());
toReturn.add(ckanGroup);
break;
}
}
}
}catch(Exception e){
LOG.error("Unable to get user's groups", e);
}
return toReturn;
}
//@Override
private String getApiKeyFromUsername(String username) {
LOG.debug("Request api key for user = " + username);
// checks
checkNotNull(username);
checkArgument(!username.isEmpty());
// in order to avoid errors, the username is always converted
String ckanUsername = CatalogueUtilMethods.fromUsernameToCKanUsername(username);
// check in the hashmap first
if(apiKeysMap.containsKey(ckanUsername)){
CKANTokenBean bean = apiKeysMap.get(ckanUsername);
if(bean.timestamp + EXPIRE_KEY_TIME > System.currentTimeMillis()){ // it's still ok
return bean.apiKey;
}
}
LOG.debug("Api key was not in cache or it expired");
try{
String apiToReturn = dbCaller.getApiKeyFromUsername(username, State.ACTIVE.name().toLowerCase());
// save into the hashmap
if(apiToReturn != null)
apiKeysMap.put(ckanUsername, new CKANTokenBean(apiToReturn, System.currentTimeMillis()));
return apiToReturn;
}catch(Exception e){
LOG.error("Unable to retrieve key for user " + ckanUsername, e);
}
return null;
}
/*
*
*
*
*
*
*
*
*
*
* WRITE OPERATIONS
*
*
*
*
*
*
*
*
*
*
*/
public boolean patchProductCustomFields(String productId, Map<String, List<String>> customFieldsToChange,
boolean removeOld) {
return false;
}
public String addResourceToDataset(ResourceBean resource) throws Exception {
return null;
}
public boolean deleteResourceFromDataset(String resourceId) {
return false;
}
public boolean existProductWithNameOrId(String nameOrId) {
return false;
}
}

View File

@ -0,0 +1,690 @@
package org.gcube.datacatalogue.ckanutillibrary.server;
import static org.gcube.resources.discovery.icclient.ICFactory.client;
import static org.gcube.resources.discovery.icclient.ICFactory.clientFor;
import static org.gcube.resources.discovery.icclient.ICFactory.queryFor;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.gcube.common.encryption.StringEncrypter;
import org.gcube.common.resources.gcore.ServiceEndpoint;
import org.gcube.common.resources.gcore.ServiceEndpoint.AccessPoint;
import org.gcube.common.resources.gcore.ServiceEndpoint.Property;
import org.gcube.common.resources.gcore.utils.XPathHelper;
import org.gcube.common.scope.api.ScopeProvider;
import org.gcube.datacatalogue.ckanutillibrary.shared.ex.ApplicationProfileNotFoundException;
import org.gcube.datacatalogue.ckanutillibrary.shared.ex.NoApplicationProfileMasterException;
import org.gcube.datacatalogue.ckanutillibrary.shared.ex.NoDataCatalogueRuntimeResourceException;
import org.gcube.datacatalogue.ckanutillibrary.shared.ex.ServiceEndPointException;
import org.gcube.resources.discovery.client.api.DiscoveryClient;
import org.gcube.resources.discovery.client.queries.api.Query;
import org.gcube.resources.discovery.client.queries.api.SimpleQuery;
import org.gcube.resources.discovery.client.queries.impl.QueryBox;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
/**
* Retrieve ckan running instance information in the infrastructure (for both its database and data catalogue url).
*
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
* updated by Francesco Mangiacrapa at ISTI-CNR (francesco.mangiacrapa@isti.cnr.it)
*/
public class DataCatalogueRunningCluster {
//logger
private static final Logger logger = LoggerFactory.getLogger(DataCatalogueRunningCluster.class);
// database of the datacatalogue info
private final static String RUNTIME_DB_RESOURCE_NAME = "CKanDatabase";
private final static String PLATFORM_DB_NAME = "postgres";
private final static String APPLICATION_PROFILE_NAME = "CkanPortlet";
// data catalogue info
private final static String RUNTIME_CATALOGUE_RESOURCE_NAME = "CKanDataCatalogue";
private final static String PLATFORM_CATALOGUE_NAME = "Tomcat";
// api key property for SYSADMIN
private final static String API_KEY_PROPERTY = "API_KEY";
// catalogue email
private final static String CKAN_EMAIL_PROPERTY = "CATALOGUE_EMAIL";
// property to retrieve the master service endpoint into the /root scope
private final static String IS_MASTER_ROOT_KEY_PROPERTY = "IS_ROOT_MASTER"; // true, false.. missing means false as well
private final static String IS_MANAGE_PRODUCT_ENABLED = "IS_MANAGE_PRODUCT_ENABLED"; // true, false.. missing means false as well (for GRSF records)
private final static String SOCIAL_POST = "SOCIAL_POST";
private final static String ALERT_USERS_ON_POST_CREATION = "ALERT_USERS_ON_POST_CREATION";
private final static String SOLR_INDEX_ADDRESS = "SOLR_INDEX_ADDRESS";
// url of the http uri for this scope
private final static String URL_RESOLVER = "URL_RESOLVER";
// Other generic resource for delegating roles in groups to users
private final static String CATALOGUE_EXTENDING_ROLES = "CatalogueDelegateRoles";
// retrieved data
private List<String> datacatalogueUrls = new ArrayList<String>();
private List<String> hostsDB = new ArrayList<String>();
private List<Integer> portsDB = new ArrayList<Integer>();
private String nameDB;
private String userDB;
private String passwordDB;
private String portletUrl;
private String urlSolr;
private boolean manageProductEnabled;
private String urlResolver;
private boolean socialPost;
private boolean alertUsers;
private Map<String, String> extendRoleInOrganization = new HashMap<String, String>(0);
// generic role key
public static final String CKAN_GENERIC_ROLE = "*";
public static final String ROLE_ORGANIZATION_SEPARATOR = "|";
public static final String TUPLES_SEPARATOR = ",";
private static final String DEFAULT_CATALOGUE_EMAIL = "catalogue@d4science.org";
/**
* The Enum ACCESS_LEVEL_TO_CATALOGUE_PORTLET.
*
* @author Francesco Mangiacrapa at ISTI-CNR (francesco.mangiacrapa@isti.cnr.it)
*
* Nov 12, 2019
*/
//Added by Francesco, see #18039
public static final String PUBLIC_VRE_CATALOGUE_URL = "public-vre-url";
public static enum ACCESS_LEVEL_TO_CATALOGUE_PORTLET {PUBLIC_GATEWAY, PUBLIC_VRE, PRIVATE_VRE};
public Map<ACCESS_LEVEL_TO_CATALOGUE_PORTLET, String> mapAccessURLToCatalogue;
// this token is needed in order to assign roles to user
private String sysAdminToken;
private String catalogueEmail;
/**
* Instantiates a new data catalogue running cluster.
*
* @param scope the scope
* @throws Exception the exception
*/
public DataCatalogueRunningCluster(String scope) throws Exception{
if(scope == null || scope.isEmpty())
throw new Exception("Invalid scope!!");
// retrieve the current scope and save it (it will be reset later)
String currentScope = ScopeProvider.instance.get();
logger.info("Retrieving ckan database service end point information for scope " + scope);
try {
// set the scope
ScopeProvider.instance.set(scope);
logger.debug("Retrieving database information.");
List<ServiceEndpoint> resources = getConfigurationFromISFORDB();
evaluateRightConfigurationDB(resources);
logger.debug("Retrieving ckan data catalogue service end point information and sysadmin token.");
resources = getConfigurationFromISFORCatalogueUrl();
evaluateRightConfigurationCatalogue(resources);
// finally get the url in which the ckan portlet is deployed
logger.debug("Looking for portlet url in " + ScopeProvider.instance.get() + " scope" );
//portletUrl = getPortletUrlFromInfrastrucure();
mapAccessURLToCatalogue = getPortletUrlFromInfrastrucure();
portletUrl = mapAccessURLToCatalogue.get(ACCESS_LEVEL_TO_CATALOGUE_PORTLET.PRIVATE_VRE);
// and parse the CatalogueDelegateRole resource, if any, in this context
parseExtendingRoles();
}catch(Exception e) {
logger.warn("The following error occurred: " + e.toString());
throw e;
}finally{
ScopeProvider.instance.set(currentScope);
}
}
/**
* Evaluate the right configuration about ckan.
*
* @param resources the resources
* @throws NoDataCatalogueRuntimeResourceException the no data catalogue runtime resource exception
* @throws ServiceEndPointException the service end point exception
*/
private void evaluateRightConfigurationCatalogue(
List<ServiceEndpoint> resources) throws NoDataCatalogueRuntimeResourceException, ServiceEndPointException {
if (resources.size() == 0){
logger.error("There is no Runtime Resource having name " + RUNTIME_CATALOGUE_RESOURCE_NAME +" and Platform " + PLATFORM_CATALOGUE_NAME + " in this scope.");
throw new NoDataCatalogueRuntimeResourceException();
}
else {
logger.debug(resources.toString());
try{
if(resources.size() > 1){
boolean oneWasMaster = false;
logger.info("Too many Runtime Resource having name " + RUNTIME_CATALOGUE_RESOURCE_NAME +" in this scope.. Looking for the one that has the property " + IS_MASTER_ROOT_KEY_PROPERTY);
for (ServiceEndpoint res : resources) {
Iterator<AccessPoint> accessPointIterator = res.profile().accessPoints().iterator();
while (accessPointIterator.hasNext()) {
ServiceEndpoint.AccessPoint accessPoint = accessPointIterator
.next();
// get the is master property
Property entry = accessPoint.propertyMap().get(IS_MASTER_ROOT_KEY_PROPERTY);
String isMaster = entry != null ? entry.value() : null;
if(isMaster == null || !isMaster.equals("true"))
continue;
// set this variable
oneWasMaster = true;
// add this host
datacatalogueUrls.add(accessPoint.address());
// retrieve sys admin token
sysAdminToken = accessPoint.propertyMap().get(API_KEY_PROPERTY).value();
sysAdminToken = StringEncrypter.getEncrypter().decrypt(sysAdminToken);
// retrieve catalogue email
if(accessPoint.propertyMap().containsKey(CKAN_EMAIL_PROPERTY)){
catalogueEmail = accessPoint.propertyMap().get(CKAN_EMAIL_PROPERTY).value();
catalogueEmail = StringEncrypter.getEncrypter().decrypt(catalogueEmail);
}
// retrieve URL_RESOLVER
if(accessPoint.propertyMap().containsKey(URL_RESOLVER))
urlResolver = accessPoint.propertyMap().get(URL_RESOLVER).value();
// break now
break;
}
}
// if none of them was master, throw an exception
if(!oneWasMaster)
throw new NoApplicationProfileMasterException("There is no application profile with MASTER property");
}else{
ServiceEndpoint res = resources.get(0);
Iterator<AccessPoint> accessPointIterator = res.profile().accessPoints().iterator();
while (accessPointIterator.hasNext()) {
ServiceEndpoint.AccessPoint accessPoint = accessPointIterator
.next();
// add this host
datacatalogueUrls.add(accessPoint.address());
// retrieve sys admin token
sysAdminToken = accessPoint.propertyMap().get(API_KEY_PROPERTY).value();
sysAdminToken = StringEncrypter.getEncrypter().decrypt(sysAdminToken);
// retrieve catalogue email
if(accessPoint.propertyMap().containsKey(CKAN_EMAIL_PROPERTY)){
catalogueEmail = accessPoint.propertyMap().get(CKAN_EMAIL_PROPERTY).value();
catalogueEmail = StringEncrypter.getEncrypter().decrypt(catalogueEmail);
}
// get the is manage product property
Property entry = accessPoint.propertyMap().get(IS_MANAGE_PRODUCT_ENABLED);
String isManageProduct = entry != null ? entry.value() : null;
if(isManageProduct != null && isManageProduct.equals("true")){
logger.info("Manage product is enabled in this scope");
manageProductEnabled = true;
}
// retrieve option to check if the social post has to be made
socialPost = true; // default is true
if(accessPoint.propertyMap().containsKey(SOCIAL_POST))
if(accessPoint.propertyMap().get(SOCIAL_POST).value().trim().equalsIgnoreCase("false"))
socialPost = false;
// retrieve option for user alert
if(accessPoint.propertyMap().containsKey(ALERT_USERS_ON_POST_CREATION))
if(accessPoint.propertyMap().get(ALERT_USERS_ON_POST_CREATION).value().trim().equalsIgnoreCase("true"))
alertUsers = true;
// retrieve URL_RESOLVER
if(accessPoint.propertyMap().containsKey(URL_RESOLVER))
urlResolver = accessPoint.propertyMap().get(URL_RESOLVER).value();
// retrieve url of the solr index for further queries
if(accessPoint.propertyMap().containsKey(SOLR_INDEX_ADDRESS))
urlSolr = accessPoint.propertyMap().get(SOLR_INDEX_ADDRESS).value();
}
}
}catch(Exception e){
throw new ServiceEndPointException("There is no service end point for such information" + e.toString());
}
}
}
/**
* Retrieve the right DB information.
*
* @param resources the resources
* @throws ServiceEndPointException the service end point exception
* @throws NoDataCatalogueRuntimeResourceException the no data catalogue runtime resource exception
*/
private void evaluateRightConfigurationDB(List<ServiceEndpoint> resources) throws ServiceEndPointException, NoDataCatalogueRuntimeResourceException {
if (resources.size() == 0){
throw new NoDataCatalogueRuntimeResourceException("There is no Runtime Resource having name " + RUNTIME_DB_RESOURCE_NAME +" and Platform " + PLATFORM_DB_NAME + " in this scope.");
}
else {
try{
if(resources.size() > 1){
boolean oneWasMaster = false;
logger.info("Too many Runtime Resource having name " + RUNTIME_DB_RESOURCE_NAME +" in this scope.. Looking for the one that has the property " + IS_MASTER_ROOT_KEY_PROPERTY);
for (ServiceEndpoint res : resources) {
Iterator<AccessPoint> accessPointIterator = res.profile().accessPoints().iterator();
while (accessPointIterator.hasNext()) {
ServiceEndpoint.AccessPoint accessPoint = accessPointIterator
.next();
// get the is master property
Property entry = accessPoint.propertyMap().get(IS_MASTER_ROOT_KEY_PROPERTY);
String isMaster = entry != null ? entry.value() : null;
if(isMaster == null || !isMaster.equals("true"))
continue;
// set this variable
oneWasMaster = true;
// add this host
hostsDB.add(accessPoint.address().split(":")[0]);
// save the port
int port = Integer.parseInt(accessPoint.address().split(":")[1]);
portsDB.add(port);
// save the name of the cluster (this should be unique)
nameDB = accessPoint.name();
// save user and password
passwordDB = StringEncrypter.getEncrypter().decrypt(accessPoint.password());
userDB = accessPoint.username();
// now break
break;
}
}
// if none of them was master, throw an exception
if(!oneWasMaster)
throw new NoApplicationProfileMasterException("There is no application profile with MASTER property");
}else{
logger.debug(resources.toString());
ServiceEndpoint res = resources.get(0);
Iterator<AccessPoint> accessPointIterator = res.profile().accessPoints().iterator();
while (accessPointIterator.hasNext()) {
ServiceEndpoint.AccessPoint accessPoint = accessPointIterator
.next();
// add this host
hostsDB.add(accessPoint.address().split(":")[0]);
// save the port
int port = Integer.parseInt(accessPoint.address().split(":")[1]);
portsDB.add(port);
// save the name of the cluster (this should be unique)
nameDB = accessPoint.name();
// save user and password
passwordDB = StringEncrypter.getEncrypter().decrypt(accessPoint.password());
userDB = accessPoint.username();
}
}
}catch(Exception e ){
throw new ServiceEndPointException(e.toString());
}
}
}
/**
* Retrieve endpoints information from IS for DB.
*
* @return list of endpoints for ckan database
* @throws Exception the exception
*/
private static List<ServiceEndpoint> getConfigurationFromISFORDB() throws Exception{
SimpleQuery query = queryFor(ServiceEndpoint.class);
query.addCondition("$resource/Profile/Name/text() eq '"+ RUNTIME_DB_RESOURCE_NAME +"'");
query.addCondition("$resource/Profile/Platform/Name/text() eq '"+ PLATFORM_DB_NAME +"'");
DiscoveryClient<ServiceEndpoint> client = clientFor(ServiceEndpoint.class);
List<ServiceEndpoint> toReturn = client.submit(query);
return toReturn;
}
/**
* Retrieve endpoints information from IS for DataCatalogue URL.
*
* @return list of endpoints for ckan data catalogue
* @throws Exception the exception
*/
private static List<ServiceEndpoint> getConfigurationFromISFORCatalogueUrl() throws Exception{
SimpleQuery query = queryFor(ServiceEndpoint.class);
query.addCondition("$resource/Profile/Name/text() eq '"+ RUNTIME_CATALOGUE_RESOURCE_NAME +"'");
query.addCondition("$resource/Profile/Platform/Name/text() eq '"+ PLATFORM_CATALOGUE_NAME +"'");
DiscoveryClient<ServiceEndpoint> client = clientFor(ServiceEndpoint.class);
List<ServiceEndpoint> toReturn = client.submit(query);
return toReturn;
}
/**
* Retrieve the url of the ckan portlet deployed into this scope
* updated by Francesco see Feature #18039.
*
* @return the portlet url from infrastrucure
*/
private static Map<ACCESS_LEVEL_TO_CATALOGUE_PORTLET,String> getPortletUrlFromInfrastrucure() {
String scope = ScopeProvider.instance.get();
logger.debug("Trying to fetch applicationProfile profile from the infrastructure for " + APPLICATION_PROFILE_NAME + " scope: " + scope);
Map<ACCESS_LEVEL_TO_CATALOGUE_PORTLET,String> mapAccess = new HashMap<ACCESS_LEVEL_TO_CATALOGUE_PORTLET,String>(3);
try {
Query q = new QueryBox("for $profile in collection('/db/Profiles/GenericResource')//Resource " +
"where $profile/Profile/SecondaryType/string() eq 'ApplicationProfile' and $profile/Profile/Name/string() " +
" eq '" + APPLICATION_PROFILE_NAME + "'" +
"return $profile");
DiscoveryClient<String> client = client();
List<String> appProfile = client.submit(q);
if (appProfile == null || appProfile.size() == 0)
throw new ApplicationProfileNotFoundException("Your applicationProfile is not registered in the infrastructure");
else {
String elem = appProfile.get(0);
DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Node node = docBuilder.parse(new InputSource(new StringReader(elem))).getDocumentElement();
XPathHelper helper = new XPathHelper(node);
List<String> currValue = null;
currValue = helper.evaluate("/Resource/Profile/Body/url/text()");
if (currValue != null && currValue.size() > 0) {
logger.debug("Private portlet url found is " + currValue.get(0));
//return currValue.get(0);
mapAccess.put(ACCESS_LEVEL_TO_CATALOGUE_PORTLET.PRIVATE_VRE, currValue.get(0));
}
currValue = null;
currValue = helper.evaluate("/Resource/Profile/Body/"+PUBLIC_VRE_CATALOGUE_URL+"/text()");
if (currValue != null && currValue.size() > 0) {
logger.debug(PUBLIC_VRE_CATALOGUE_URL+" portlet url found is " + currValue.get(0));
//return currValue.get(0);
mapAccess.put(ACCESS_LEVEL_TO_CATALOGUE_PORTLET.PUBLIC_VRE, currValue.get(0));
}
}
} catch (Exception e) {
logger.error("Error while trying to fetch applicationProfile profile from the infrastructure", e);
}
return mapAccess;
}
/**
* Parse the CatalogueDelegateRoles in this context.
*
* @throws ParserConfigurationException the parser configuration exception
* @throws SAXException the SAX exception
* @throws IOException Signals that an I/O exception has occurred.
*/
private void parseExtendingRoles() throws ParserConfigurationException, SAXException, IOException {
Query q = new QueryBox("for $profile in collection('/db/Profiles/GenericResource')//Resource " +
"where $profile/Profile/SecondaryType/string() eq 'ApplicationProfile' and $profile/Profile/Name/string() " +
" eq '" + CATALOGUE_EXTENDING_ROLES + "'" +
"return $profile");
DiscoveryClient<String> client = client();
List<String> appProfile = client.submit(q);
logger.debug("Resource for extending role has size " + appProfile.size());
if (appProfile == null || appProfile.size() == 0)
return;
else {
String profile = appProfile.get(0);
DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Node node = docBuilder.parse(new InputSource(new StringReader(profile))).getDocumentElement();
XPathHelper helper = new XPathHelper(node);
// fetch delegate elements
NodeList delegates = helper.evaluateForNodes("/Resource/Profile/Body/delegates/delegate");
if (delegates != null && delegates.getLength() > 0) {
for(int i = 0; i < delegates.getLength(); i++){
Node nodeI = delegates.item(i);
if(nodeI.getNodeType() == Node.ELEMENT_NODE) {
Element elem = (Element)nodeI;
String role = elem.getElementsByTagName("sourceRole").item(0).getTextContent();
String destOrg = elem.getElementsByTagName("destOrganization").item(0).getTextContent();
String sourceOrg = elem.getElementsByTagName("sourceOrganization").item(0).getTextContent();
if(destOrg == null || sourceOrg == null){
logger.warn("DestOrg or SourceOrg parameters missing");
continue;
}else{
String currentValueForKey = extendRoleInOrganization.get(sourceOrg);
if(currentValueForKey == null)
currentValueForKey = "";
else
currentValueForKey += TUPLES_SEPARATOR;
currentValueForKey += destOrg + ROLE_ORGANIZATION_SEPARATOR + role;
extendRoleInOrganization.put(sourceOrg, currentValueForKey);
}
}
}
}
}
logger.debug("Extended role map in this scope is " + extendRoleInOrganization);
}
/**
* Retrieve the ckan portlet url.
*
* @return the portletUrl
*/
public String getPortletUrl() {
return portletUrl;
}
/**
* Retrieve data catalogue url.
*
* @return the data catalogue url
*/
public List<String> getDataCatalogueUrl() {
return datacatalogueUrls;
}
/**
* Get the hosts for such resource.
*
* @return the database hosts
*/
public List<String> getDatabaseHosts() {
return hostsDB;
}
/**
* Get the ports for such resource.
*
* @return the database ports
*/
public List<Integer> getDatabasePorts() {
return portsDB;
}
/**
* Get the database name.
*
* @return the data base name
*/
public String getDataBaseName() {
return nameDB;
}
/**
* Get the database's user.
*
* @return the data base user
*/
public String getDataBaseUser() {
return userDB;
}
/**
* Get the database's password.
*
* @return the data base password
*/
public String getDataBasePassword() {
return passwordDB;
}
/**
* Gets the sys admin token.
*
* @return the sysAdminToken
*/
public String getSysAdminToken() {
return sysAdminToken;
}
/**
* Is manager product enabled (e.g., for GRSF records)
*
* @return true, if is manage product enabled
*/
public boolean isManageProductEnabled() {
return manageProductEnabled;
}
/**
* Get the url of the uri resolver for this instance/scope.
*
* @return the url resolver
*/
public String getUrlResolver() {
return urlResolver;
}
/**
* Check if alert user members is enabled.
*
* @return true, if is alert enabled
*/
public boolean isAlertEnabled() {
return alertUsers;
}
/**
* Get roles to extend.
*
* @return Map<String, String>
*/
public Map<String, String> getExtendRoleInOrganization() {
return extendRoleInOrganization;
}
/**
* Get the solr index base url.
*
* @return the url solr
*/
public String getUrlSolr() {
return urlSolr;
}
/**
* Gets the map access URL to catalogue.
*
* @return the map access URL to catalogue
*/
public Map<ACCESS_LEVEL_TO_CATALOGUE_PORTLET, String> getMapAccessURLToCatalogue() {
return mapAccessURLToCatalogue;
}
/**
* Get the catalogue email. Default is "catalogue@d4science.org"
*
* @return the email catalogue
*/
public String getEmailCatalogue() {
logger.debug("Read email from resource is " + catalogueEmail);
return catalogueEmail == null? DEFAULT_CATALOGUE_EMAIL : catalogueEmail;
}
/**
* Checks if is social post enabled.
*
* @return true, if is social post enabled
*/
public boolean isSocialPostEnabled() {
return socialPost;
}
}

View File

@ -0,0 +1,139 @@
package org.gcube.datacatalogue.ckanutillibrary.server.utils;
import java.net.HttpURLConnection;
import java.net.URL;
import org.gcube.common.scope.api.ScopeProvider;
import org.gcube.common.scope.impl.ScopeBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Some utility methods used within the library.
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
*/
public class CatalogueUtilMethods {
private static final Logger logger = LoggerFactory.getLogger(CatalogueUtilMethods.class);
private final static String HTTPS = "https";
private final static String HTTP = "http";
/**
* Maps the scope name to the ckan organization name
* Use getCKANOrganization() which uses current scope
* @return
*/
@Deprecated
public static String getOrganizationNameFromScope(String scope){
if(scope == null || scope.isEmpty()) {
throw new IllegalArgumentException("scope cannot be null");
}
ScopeBean scopeBean = new ScopeBean(scope);
return scopeBean.name().toLowerCase().replace(" ", "_").replace("-", "_");
}
/**
* Get CKAN Organization name by using scope name
*
*/
public static String getCKANOrganization() {
ScopeBean scopeBean = new ScopeBean(ScopeProvider.instance.get());
return scopeBean.name().toLowerCase().replace(" ", "_").replace("-", "_");
}
/**
* Ckan username has _ instead of . (that is, costantino.perciante -> costantino_perciante)
* @param owner
* @return
*/
public static String fromUsernameToCKanUsername(String username){
if(username == null)
return null;
return username.trim().replaceAll("\\.", "_");
}
/**
* Liferay username has . instead of _ (that is, costantino_perciante -> costantino.perciante)
* @param owner
* @return
*/
public static String fromCKanUsernameToUsername(String ckanUsername){
if(ckanUsername == null)
return null;
return ckanUsername.trim().replaceAll("_", ".");
}
/**
* Generate the catalogue's dataset name from its title
* @param title
* @return
*/
public static String fromProductTitleToName(String title) {
if(title == null)
return null;
String regexTitleNameTransform = "[^A-Za-z0-9_-]";
return title.trim().replaceAll(regexTitleNameTransform, "_").replaceAll("_+", "_").toLowerCase();
}
/**
* Convert a display group name to group id
* @param groupName
* @return
*/
public static String fromGroupTitleToName(String groupName){
if(groupName == null)
return null;
String regexGroupNameTransform = "[^A-Za-z0-9-]";
String modified = groupName.trim().replaceAll(regexGroupNameTransform, "-").replaceAll("-+", "-").toLowerCase();
if(modified.startsWith("-"))
modified = modified.substring(1);
if(modified.endsWith("-"))
modified = modified.substring(0, modified.length() -1);
return modified;
}
/**
* Utility method to check if a something at this url actually exists
* @param URLName
* @return
*/
public static boolean resourceExists(String URLName){
if(URLName == null || URLName.isEmpty())
return false;
try {
// replace https
String urlToTest = URLName.replace(HTTPS, HTTP);
HttpURLConnection.setFollowRedirects(true);
HttpURLConnection con = (HttpURLConnection) new URL(urlToTest).openConnection();
con.setRequestMethod("HEAD");
logger.debug("Return code is " + con.getResponseCode());
return (con.getResponseCode() == HttpURLConnection.HTTP_OK);
}
catch (Exception e) {
logger.error("Exception while checking url", e);
return false;
}
}
/**
* Builds a string made of key + scope
* @param key
* @param scope
* @return
*/
public static String concatenateSessionKeyScope(String key, String scope){
if(key == null || scope == null)
throw new IllegalArgumentException("Key or scope null");
return key.concat(scope);
}
}

View File

@ -0,0 +1,17 @@
package org.gcube.datacatalogue.ckanutillibrary.server.utils;
/**
* A list of attributes that are saved into http session.
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
*/
public class SessionCatalogueAttributes {
// CKAN KEYS (PLEASE NOTE THAT MOST OF THESE INFO ARE SAVED INTO SESSION PER SCOPE)
public static final String CKAN_ORGS_USER_KEY = "ckanOrgs"; // organizations to whom he belongs (shown into the portlet)
public static final String CKAN_HIGHEST_ROLE = "ckanHighestRole"; // editor, member, admin
public static final String CKAN_ORGANIZATIONS_PUBLISH_KEY = "ckanOrganizationsPublish"; // here he can publish (admin/editor role)
public static final String CKAN_LICENSES_KEY = "ckanLicenses"; // licenses
public static final String CKAN_PROFILES_KEY = "ckanProfiles"; // product profiles
public static final String CKAN_GROUPS_MEMBER = "ckanGroupsMember";
public static final String CKAN_GROUPS_USER_KEY = "ckanGroups"; // to show the list of groups in the portlet
}

View File

@ -0,0 +1,24 @@
package org.gcube.datacatalogue.ckanutillibrary.server.utils.url;
/**
* Entity context for uri resolver
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
*/
public enum EntityContext {
DATASET("dataset"),
GROUP("group"),
ORGANIZATION("organization");
private String entityAsString;
private EntityContext(String entityAsString) {
this.entityAsString = entityAsString;
}
@Override
public String toString() {
return this.entityAsString;
}
}

View File

@ -0,0 +1,134 @@
package org.gcube.datacatalogue.ckanutillibrary.shared;
import java.io.Serializable;
/**
* A CKan user.
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
*/
public class CKanUserWrapper implements Serializable{
private static final long serialVersionUID = 6264706263035722775L;
private String id;
private String name;
private String apiKey;
private long creationTimestamp;
private String about;
private String openId;
private String fullName;
private String email;
private boolean isAdmin;
public CKanUserWrapper() {
super();
}
/** Create a ckan user object.
* @param id
* @param name
* @param apiKey
* @param creationTimestamp
* @param about
* @param openId
* @param fullName
* @param email
* @param isAdmin
*/
public CKanUserWrapper(String id, String name, String apiKey,
long creationTimestamp, String about, String openId,
String fullName, String email, boolean isAdmin) {
super();
this.id = id;
this.name = name;
this.apiKey = apiKey;
this.creationTimestamp = creationTimestamp;
this.about = about;
this.openId = openId;
this.fullName = fullName;
this.email = email;
this.isAdmin = isAdmin;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getApiKey() {
return apiKey;
}
public void setApiKey(String apiKey) {
this.apiKey = apiKey;
}
public long getCreationTimestamp() {
return creationTimestamp;
}
public void setCreationTimestamp(long creationTimestamp) {
this.creationTimestamp = creationTimestamp;
}
public String getAbout() {
return about;
}
public void setAbout(String about) {
this.about = about;
}
public String getOpenId() {
return openId;
}
public void setOpenId(String openId) {
this.openId = openId;
}
public String getFullName() {
return fullName;
}
public void setFullName(String fullName) {
this.fullName = fullName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public boolean isAdmin() {
return isAdmin;
}
public void setAdmin(boolean isAdmin) {
this.isAdmin = isAdmin;
}
@Override
public String toString() {
return "CKanUserExtended [id=" + id + ", name=" + name + ", apiKey=" + apiKey.substring(0, 5) + "****************"
+ ", creationTimestamp=" + creationTimestamp + ", about="
+ about + ", openId=" + openId + ", fullName=" + fullName
+ ", email=" + email + ", isAdmin=" + isAdmin + "]";
}
}

View File

@ -0,0 +1,96 @@
package org.gcube.datacatalogue.ckanutillibrary.shared;
import static com.google.common.base.Preconditions.checkNotNull;
import org.json.simple.JSONObject;
/**
* A ckan dataset relationship. It is represented by the following fields
* <ul>
* <li> subject dataset id
* <li> object dataset id
* <li> type of the relationship
* <li> comment an optional comment
* </ul>
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
*/
public class CkanDatasetRelationship {
private String subject;
private String object;
private String comment;
private String type;
public CkanDatasetRelationship(){
super();
}
/**
* @param subject
* @param object
* @param comment
* @param type
*/
public CkanDatasetRelationship(String subject, String object,
String comment, String type) {
super();
this.subject = subject;
this.object = object;
this.comment = comment;
this.type = type;
}
/**
* From a json object that must have the properties listed in the class header (comment is optional)
* @param object
*/
public CkanDatasetRelationship(JSONObject object) {
this.comment = (String) object.get("comment");
this.object = (String) object.get("object");
this.subject = (String) object.get("subject");
this.type = (String) object.get("type"); // TODO convert to one of enums DatasetRelationships
checkNotNull(object);
checkNotNull(subject);
checkNotNull(type);
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public String getObject() {
return object;
}
public void setObject(String object) {
this.object = object;
}
public String getComment() {
return comment;
}
public void setComment(String comment) {
this.comment = comment;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
@Override
public String toString() {
return "CkanDatasetRelationship [subject=" + subject + ", object="
+ object + ", comment=" + comment + ", type=" + type
+ "]";
}
}

View File

@ -0,0 +1,27 @@
package org.gcube.datacatalogue.ckanutillibrary.shared;
/**
* Allowed relationships between packages(datasets). Some of them are not supported yet due to the problem
* reported here https://support.d4science.org/issues/4455
* <ul>
* <li> depends_on
* <li> dependency_of
* <li> derives_from
* <li> has_derivation
* <li> child_of
* <li> parent_of
* <li> links_to
* <li> linked_from
* </ul>
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
*/
public enum DatasetRelationships {
depends_on,
dependency_of,
derives_from,
has_derivation,
child_of,
parent_of,
links_to,
linked_from
}

View File

@ -0,0 +1,57 @@
package org.gcube.datacatalogue.ckanutillibrary.shared;
import java.io.Serializable;
/**
* This bean offers the following information:
* <ul>
* <li> landing page url to the items page (within the portlet)
* <li> landing page url to the orgs page (within the portlet)
* <li> landing page url to the groups page (within the portlet)
* <li> landing page url to the types page (within the portlet)
* </ul>
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
*/
public class LandingPages implements Serializable {
private static final long serialVersionUID = -5617896049674346109L;
private String urlTypes;
private String urlOrganizations;
private String urlGroups;
private String urlItems;
public LandingPages() {
super();
}
public String getUrlTypes() {
return urlTypes;
}
public void setUrlTypes(String urlTypes) {
this.urlTypes = urlTypes;
}
public String getUrlOrganizations() {
return urlOrganizations;
}
public void setUrlOrganizations(String urlOrganizations) {
this.urlOrganizations = urlOrganizations;
}
public String getUrlGroups() {
return urlGroups;
}
public void setUrlGroups(String urlGroups) {
this.urlGroups = urlGroups;
}
public String getUrlItems() {
return urlItems;
}
public void setUrlItems(String urlItems) {
this.urlItems = urlItems;
}
@Override
public String toString() {
return "LandingPages [urlTypes=" + urlTypes + ", urlOrganizations="
+ urlOrganizations + ", urlGroups=" + urlGroups + ", urlItems="
+ urlItems + "]";
}
}

View File

@ -0,0 +1,152 @@
package org.gcube.datacatalogue.ckanutillibrary.shared;
import java.io.Serializable;
/**
* A bean that resembles the CKanResource bean object
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
*/
public class ResourceBean implements Serializable {
private static final long serialVersionUID = -5275448097250176185L;
private String url;
private String name;
private String description;
private String id;
private String owner;
private String datasetId;
private String mimeType;
public ResourceBean(){
super();
}
/**
* @param url
* @param name
* @param description
* @param id
* @param owner
* @param datasetId
* @param mimeType
*/
public ResourceBean(String url, String name, String description, String id,
String owner, String datasetId, String mimeType) {
super();
this.url = url;
this.name = name;
this.description = description;
this.id = id;
this.owner = owner;
this.datasetId = datasetId;
this.mimeType = mimeType;
}
/**
* @return the url
*/
public String getUrl() {
return url;
}
/**
* @param url the url to set
*/
public void setUrl(String url) {
this.url = url;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the description
*/
public String getDescription() {
return description;
}
/**
* @param description the description to set
*/
public void setDescription(String description) {
this.description = description;
}
/**
* @return the id
*/
public String getId() {
return id;
}
/**
* @param id the id to set
*/
public void setId(String id) {
this.id = id;
}
/**
* @return the owner
*/
public String getOwner() {
return owner;
}
/**
* @param owner the owner to set
*/
public void setOwner(String owner) {
this.owner = owner;
}
/**
* @return the datasetId
*/
public String getDatasetId() {
return datasetId;
}
/**
* @param datasetId the datasetId to set
*/
public void setDatasetId(String datasetId) {
this.datasetId = datasetId;
}
/**
* @return the mimeType
*/
public String getMimeType() {
return mimeType;
}
/**
* @param mimeType the mimeType to set
*/
public void setMimeType(String mimeType) {
this.mimeType = mimeType;
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "ResourceBean [url=" + url + ", name=" + name + ", description="
+ description + ", id=" + id + ", owner=" + owner
+ ", datasetId=" + datasetId + ", mimeType=" + mimeType + "]";
}
}

View File

@ -0,0 +1,39 @@
package org.gcube.datacatalogue.ckanutillibrary.shared;
/**
* Roles that user can have into organizations/groups.
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
*/
public enum RolesCkanGroupOrOrg{
MEMBER,
EDITOR,
ADMIN;
public static String convertToCkanCapacity(RolesCkanGroupOrOrg role){
if(role == null)
return null;
else
return role.toString().toLowerCase();
}
public static RolesCkanGroupOrOrg convertFromCapacity(String capacity){
if(capacity == null)
return null;
else
return RolesCkanGroupOrOrg.valueOf(capacity.toUpperCase());
}
/**
* Get the higher role between role1 and role2
* @param role1
* @param role2
* @return the higher role
*/
public static RolesCkanGroupOrOrg getHigher(RolesCkanGroupOrOrg role1, RolesCkanGroupOrOrg role2){
return role1.ordinal() > role2.ordinal() ? role1 : role2;
}
}

View File

@ -0,0 +1,10 @@
package org.gcube.datacatalogue.ckanutillibrary.shared;
/**
* The current state of this group/user
* @author Costantino Perciante at ISTI-CNR
* (costantino.perciante@isti.cnr.it)
*/
public enum State{
DELETED, ACTIVE
}

View File

@ -0,0 +1,54 @@
package org.gcube.datacatalogue.ckanutillibrary.shared;
import java.io.Serializable;
/**
* This bean offers the following statistics:
* <ul>
* <li> number of items of the catalogue
* <li> number of organizations of the catalogue
* <li> number of groups of the catalogue
* <li> number of types of the catalogue
* </ul>
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
*/
public class Statistics implements Serializable{
private static final long serialVersionUID = 2871906712366452266L;
private long numTypes;
private long numOrganizations;
private long numGroups;
private long numItems;
public long getNumTypes() {
return numTypes;
}
public void setNumTypes(long numTypes) {
this.numTypes = numTypes;
}
public long getNumOrganizations() {
return numOrganizations;
}
public void setNumOrganizations(long numOrganizations) {
this.numOrganizations = numOrganizations;
}
public long getNumGroups() {
return numGroups;
}
public void setNumGroups(long numGroups) {
this.numGroups = numGroups;
}
public long getNumItems() {
return numItems;
}
public void setNumItems(long numItems) {
this.numItems = numItems;
}
@Override
public String toString() {
return "Statistics [numTypes=" + numTypes + ", numOrganizations="
+ numOrganizations + ", numGroups=" + numGroups + ", numItems="
+ numItems + "]";
}
}

View File

@ -0,0 +1,12 @@
package org.gcube.datacatalogue.ckanutillibrary.shared.ex;
@SuppressWarnings("serial")
/**
* Thrown when no application profile with such information is found
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
*/
public class ApplicationProfileNotFoundException extends Exception {
public ApplicationProfileNotFoundException(String message) {
super(message);
}
}

View File

@ -0,0 +1,20 @@
package org.gcube.datacatalogue.ckanutillibrary.shared.ex;
/**
* Thrown when there are more than one application profile, but none of them was set as master
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
*/
public class NoApplicationProfileMasterException extends Exception {
private static final long serialVersionUID = 5874713540422734005L;
private static final String DEFAULT_MESSAGE = "There is more than one application profile into this scope"
+ " but none of them is set as master!";
public NoApplicationProfileMasterException(){
super(DEFAULT_MESSAGE);
}
public NoApplicationProfileMasterException(String message) {
super(message);
}
}

View File

@ -0,0 +1,21 @@
package org.gcube.datacatalogue.ckanutillibrary.shared.ex;
/**
* No Data Catalogue node found.
* @author Costantino Perciante at ISTI-CNR
* (costantino.perciante@isti.cnr.it)
*/
public class NoDataCatalogueRuntimeResourceException extends Exception {
private static final long serialVersionUID = -40748130477807648L;
private static final String DEFAULT_MESSAGE = "No Data Catalogue instance for this scope!";
public NoDataCatalogueRuntimeResourceException(){
super(DEFAULT_MESSAGE);
}
public NoDataCatalogueRuntimeResourceException(String message) {
super(message);
}
}

View File

@ -0,0 +1,19 @@
package org.gcube.datacatalogue.ckanutillibrary.shared.ex;
/**
* Exception thrown when it is not possible retrieve information from the ServiceEndpoint
* related to the Data Catalogue
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
*/
public class ServiceEndPointException extends Exception {
private static final long serialVersionUID = 7057074369001221035L;
private static final String DEFAULT_MESSAGE = "Unable to retrieve information from Data Catalogue endpoint!";
public ServiceEndPointException(){
super(DEFAULT_MESSAGE);
}
public ServiceEndPointException(String string) {
super(string);
}
}

View File

@ -0,0 +1,22 @@
package org.gcube.datacatalogue.ckanutillibrary.shared.ex;
/**
* Too many clusters in this scope exception.
* @author Costantino Perciante at ISTI-CNR
* (costantino.perciante@isti.cnr.it)
*
*/
public class TooManyRunningClustersException extends Exception {
private static final long serialVersionUID = -7847493730006647045L;
private static final String DEFAULT_MESSAGE = "Too many CKan data catalague instances for this scope!";
public TooManyRunningClustersException(){
super(DEFAULT_MESSAGE);
}
public TooManyRunningClustersException(String message) {
super(message);
}
}

View File

@ -0,0 +1,15 @@
Manifest-Version: 1.0
Built-By: francesco
Build-Jdk: 1.8.0_252
Specification-Title: CKan utility library
Specification-Version: 0.1.0-SNAPSHOT
Implementation-Title: CKan utility library
Implementation-Version: 0.1.0-SNAPSHOT
Implementation-Vendor-Id: org.gcube.datacatalogue
Build-Time: 20200601-134620
Created-By: Maven Integration for Eclipse
SCM-Branch:
SCM-Revision:
SCM-Revision-URL: https://code-repo.d4science.org/gCubeSystem/catalogu
e-util-library/commit/${buildNumber}

View File

@ -0,0 +1,7 @@
#Generated by Maven Integration for Eclipse
#Mon Jun 01 15:46:21 CEST 2020
version=0.1.0-SNAPSHOT
groupId=org.gcube.datacatalogue
m2e.projectName=catalogue-util-library
m2e.projectLocation=/home/francesco/git/catalogue-util-library
artifactId=catalogue-util-library

View File

@ -0,0 +1,228 @@
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>maven-parent</artifactId>
<groupId>org.gcube.tools</groupId>
<version>1.1.0</version>
<relativePath />
</parent>
<groupId>org.gcube.datacatalogue</groupId>
<artifactId>catalogue-util-library</artifactId>
<version>0.1.0-SNAPSHOT</version>
<name>CKan utility library</name>
<description>
Utility library to retrieve users information, organizations information and so on from the ckan d4science datacatalogue
</description>
<scm>
<connection>scm:git:https://code-repo.d4science.org/gCubeSystem/${project.artifactId}.git</connection>
<developerConnection>scm:git:https://code-repo.d4science.org/gCubeSystem/${project.artifactId}.git</developerConnection>
<url>https://code-repo.d4science.org/gCubeSystem/${project.artifactId}</url>
</scm>
<properties>
<serviceClass>data-catalogue</serviceClass>
<jackanVersion>0.4.2</jackanVersion>
<postgresVersion>9.4.1208.jre7</postgresVersion>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<gwtVersion>2.7.0</gwtVersion>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.gcube.distribution</groupId>
<artifactId>maven-portal-bom</artifactId>
<version>LATEST</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.google.gwt</groupId>
<artifactId>gwt-user</artifactId>
<scope>provided</scope>
</dependency>
<!-- CKAN client library -->
<dependency>
<groupId>eu.trentorise.opendata</groupId>
<artifactId>jackan</artifactId>
<version>${jackanVersion}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.gcube.data-publishing</groupId>
<artifactId>gcat-client</artifactId>
<version>[1.0.0, 2.0.0-SNAPSHOT)</version>
<scope>compile</scope>
</dependency>
<!-- <dependency> -->
<!-- <groupId>org.apache.httpcomponents</groupId> -->
<!-- <artifactId>fluent-hc</artifactId> -->
<!-- <version>4.5.3</version> -->
<!-- <scope>provided</scope> -->
<!-- </dependency> -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.gcube.common.portal</groupId>
<artifactId>portal-manager</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.gcube.resources.discovery</groupId>
<artifactId>ic-client</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.gcube.core</groupId>
<artifactId>common-scope-maps</artifactId>
<scope>provided</scope>
<!-- put at provided for deploying -->
</dependency>
<dependency>
<groupId>org.gcube.core</groupId>
<artifactId>common-encryption</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.gcube.dvos</groupId>
<artifactId>usermanagement-core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>net.htmlparser.jericho</groupId>
<artifactId>jericho-html</artifactId>
<version>3.3</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<dependency>
<groupId>com.googlecode.json-simple</groupId>
<artifactId>json-simple</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.solr</groupId>
<artifactId>solr-solrj</artifactId>
<version>[4.10.2,5.0.0)</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.*</include>
</includes>
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.2</version>
<executions>
<execution>
<goals>
<goal>test-jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.12</version>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.5</version>
<executions>
<execution>
<id>copy-profile</id>
<phase>install</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>target</outputDirectory>
<resources>
<resource>
<directory>${distroDirectory}</directory>
<filtering>true</filtering>
<includes>
<include>profile.xml</include>
</includes>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptors>
<descriptor>${distroDirectory}/descriptor.xml</descriptor>
</descriptors>
<archive>
<manifest>
<mainClass>fully.qualified.MainClass</mainClass>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<id>servicearchive</id>
<phase>install</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<module rename-to='ckanutilitylibrary'>
<!-- Inherit the core Web Toolkit stuff. -->
<inherits name='com.google.gwt.user.User' />
<!-- Specify the paths for translatable code -->
<source path='client' />
<source path='shared' />
</module>

View File

@ -0,0 +1,240 @@
/**
*
*/
package org.gcube.datacatalogue.ckanutillibrary.ckan;
import static com.google.common.base.Preconditions.checkNotNull;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URLEncoder;
import java.util.Arrays;
import javax.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Charsets;
import com.google.common.io.CharStreams;
import eu.trentorise.opendata.jackan.CheckedCkanClient;
import eu.trentorise.opendata.jackan.exceptions.CkanException;
import eu.trentorise.opendata.jackan.exceptions.JackanException;
import eu.trentorise.opendata.jackan.internal.org.apache.http.client.fluent.Request;
import eu.trentorise.opendata.jackan.internal.org.apache.http.client.fluent.Response;
import eu.trentorise.opendata.jackan.model.CkanGroup;
import eu.trentorise.opendata.jackan.model.CkanOrganization;
import eu.trentorise.opendata.jackan.model.CkanResponse;
/**
* The Class ExtendCkanClient.
*
* @author Francesco Mangiacrapa at ISTI-CNR (francesco.mangiacrapa@isti.cnr.it)
*
* Jun 14, 2019
*/
public class ExtendCkanClient extends CheckedCkanClient implements PatchedCkan{
private static final Logger logger = LoggerFactory.getLogger(ExtendCkanClient.class);
@Nullable
private static ObjectMapper objectMapper;
private String catalogueURL;
private String ckanToken;
private int extendTimeout = 120000; //in milliseconds
/**
* Instantiates a new extend ckan client.
*
* @param catalogueURL the catalogue url
*/
public ExtendCkanClient(String catalogueURL) {
super(catalogueURL);
this.catalogueURL = catalogueURL;
}
/**
* Instantiates a new extend ckan client.
*
* @param catalogueURL the catalogue url
* @param ckanToken the ckan token
*/
public ExtendCkanClient(String catalogueURL, @Nullable String ckanToken) {
super(catalogueURL, ckanToken);
this.catalogueURL = catalogueURL;
this.ckanToken = ckanToken;
}
/**
* Instantiates a new extend ckan client.
*
* @param catalogueURL the catalogue url
* @param ckanToken the ckan token
* @param timeout the timeout
*/
public ExtendCkanClient(String catalogueURL, @Nullable String ckanToken, int timeout) {
super(catalogueURL, ckanToken);
this.catalogueURL = catalogueURL;
this.ckanToken = ckanToken;
this.extendTimeout = timeout;
}
/**
* Configures the request. Should work both for GETs and POSTs.
*
* @param request the request
* @return the request
*/
@Override
protected Request configureRequest(Request request) {
request = super.configureRequest(request);
logger.debug("Setting timeout to {}", extendTimeout);
request.socketTimeout(this.extendTimeout)
.connectTimeout(this.extendTimeout);
return request;
}
/**
* Gets the catalogue url.
*
* @return the catalogueURL
*/
public String getCatalogueURL() {
return catalogueURL;
}
/**
* Gets the ckan token.
*
* @return the ckanToken
*/
@Override
public String getCkanToken() {
return ckanToken;
}
/**
* Gets the timeout.
*
* @return the timeout
*/
public int getTimeout() {
return extendTimeout;
}
/* (non-Javadoc)
* @see eu.trentorise.opendata.jackan.CkanClient#getOrganization(java.lang.String)
*/
public synchronized CkanOrganization getOrganization(String idOrName) {
checkNotNull(idOrName, "Need a valid id or name!");
logger.info("Patched read organization for id/name: {}", idOrName);
return getHttp(OrganizationResponse.class, "/api/3/action/organization_show", "id", idOrName,
"include_datasets", "false", "include_users", "true").result;
}
/* (non-Javadoc)
* @see eu.trentorise.opendata.jackan.CkanClient#getGroup(java.lang.String)
*/
public synchronized CkanGroup getGroup(String idOrName) {
checkNotNull(idOrName, "Need a valid id or name!");
logger.info("Patched read group for id/name: {}", idOrName);
return getHttp(GroupResponse.class, "/api/3/action/group_show", "id", idOrName, "include_datasets",
"false", "include_users", "true").result;
}
/**
* Retrieves the Jackson object mapper for reading operations. Internally,
* Object mapper is initialized at first call.
*
* @return the object mapper
*/
static ObjectMapper getObjectMapper() {
if (objectMapper == null) {
objectMapper = new ObjectMapper();
configureObjectMapper(objectMapper);
}
return objectMapper;
}
/* (non-Javadoc)
* @see org.gcube.datacatalogue.ckanutillibrary.server.patch.PatchedCkan#getHttp(java.lang.Class, java.lang.String, java.lang.Object[])
*/
public <T extends CkanResponse> T getHttp(Class<T> responseType, String path, Object... params) {
checkNotNull(responseType);
checkNotNull(path);
String fullUrl = calcFullUrl(path, params);
T ckanResponse;
String returnedText;
try {
logger.debug("getting {}", fullUrl);
Request request = Request.Get(fullUrl);
configureRequest(request);
Response response = request.execute();
InputStream stream = response.returnResponse()
.getEntity()
.getContent();
try (InputStreamReader reader = new InputStreamReader(stream, Charsets.UTF_8)) {
returnedText = CharStreams.toString(reader);
}
logger.trace("returnedText {}", returnedText);
} catch (Exception ex) {
throw new CkanException("Error while performing GET. Request url was: " + fullUrl, this, ex);
}
try {
ckanResponse = getObjectMapper().readValue(returnedText, responseType);
} catch (Exception ex) {
throw new CkanException(
"Couldn't interpret json returned by the server! Returned text was: " + returnedText, this, ex);
}
if (!ckanResponse.isSuccess()) {
throwCkanException("Error while performing GET. Request url was: " + fullUrl, ckanResponse);
}
return ckanResponse;
}
/* (non-Javadoc)
* @see org.gcube.datacatalogue.ckanutillibrary.server.patch.PatchedCkan#calcFullUrl(java.lang.String, java.lang.Object[])
*/
public String calcFullUrl(String path, Object[] params) {
checkNotNull(path);
try {
StringBuilder sb = new StringBuilder().append(catalogueURL)
.append(path);
for (int i = 0; i < params.length; i += 2) {
sb.append(i == 0 ? "?" : "&")
.append(URLEncoder.encode(params[i].toString(), "UTF-8"))
.append("=")
.append(URLEncoder.encode(params[i + 1].toString(), "UTF-8"));
}
return sb.toString();
} catch (Exception ex) {
throw new JackanException("Error while building url to perform GET! \n path: " + path + " \n params: "
+ Arrays.toString(params), ex);
}
}
}

View File

@ -0,0 +1,113 @@
package org.gcube.datacatalogue.ckanutillibrary.ckan;
import eu.trentorise.opendata.jackan.CkanClient;
import eu.trentorise.opendata.jackan.exceptions.CkanException;
import eu.trentorise.opendata.jackan.exceptions.JackanException;
import eu.trentorise.opendata.jackan.model.CkanGroup;
import eu.trentorise.opendata.jackan.model.CkanOrganization;
import eu.trentorise.opendata.jackan.model.CkanResponse;
/**
* The Interface PatchedCkan.
*
* @author Francesco Mangiacrapa at ISTI-CNR (francesco.mangiacrapa@isti.cnr.it)
*
* Jun 14, 2019
*/
public interface PatchedCkan {
/**
*
* This Class is private in {@link CkanClient} so I need to rewrite it
*
* The Class OrganizationResponse.
*
* @author Francesco Mangiacrapa at ISTI-CNR (francesco.mangiacrapa@isti.cnr.it)
*
* Jun 7, 2019
*/
static class OrganizationResponse extends CkanResponse {
public CkanOrganization result;
}
/**
*
*
* This Class is private in {@link CkanClient} so I need to rewrite it
*
*
* The Class GroupResponse.
*
* @author Francesco Mangiacrapa at ISTI-CNR (francesco.mangiacrapa@isti.cnr.it)
*
* Jun 7, 2019
*/
static class GroupResponse extends CkanResponse {
public CkanGroup result;
/**
* Instantiates a new group response.
*/
public GroupResponse() {
}
}
/**
*
* This method is private in {@link CkanClient} so I need to rewrite it
*
*
*
* Performs HTTP GET on server. If {@link CkanResponse#isSuccess()} is false
* throws {@link CkanException}.
*
* @param <T> the generic type
* @param responseType a descendant of CkanResponse
* @param path something like /api/3/package_show
* @param params list of key, value parameters. They must be not be url
* encoded. i.e. "id","laghi-monitorati-trento"
* @return the http
* @throws CkanException on error
*/
public <T extends CkanResponse> T getHttp(Class<T> responseType, String path, Object... params);
/**
*
* This method is private in {@link CkanClient} so I need to rewrite it
*
*
* Calculates a full url out of the provided params.
*
* @param path something like /api/3/package_show
* @param params list of key, value parameters. They must be not be url encoded.
* i.e. "id","laghi-monitorati-trento"
* @return the full url to be called.
* @throws JackanException if there is any error building the url
*/
public String calcFullUrl(String path, Object[] params);
// WE NEED TO OVERRIDE THE FOLLOWING METHODS
/**
* Gets the organization.
*
* @param idOrName the id or name
* @return the organization
*/
public CkanOrganization getOrganization(String idOrName);
/**
* Gets the group.
*
* @param idOrName the id or name
* @return the group
*/
public CkanGroup getGroup(String idOrName);
}

View File

@ -0,0 +1,168 @@
package org.gcube.datacatalogue.ckanutillibrary.ckan;
import static com.google.common.base.Preconditions.checkNotNull;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URLEncoder;
import java.util.Arrays;
import javax.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Charsets;
import com.google.common.io.CharStreams;
import eu.trentorise.opendata.jackan.CkanClient;
import eu.trentorise.opendata.jackan.exceptions.CkanException;
import eu.trentorise.opendata.jackan.exceptions.JackanException;
import eu.trentorise.opendata.jackan.internal.org.apache.http.client.fluent.Request;
import eu.trentorise.opendata.jackan.internal.org.apache.http.client.fluent.Response;
import eu.trentorise.opendata.jackan.model.CkanGroup;
import eu.trentorise.opendata.jackan.model.CkanOrganization;
import eu.trentorise.opendata.jackan.model.CkanResponse;
/**
* The Class SimpleExtendCkanClient.
*
* @author Francesco Mangiacrapa at ISTI-CNR (francesco.mangiacrapa@isti.cnr.it)
*
* Jun 7, 2019
*/
public class SimpleExtendCkanClient extends CkanClient implements PatchedCkan{
private String catalogueURL;
@Nullable
private static ObjectMapper objectMapper;
private static final Logger logger = LoggerFactory.getLogger(SimpleExtendCkanClient.class);
/**
* Instantiates a new simple extend ckan client.
*
* @param catalogueURL the catalogue URL
*/
public SimpleExtendCkanClient(String catalogueURL) {
super(catalogueURL);
this.catalogueURL = catalogueURL;
}
/* (non-Javadoc)
* @see eu.trentorise.opendata.jackan.CkanClient#getOrganization(java.lang.String)
*/
public synchronized CkanOrganization getOrganization(String idOrName) {
checkNotNull(idOrName, "Need a valid id or name!");
logger.info("Patched read organization for id/name: {}", idOrName);
return getHttp(OrganizationResponse.class, "/api/3/action/organization_show", "id", idOrName,
"include_datasets", "false", "include_users", "true").result;
}
/* (non-Javadoc)
* @see eu.trentorise.opendata.jackan.CkanClient#getGroup(java.lang.String)
*/
public synchronized CkanGroup getGroup(String idOrName) {
checkNotNull(idOrName, "Need a valid id or name!");
logger.info("Patched read group for id/name: {}", idOrName);
return getHttp(GroupResponse.class, "/api/3/action/group_show", "id", idOrName, "include_datasets",
"false", "include_users", "true").result;
}
/**
* Retrieves the Jackson object mapper for reading operations. Internally,
* Object mapper is initialized at first call.
*
* @return the object mapper
*/
public static ObjectMapper getObjectMapper() {
if (objectMapper == null) {
objectMapper = new ObjectMapper();
configureObjectMapper(objectMapper);
}
return objectMapper;
}
/* (non-Javadoc)
* @see org.gcube.datacatalogue.ckanutillibrary.server.patch.PatchedCkan#getHttp(java.lang.Class, java.lang.String, java.lang.Object[])
*/
public <T extends CkanResponse> T getHttp(Class<T> responseType, String path, Object... params) {
checkNotNull(responseType);
checkNotNull(path);
String fullUrl = calcFullUrl(path, params);
T ckanResponse;
String returnedText;
try {
logger.debug("getting {}", fullUrl);
Request request = Request.Get(fullUrl);
configureRequest(request);
Response response = request.execute();
InputStream stream = response.returnResponse()
.getEntity()
.getContent();
try (InputStreamReader reader = new InputStreamReader(stream, Charsets.UTF_8)) {
returnedText = CharStreams.toString(reader);
}
logger.trace("returnedText {}", returnedText);
} catch (Exception ex) {
throw new CkanException("Error while performing GET. Request url was: " + fullUrl, this, ex);
}
try {
ckanResponse = getObjectMapper().readValue(returnedText, responseType);
} catch (Exception ex) {
throw new CkanException(
"Couldn't interpret json returned by the server! Returned text was: " + returnedText, this, ex);
}
if (!ckanResponse.isSuccess()) {
throwCkanException("Error while performing GET. Request url was: " + fullUrl, ckanResponse);
}
return ckanResponse;
}
/* (non-Javadoc)
* @see org.gcube.datacatalogue.ckanutillibrary.server.patch.PatchedCkan#calcFullUrl(java.lang.String, java.lang.Object[])
*/
public String calcFullUrl(String path, Object[] params) {
checkNotNull(path);
try {
StringBuilder sb = new StringBuilder().append(catalogueURL)
.append(path);
for (int i = 0; i < params.length; i += 2) {
sb.append(i == 0 ? "?" : "&")
.append(URLEncoder.encode(params[i].toString(), "UTF-8"))
.append("=")
.append(URLEncoder.encode(params[i + 1].toString(), "UTF-8"));
}
return sb.toString();
} catch (Exception ex) {
throw new JackanException("Error while building url to perform GET! \n path: " + path + " \n params: "
+ Arrays.toString(params), ex);
}
}
/**
* Gets the catalogue url.
*
* @return the catalogueURL
*/
public String getCatalogueURL() {
return catalogueURL;
}
}

View File

@ -0,0 +1,209 @@
package org.gcube.datacatalogue.ckanutillibrary.db;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import org.gcube.datacatalogue.ckanutillibrary.shared.RolesCkanGroupOrOrg;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class DBCaller {
private static final Logger LOG = LoggerFactory.getLogger(DBCaller.class);
private String CKAN_DB_URL;
private Integer CKAN_DB_PORT;
private String CKAN_DB_NAME;
private String CKAN_DB_USER;
private String CKAN_DB_PASSWORD;
public DBCaller() {
}
public DBCaller(String cKAN_DB_URL, Integer cKAN_DB_PORT, String cKAN_DB_NAME, String cKAN_DB_USER,
String cKAN_DB_PASSWORD) {
CKAN_DB_URL = cKAN_DB_URL;
CKAN_DB_PORT = cKAN_DB_PORT;
CKAN_DB_NAME = cKAN_DB_NAME;
CKAN_DB_USER = cKAN_DB_USER;
CKAN_DB_PASSWORD = cKAN_DB_PASSWORD;
}
/**
* Retrieve connection from the pool
* @return a connection available within the pool
* @throws SQLException
* @throws ClassNotFoundException
*/
private Connection getConnection() throws SQLException, ClassNotFoundException{
LOG.debug("CONNECTION REQUEST");
// create db connection
Class.forName("org.postgresql.Driver");
String dbBaseConnectionURL = String.format("jdbc:postgresql://%s", CKAN_DB_URL);
if(CKAN_DB_PORT!=null)
dbBaseConnectionURL+=":" + CKAN_DB_PORT;
dbBaseConnectionURL+="/" + CKAN_DB_NAME;
Connection connection = DriverManager.getConnection(dbBaseConnectionURL, CKAN_DB_USER, CKAN_DB_PASSWORD);
// Connection connection = DriverManager.getConnection(
// "jdbc:postgresql://" + CKAN_DB_URL + ":" + CKAN_DB_PORT + "/" + CKAN_DB_NAME, CKAN_DB_USER, CKAN_DB_PASSWORD);
return connection;
}
/**
* Retrieve the map (groups id, capacity) with the groups to which the user belongs by querying directly the database.
* @param username
* @return
* @throws SQLException
* @throws ClassNotFoundException
*/
public Map<String, RolesCkanGroupOrOrg> getGroupsByUserFromDB(String userId){
checkNotNull(userId);
//couples (groups id, capacity) of the user in the group
Map<String, RolesCkanGroupOrOrg> toReturn = new HashMap<String, RolesCkanGroupOrOrg>();
Connection connection = null;
try{
connection = getConnection();
ResultSet rs;
String joinQuery = "SELECT \"group_id\",\"capacity\" FROM \"public\".\"member\" "
+ "JOIN \"public\".\"group\" ON \"member\".\"group_id\" = \"group\".\"id\" where \"table_id\"=?"
+ " and \"table_name\"='user' and \"member\".\"state\"='active' and \"group\".\"state\"='active' and \"group\".\"is_organization\"=?;";
PreparedStatement preparedStatement = connection.prepareStatement(joinQuery);
preparedStatement.setString(1, userId);
preparedStatement.setBoolean(2, false);
rs = preparedStatement.executeQuery();
while (rs.next()) {
toReturn.put(rs.getString("group_id"), RolesCkanGroupOrOrg.convertFromCapacity(rs.getString("capacity")));
}
}catch(Exception e){
LOG.error("Failed to retrieve the groups to whom the user belongs. Error is " + e.getMessage());
return null;
}finally{
closeConnection(connection);
}
return toReturn;
}
/**
* Retrieve the map (organisation id, capacity) with the organisations to which the user belongs by querying directly the database.
* @param username
* @return
* @throws SQLException
* @throws ClassNotFoundException
*/
public Map<String, RolesCkanGroupOrOrg> getOrganizationsByUserFromDB(String userId){
checkNotNull(userId);
Map<String, RolesCkanGroupOrOrg> toReturn = new HashMap<String, RolesCkanGroupOrOrg>();
Connection connection = null;
try{
connection = getConnection();
ResultSet rs;
String joinQuery = "SELECT \"group_id\",\"capacity\" FROM \"public\".\"member\" "
+ "JOIN \"public\".\"group\" ON \"member\".\"group_id\" = \"group\".\"id\" where \"table_id\"=?"
+ " and \"table_name\"='user' and \"member\".\"state\"='active' and \"group\".\"state\"='active' and \"group\".\"is_organization\"=?;";
PreparedStatement preparedStatement = connection.prepareStatement(joinQuery);
preparedStatement.setString(1, userId);
preparedStatement.setBoolean(2, true);
rs = preparedStatement.executeQuery();
while (rs.next()) {
toReturn.put(rs.getString("group_id"), RolesCkanGroupOrOrg.convertFromCapacity(rs.getString("capacity")));
}
}catch(Exception e){
LOG.error("Failed to retrieve the groups to whom the user belongs. Error is " + e.getMessage());
return null;
}finally{
closeConnection(connection);
}
return toReturn;
}
public String getApiKeyFromUsername(String username, String state) {
LOG.debug("Request api key for user = " + username);
// checks
checkNotNull(username);
checkArgument(!username.isEmpty());
// the connection
Connection connection = null;
String apiToReturn = null;
try{
connection = getConnection();
String query = "SELECT \"apikey\" FROM \"user\" WHERE \"name\"=? and \"state\"=?;";
PreparedStatement preparedStatement = connection.prepareStatement(query);
preparedStatement.setString(1, username);
preparedStatement.setString(2, state);
ResultSet rs = preparedStatement.executeQuery();
while (rs.next()) {
apiToReturn = rs.getString("apikey");
LOG.debug("Api key "+apiToReturn.substring(0,10)+" MASKED-TOKEN retrieved for user " + username);
break;
}
return apiToReturn;
}catch(Exception e){
LOG.error("Unable to retrieve key for user " + username, e);
}finally{
closeConnection(connection);
}
return null;
}
/**
* Tries to close a connection
* @param connection
*/
private void closeConnection(Connection connection){
if(connection != null){
try{
connection.close();
}catch(Exception e){
LOG.error("Unable to close this connection ", e);
}
}
}
}

View File

@ -0,0 +1,69 @@
package org.gcube.datacatalogue.ckanutillibrary.gcat;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.List;
import org.gcube.datacatalogue.ckanutillibrary.ckan.SimpleExtendCkanClient;
import org.gcube.gcat.client.Item;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import eu.trentorise.opendata.jackan.model.CkanDataset;
import eu.trentorise.opendata.jackan.model.CkanLicense;
// TODO: Auto-generated Javadoc
/**
* The Class GCatCaller.
*
* @author Francesco Mangiacrapa at ISTI-CNR Pisa (Italy)
* May 29, 2020
*/
public class GCatCaller {
private SimpleExtendCkanClient jackanCkanClient;
private String catalogueURL;
private static final Logger LOG = LoggerFactory.getLogger(GCatCaller.class);
/**
* Instantiates a new g cat caller.
*/
public GCatCaller(String catalogueURL) {
this.catalogueURL = catalogueURL;
this.jackanCkanClient = new SimpleExtendCkanClient(catalogueURL);
}
/**
* Gets the dataset for name.
*
* @param datasetIdOrName the dataset id or name
* @return the dataset for name
* @throws JsonParseException the json parse exception
* @throws JsonMappingException the json mapping exception
* @throws IOException Signals that an I/O exception has occurred.
*/
public CkanDataset getDatasetForName(String datasetIdOrName) throws JsonParseException, JsonMappingException, IOException {
LOG.debug("Get dataset for name "+datasetIdOrName+ "called");
String json = new Item().read(datasetIdOrName);
return SimpleExtendCkanClient.getObjectMapper().readValue(json, CkanDataset.class);
}
/**
* TODO gCAT missing
* @return
* @throws MalformedURLException
*/
public List<CkanLicense> getLicenseList() {
LOG.debug("Get linces list called");
return jackanCkanClient.getLicenseList();
}
}

View File

@ -0,0 +1,105 @@
package org.gcube.datacatalogue.ckanutillibrary.server;
import static org.gcube.resources.discovery.icclient.ICFactory.client;
import java.io.StringReader;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.gcube.common.portal.PortalContext;
import org.gcube.common.resources.gcore.utils.XPathHelper;
import org.gcube.common.scope.api.ScopeProvider;
import org.gcube.datacatalogue.ckanutillibrary.shared.ex.ApplicationProfileNotFoundException;
import org.gcube.resources.discovery.client.api.DiscoveryClient;
import org.gcube.resources.discovery.client.queries.api.Query;
import org.gcube.resources.discovery.client.queries.impl.QueryBox;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;
/**
* This class has a method that tries to read the application profile whose structure contains
* couples Scope/Current_Url to check where the the needed information needs to be discovered according to the current
* portlet url. It means that the scope in which the ckan related information will be discovered could be different wrt the running one.
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
*/
public class ApplicationProfileScopePerUrlReader {
private static final Logger logger = LoggerFactory.getLogger(ApplicationProfileScopePerUrlReader.class);
private final static String APPLICATION_PROFILE_NAME = "DataCatalogueMapScopesUrls";
private final static String QUERY = "for $profile in collection('/db/Profiles/GenericResource')//Resource " +
"where $profile/Profile/SecondaryType/string() eq 'ApplicationProfile' and $profile/Profile/Name/string() " +
" eq '" + APPLICATION_PROFILE_NAME + "'" +
"return $profile";
/**
* Get the scope in which discover for this url. If the Application Profile doesn't contain it, the current scope (taken
* from ScopeProvider is returned).
* @param url
* @return the scope to be used for the given url
*/
public static String getScopePerUrl(String url){
logger.info("Request scope for ckan portlet at url " + url);
String scope = ScopeProvider.instance.get();
String scopeToReturn = scope;
String rootScopeForInfrastructure = "/" + PortalContext.getConfiguration().getInfrastructureName();
if(url == null || url.isEmpty()){
logger.info("The url passed is null or empty! Returning current scope [" + scope + "]");
return scope;
}
// set this scope
ScopeProvider.instance.set(rootScopeForInfrastructure);
logger.debug("Trying to fetch applicationProfile profile from the infrastructure for " + APPLICATION_PROFILE_NAME + " scope: " + rootScopeForInfrastructure);
try {
Query q = new QueryBox(QUERY);
DiscoveryClient<String> client = client();
List<String> appProfile = client.submit(q);
if (appProfile == null || appProfile.size() == 0)
throw new ApplicationProfileNotFoundException("Your applicationProfile is not registered in the infrastructure");
else{
String elem = appProfile.get(0);
DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Node node = docBuilder.parse(new InputSource(new StringReader(elem))).getDocumentElement();
XPathHelper helper = new XPathHelper(node);
List<String> urls = helper.evaluate("/Resource/Profile/Body/EndPoint/URL/text()");
if (urls != null && urls.size() > 0) {
boolean foundScope = false;
for (int i = 0; i < urls.size(); i++) {
if (urls.get(i).trim().compareTo(url) == 0) { // url found
scopeToReturn = helper.evaluate("/Resource/Profile/Body/EndPoint/Scope/text()").get(i);
logger.debug("Found, returning " + scopeToReturn);
foundScope = true;
break;
}
}
if (!foundScope || scopeToReturn == null || scopeToReturn.isEmpty()){
logger.debug("Scope is missing for url " + url + ". Returning " + scope);
}
}
else
throw
new ApplicationProfileNotFoundException("Your applicationProfile EndPoint was not found in the profile, consider adding <EndPoint><Scope> element in <Body>");
}
} catch (Exception e) {
logger.error("Error while trying to fetch applicationProfile profile from the infrastructure", e);
}finally{
ScopeProvider.instance.set(scope);
}
return scopeToReturn;
}
}

View File

@ -0,0 +1,44 @@
package org.gcube.datacatalogue.ckanutillibrary.server;
// TODO: Auto-generated Javadoc
/**
* The Class CKANTokenBean.
*
* @author Francesco Mangiacrapa at ISTI-CNR Pisa (Italy)
* Jun 1, 2020
*/
public class CKANTokenBean {
protected String apiKey;
protected long timestamp;
/**
* Instantiates a new CKAN token bean.
*
* @param apiKey the api key
* @param timestamp the timestamp
*/
public CKANTokenBean(String apiKey, long timestamp) {
super();
this.apiKey = apiKey;
this.timestamp = timestamp;
}
public String getApiKey() {
return apiKey;
}
public void setApiKey(String apiKey) {
this.apiKey = apiKey;
}
public long getTimestamp() {
return timestamp;
}
public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}
}

View File

@ -0,0 +1,200 @@
package org.gcube.datacatalogue.ckanutillibrary.server;
import java.util.List;
import java.util.Map;
import org.gcube.datacatalogue.ckanutillibrary.shared.ResourceBean;
import org.gcube.datacatalogue.ckanutillibrary.shared.RolesCkanGroupOrOrg;
import eu.trentorise.opendata.jackan.model.CkanDataset;
import eu.trentorise.opendata.jackan.model.CkanGroup;
import eu.trentorise.opendata.jackan.model.CkanLicense;
import eu.trentorise.opendata.jackan.model.CkanOrganization;
public interface DataCatalogue {
/**
* Finds the id associated to the chosen license
*
* @param chosenLicense
* @return the id on success, null otherwise
*/
String findLicenseIdByLicenseTitle(String chosenLicense);
/**
* Given the id or the name of the dataset it returns its current url by
* contacting the uri resolver. If no uri resolver is available, an url that is
* not guaranteed to be long term valid will be generated. Information are not
* encrypted.
*
* @param datasetId
* @return The url of the dataset on success, null otherwise
*/
String getUnencryptedUrlFromDatasetIdOrName(String datasetIdOrName);
/**
* Create a dataset with those information. The method allows to have multiple
* values for the same custom field key. NOTE: unfortunately java doesn't
* support overload in java interface methods (that's way I cannot use the same
* name for the method)
*
* @param title
* @param name (unique identifier)
* @param organizationNameOrId
* @param author
* @param authorMail
* @param maintainer
* @param maintainerMail
* @param version
* @param description
* @param licenseId
* @param tags
* @param customFields
* @param resources
* @param setPublic (manage visibility: Admin role is needed)
* @return the id of the dataset on success, null otherwise
* @throws Exception
*/
String createCKanDatasetMultipleCustomFields(String title, String name, String organizationNameOrId, String author,
String authorMail, String maintainer, String maintainerMail, long version, String description,
String licenseId, List<String> tags, Map<String, List<String>> customFields, List<ResourceBean> resources,
boolean setPublic) throws Exception;
/**
* Patch a product with product id productId by using the couples in
* customFieldsToChange. NOTE: only the specified custom fields will be changed.
* If a custom field with a given key already exists, and removeOld is set to
* false, the new values are added at the end of the list. Otherwise they are
* lost.
*
* @param productId
* @param customFieldsToChange
* @param removeOld
* @return
*/
boolean patchProductCustomFields(String productId, Map<String, List<String>> customFieldsToChange,
boolean removeOld);
/**
* Add a resource described by the bean to the dataset id into
* resource.datasetId
*
* @param resource
* @return String the id of the resource on success, null otherwise
*/
String addResourceToDataset(ResourceBean resource) throws Exception;
/**
* Remove the resource with id resourceId from the dataset in which it is.
*
* @param resourceId
* @return true on success, false otherwise.
*/
boolean deleteResourceFromDataset(String resourceId);
/**
* Create a dataset with those information.
*
* @param apiKey
* @param title
* @param name (unique identifier)
* @param organizationNameOrId
* @param author
* @param authorMail
* @param maintainer
* @param maintainerMail
* @param version
* @param description
* @param licenseId
* @param tags
* @param customFields
* @param resources
* @param setPublic (manage visibility: Admin role is needed)
* @return the id of the dataset on success, null otherwise
* @throws Exception
*/
/**
* Checks if a product with such name already exists. Please remember that the
* name is unique.
*
* @param nameOrId the name or the id of the dataset to check
* @return
*/
boolean existProductWithNameOrId(String nameOrId);
/**
* The method returns the role the user has in the groups he/she belongs to (it
* uses the db, so it is much faster)
*
* @param username
* @param apiKey
* @return
*/
Map<String, Map<CkanGroup, RolesCkanGroupOrOrg>> getUserRoleByGroup(String username, String apiKey);
/**
* Get the list of licenses' titles.
*
* @return the list of licenses' titles
*/
List<String> getLicenseTitles();
/**
* Retrieve ckan licenses
*
* @return
*/
List<CkanLicense> getLicenses();
/**
* Retrieve the url of the uri resolver for this catalogue instance/scope
*
* @return
*/
String getUriResolverUrl();
/**
* Return the manage product property
*
* @return the manage product property
*/
boolean isManageProductEnabled();
/**
* Return the catalogue portlet for this context(i.e. scope)
*
* @return
*/
String getPortletUrl();
/**
* Return the ckan catalogue url in this scope.
*
* @return the catalogue url
*/
String getCatalogueUrl();
/**
* Returns the list of organizations to whom the user belongs (with any role)
* @param username
* @return a list of organizations
*/
List<CkanOrganization> getOrganizationsByUser(String username);
/**
* Returns the list of groups to whom the user belongs (with any role)
* @param username
* @return a list of groups
*/
List<CkanGroup> getGroupsByUser(String username);
/**
* Retrieve a ckan dataset given its id
* @param datasetId
* @return
*/
CkanDataset getDataset(String datasetId, String apiKey);
}

View File

@ -0,0 +1,78 @@
package org.gcube.datacatalogue.ckanutillibrary.server;
import java.util.concurrent.ConcurrentHashMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Please invoke this method to retrieve an object of this kind per scope.
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
*/
public class DataCatalogueFactory {
private static final Logger logger = LoggerFactory.getLogger(DataCatalogueFactory.class);
private static final long MAX_LIFETIME = 1000 * 60 * 30; // 30 MINUTES
private static DataCatalogueFactory instance = new DataCatalogueFactory();
private static ConcurrentHashMap<String, CacheBean> cache;
private class CacheBean{
DataCatalogueImpl utils;
long ttl;
public CacheBean(long ttl, DataCatalogueImpl utils){
this.ttl = ttl;
this.utils = utils;
}
}
/**
* Private constructor
*/
private DataCatalogueFactory(){
logger.debug("Ckan factory object build");
cache = new ConcurrentHashMap<String, CacheBean>();
}
/**
* Get the factory instance
* @return
*/
public static DataCatalogueFactory getFactory(){
logger.debug("Factory requested");
return instance;
}
/**
* Retrieve the ckan utils information for the given scope
* @param scope
* @return
* @throws Exception
*/
public DataCatalogueImpl getUtilsPerScope(String scope) throws Exception{
if(scope == null || scope.isEmpty())
throw new IllegalArgumentException("Invalid scope given!");
if(cache.containsKey(scope) && !expired(cache.get(scope))){
return cache.get(scope).utils;
}
else{
logger.info("Creating CKAN LIB utils for scope " + scope);
DataCatalogueImpl utils = new DataCatalogueImpl(scope);
cache.put(scope, new CacheBean(System.currentTimeMillis(), utils));
return utils;
}
}
/**
* Check if the ckan information must be retrieved again.
* @param cacheBean
* @return
*/
private boolean expired(CacheBean cacheBean) {
return (cacheBean.ttl + MAX_LIFETIME < System.currentTimeMillis());
}
}

View File

@ -0,0 +1,543 @@
package org.gcube.datacatalogue.ckanutillibrary.server;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.gcube.common.authorization.library.provider.SecurityTokenProvider;
import org.gcube.common.scope.impl.ScopeBean;
import org.gcube.common.scope.impl.ScopeBean.Type;
import org.gcube.datacatalogue.ckanutillibrary.ckan.ExtendCkanClient;
import org.gcube.datacatalogue.ckanutillibrary.ckan.SimpleExtendCkanClient;
import org.gcube.datacatalogue.ckanutillibrary.db.DBCaller;
import org.gcube.datacatalogue.ckanutillibrary.gcat.GCatCaller;
import org.gcube.datacatalogue.ckanutillibrary.server.DataCatalogueRunningCluster.ACCESS_LEVEL_TO_CATALOGUE_PORTLET;
import org.gcube.datacatalogue.ckanutillibrary.server.utils.CatalogueUtilMethods;
import org.gcube.datacatalogue.ckanutillibrary.server.utils.url.EntityContext;
import org.gcube.datacatalogue.ckanutillibrary.shared.ResourceBean;
import org.gcube.datacatalogue.ckanutillibrary.shared.RolesCkanGroupOrOrg;
import org.gcube.datacatalogue.ckanutillibrary.shared.State;
import org.json.simple.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import eu.trentorise.opendata.jackan.internal.org.apache.http.HttpResponse;
import eu.trentorise.opendata.jackan.internal.org.apache.http.client.methods.HttpPost;
import eu.trentorise.opendata.jackan.internal.org.apache.http.entity.ContentType;
import eu.trentorise.opendata.jackan.internal.org.apache.http.entity.StringEntity;
import eu.trentorise.opendata.jackan.internal.org.apache.http.impl.client.CloseableHttpClient;
import eu.trentorise.opendata.jackan.internal.org.apache.http.impl.client.HttpClientBuilder;
import eu.trentorise.opendata.jackan.internal.org.apache.http.util.EntityUtils;
import eu.trentorise.opendata.jackan.model.CkanDataset;
import eu.trentorise.opendata.jackan.model.CkanGroup;
import eu.trentorise.opendata.jackan.model.CkanLicense;
import eu.trentorise.opendata.jackan.model.CkanOrganization;
import eu.trentorise.opendata.jackan.model.CkanUser;
public class DataCatalogueImpl implements DataCatalogue {
private static final Logger LOG = LoggerFactory.getLogger(DataCatalogueImpl.class);
private String CKAN_CATALOGUE_URL;
private String CKAN_DB_NAME;
private String CKAN_DB_USER;
private String CKAN_DB_PASSWORD;
private String CKAN_DB_URL;
private Integer CKAN_DB_PORT;
private String PORTLET_URL_FOR_SCOPE;
private String SOLR_URL;
private String CKAN_TOKEN_SYS;
private String CKAN_EMAIL;
private String URI_RESOLVER_URL;
private boolean MANAGE_PRODUCT_BUTTON;
private boolean SOCIAL_POST;
private boolean ALERT_USERS_ON_POST_CREATION;
private String CONTEXT;
private Map<String, String> extendRoleInOrganization;
public Map<ACCESS_LEVEL_TO_CATALOGUE_PORTLET, String> mapAccessURLToCatalogue;
private static final String CATALOGUE_TAB_ENDING_URL = "/catalogue";
// gCat client
private GCatCaller gCatCaller;
// db client
private DBCaller dbCaller;
// ckan client
private SimpleExtendCkanClient ckanCaller;
// hashmap for ckan api keys
private ConcurrentHashMap<String, CKANTokenBean> apiKeysMap;
// apikey bean expires after X minutes in the above map
private static final int EXPIRE_KEY_TIME = 60 * 60 * 1000;
/**
* The ckan catalogue url and database will be discovered in this scope
* @param scope
* @throws Exception if unable to find datacatalogue info
*/
public DataCatalogueImpl(String scope) throws Exception{
DataCatalogueRunningCluster runningInstance = new DataCatalogueRunningCluster(scope);
// save information
CKAN_DB_URL = runningInstance.getDatabaseHosts().get(0).trim();
CKAN_DB_PORT = runningInstance.getDatabasePorts().get(0);
CKAN_DB_NAME = runningInstance.getDataBaseName().trim();
CKAN_DB_USER = runningInstance.getDataBaseUser().trim();
CKAN_DB_PASSWORD = runningInstance.getDataBasePassword().trim();
//CKAN_TOKEN_SYS = runningInstance.getSysAdminToken().trim();
CKAN_EMAIL = runningInstance.getEmailCatalogue().trim();
CKAN_CATALOGUE_URL = runningInstance.getDataCatalogueUrl().get(0).trim();
PORTLET_URL_FOR_SCOPE = runningInstance.getPortletUrl().trim();
mapAccessURLToCatalogue = runningInstance.getMapAccessURLToCatalogue();
MANAGE_PRODUCT_BUTTON = runningInstance.isManageProductEnabled();
URI_RESOLVER_URL = runningInstance.getUrlResolver();
SOCIAL_POST = runningInstance.isSocialPostEnabled();
ALERT_USERS_ON_POST_CREATION = runningInstance.isAlertEnabled();
SOLR_URL = runningInstance.getUrlSolr();
LOG.info("In the scope: "+scope+", I read the catalogue URL: " + CKAN_CATALOGUE_URL);
// build the clients
gCatCaller = new GCatCaller(CKAN_CATALOGUE_URL);
dbCaller = new DBCaller(CKAN_DB_URL, CKAN_DB_PORT, CKAN_DB_NAME, CKAN_DB_USER, CKAN_DB_PASSWORD);
ckanCaller = new SimpleExtendCkanClient(CKAN_CATALOGUE_URL);
// init map
apiKeysMap = new ConcurrentHashMap<String, CKANTokenBean>();
// save the context
CONTEXT = scope;
// extended roles
extendRoleInOrganization = runningInstance.getExtendRoleInOrganization();
}
@Override
public String getCatalogueUrl() {
return CKAN_CATALOGUE_URL;
}
@Override
public String getPortletUrl() {
//PATCHED By Francesco
ScopeBean context = new ScopeBean(CONTEXT);
if(context.is(Type.INFRASTRUCTURE)) {
LOG.info("Working with the {} scope returning the path read from GR 'Ckan-Porltet': {}", Type.INFRASTRUCTURE.toString(), PORTLET_URL_FOR_SCOPE);
return PORTLET_URL_FOR_SCOPE;
}
String vreNameLower = context.name().toLowerCase();
//CHECKING IF THE PORTLET URL CONTAINS THE VRE NAME INTO URL
if(PORTLET_URL_FOR_SCOPE.toLowerCase().contains(vreNameLower)){
//THE PORLTET URL READ FROM GENERIC RESOUCE 'CkanPortlet' SHOULD BE ALREADY VALID, POITING TO CKAN PORTLET
return PORTLET_URL_FOR_SCOPE;
}else{
//ADDING VRE getApiKeyFromUsernameNAME AND THE SUFFIX 'CATALOGUE_TAB_ENDING_URL' TO URL
String buildedUrl = PORTLET_URL_FOR_SCOPE.endsWith("/") ? PORTLET_URL_FOR_SCOPE : PORTLET_URL_FOR_SCOPE + "/";
String defaultSuffix = vreNameLower + CATALOGUE_TAB_ENDING_URL;
buildedUrl+= defaultSuffix;
LOG.warn("The Portlet URL read from Generic Resource 'Ckan-Porltet' does not contain the portlet suffix, so I added the default: "+defaultSuffix);
return buildedUrl;
}
}
@Override
public String findLicenseIdByLicenseTitle(String chosenLicense) {
LOG.debug("Requested license id");
// checks
checkNotNull(chosenLicense);
//retrieve the list of available licenses
List<CkanLicense> licenses = ckanCaller.getLicenseList();
for (CkanLicense ckanLicense : licenses) {
if(ckanLicense.getTitle().equals(chosenLicense))
return ckanLicense.getId();
}
return null;
}
@Override
public List<String> getLicenseTitles() {
LOG.debug("Request for CKAN licenses");
// get the url and the api key of the user
List<String> result = new ArrayList<String>();
//retrieve the list of available licenses
List<CkanLicense> licenses = ckanCaller.getLicenseList();
for (CkanLicense ckanLicense : licenses) {
result.add(ckanLicense.getTitle());
LOG.debug("License is " + ckanLicense.getTitle() + " and id " + ckanLicense.getId());
}
return result;
}
@Override
public List<CkanLicense> getLicenses() {
LOG.debug("Request for CKAN licenses (original jackan objects are going to be retrieved)");
//retrieve the list of available licenses
return ckanCaller.getLicenseList();
}
@Override
public CkanDataset getDataset(String datasetId, String apiKey) {
LOG.info("Request ckan dataset with id " + datasetId);
// checks
checkNotNull(datasetId);
checkArgument(!datasetId.isEmpty());
try{
if(apiKey!=null && !apiKey.isEmpty()) {
LOG.info("API-KEY found. Calling the "+ExtendCkanClient.class.getSimpleName());
ExtendCkanClient client = new ExtendCkanClient(CKAN_CATALOGUE_URL, apiKey);
return client.getDataset(datasetId);
}
String authzToken = SecurityTokenProvider.instance.get();
if(authzToken!=null && !authzToken.isEmpty()) {
LOG.info("gcube-token found. Calling the gCat client");
return gCatCaller.getDatasetForName(datasetId);
}
LOG.info("No api-key or gcube-token found. Calling Ckan Client without API-KEY");
return ckanCaller.getDataset(datasetId);
}catch(Exception e){
LOG.error("Unable to retrieve such dataset, returning null ...", e);
}
return null;
}
@Override
public String getUnencryptedUrlFromDatasetIdOrName(String datasetIdOrName) {
LOG.debug("Request coming for getting dataset url (not encrypted) of dataset with name/id " + datasetIdOrName);
// checks
checkNotNull(datasetIdOrName);
checkArgument(!datasetIdOrName.isEmpty());
String url = null;
try{
// get the dataset from name
ExtendCkanClient client = new ExtendCkanClient(CKAN_CATALOGUE_URL, CKAN_TOKEN_SYS);
CkanDataset dataset = client.getDataset(datasetIdOrName);
String name = dataset.getName();
if(dataset != null){
if(getUriResolverUrl() != null)
url = getUrlForProduct(CONTEXT, EntityContext.DATASET, name);
if(url == null || url.isEmpty())
url = getPortletUrl() + "?" + URLEncoder.encode("path=/dataset/" + name, "UTF-8");
}
}catch(Exception e){
LOG.error("Error while retrieving dataset with id/name=" + datasetIdOrName, e);
} //requestEntity.put("clear_url", Boolean.toString(unencrypted));
return url;
}
public String createCKanDatasetMultipleCustomFields(String title, String name, String organizationNameOrId,
String author, String authorMail, String maintainer, String maintainerMail, long version,
String description, String licenseId, List<String> tags, Map<String, List<String>> customFields,
List<ResourceBean> resources, boolean setPublic) throws Exception {
return null;
}
@Override
public Map<String, Map<CkanGroup, RolesCkanGroupOrOrg>> getUserRoleByGroup(
String username, String apiKey) {
checkNotNull(username);
checkNotNull(apiKey);
checkNotNull(username);
checkNotNull(apiKey);
Map<String, Map<CkanGroup, RolesCkanGroupOrOrg>> toReturn = new HashMap<String, Map<CkanGroup,RolesCkanGroupOrOrg>>();
try{
String ckanUsername = CatalogueUtilMethods.fromUsernameToCKanUsername(username);
Map<String, RolesCkanGroupOrOrg> partialResult = dbCaller.getGroupsByUserFromDB(ckanUsername);
for (String groupID : partialResult.keySet()) {
CkanGroup group = ckanCaller.getGroup(groupID);
HashMap<CkanGroup, RolesCkanGroupOrOrg> subMap = new HashMap<CkanGroup, RolesCkanGroupOrOrg>();
subMap.put(group, partialResult.get(groupID));
toReturn.put(groupID, subMap);
}
LOG.debug("Returning map " + toReturn);
}catch(Exception e){
LOG.error("Failed to retrieve roles of user in his/her own groups",e);
}
return toReturn;
}
/**
* Retrieve an url for the tuple scope, entity, entity name
* @param context
* @param entityContext
* @param entityName
*/
private String getUrlForProduct(String context, EntityContext entityContext, String entityName){
String toReturn = null;
try (CloseableHttpClient httpClient = HttpClientBuilder.create().build()) {
HttpPost httpPostRequest = new HttpPost(getUriResolverUrl());
JSONObject requestEntity = new JSONObject();
requestEntity.put("gcube_scope", context);
requestEntity.put("entity_context", entityContext.toString());
requestEntity.put("entity_name", entityName);
StringEntity params = new StringEntity(requestEntity.toJSONString(), ContentType.APPLICATION_JSON);
httpPostRequest.setEntity(params);
HttpResponse response = httpClient.execute(httpPostRequest);
if(response.getStatusLine().getStatusCode() != 200)
throw new Exception("There was an error while creating an url " + response.getStatusLine());
toReturn = EntityUtils.toString(response.getEntity());
LOG.debug("Result is " + toReturn);
}catch(Exception e){
LOG.error("Failed to get an url for this product", e);
}
return toReturn;
}
@Override
public String getUriResolverUrl() {
return URI_RESOLVER_URL;
}
/**
* Check if the manage product is enabled
* @return
*/
@Override
public boolean isManageProductEnabled() {
return MANAGE_PRODUCT_BUTTON;
}
@Override
public List<CkanOrganization> getOrganizationsByUser(String username) {
LOG.debug("Requested organizations for user " + username);
// checks
checkNotNull(username);
// in order to avoid errors, the username is always converted
String ckanUsername = CatalogueUtilMethods.fromUsernameToCKanUsername(username);
// list to return
List<CkanOrganization> toReturn = new ArrayList<CkanOrganization>();
try{
// get the list of all organizations
List<CkanOrganization> organizations = ckanCaller.getOrganizationList();
// iterate over them
for (CkanOrganization ckanOrganization : organizations) {
// get the list of users in it (if you try ckanOrganization.getUsers() it returns null.. maybe a bug TODO)
List<CkanUser> users = ckanCaller.getOrganization(ckanOrganization.getName()).getUsers();
// check if the current user is among them
for (CkanUser ckanUser : users) {
if(ckanUser.getName().equals(ckanUsername)){
LOG.debug("User " + ckanUsername + " is into " + ckanOrganization.getName());
toReturn.add(ckanOrganization);
break;
}
}
}
}catch(Exception e){
LOG.error("Unable to get user's organizations", e);
}
return toReturn;
}
@Override
public List<CkanGroup> getGroupsByUser(String username) {
LOG.debug("Requested groups for user " + username);
// checks
checkNotNull(username);
// in order to avoid errors, the username is always converted
String ckanUsername = CatalogueUtilMethods.fromUsernameToCKanUsername(username);
// list to return
List<CkanGroup> toReturn = new ArrayList<CkanGroup>();
try{
// get the list of all organizations
List<CkanGroup> groups = ckanCaller.getGroupList();
// iterate over them
for (CkanGroup ckanGroup : groups) {
List<CkanUser> users = ckanCaller.getGroup(ckanGroup.getName()).getUsers();
// check if the current user is among them
for (CkanUser ckanUser : users) {
if(ckanUser.getName().equals(ckanUsername)){
LOG.debug("User " + ckanUsername + " is into " + ckanGroup.getName());
toReturn.add(ckanGroup);
break;
}
}
}
}catch(Exception e){
LOG.error("Unable to get user's groups", e);
}
return toReturn;
}
//@Override
private String getApiKeyFromUsername(String username) {
LOG.debug("Request api key for user = " + username);
// checks
checkNotNull(username);
checkArgument(!username.isEmpty());
// in order to avoid errors, the username is always converted
String ckanUsername = CatalogueUtilMethods.fromUsernameToCKanUsername(username);
// check in the hashmap first
if(apiKeysMap.containsKey(ckanUsername)){
CKANTokenBean bean = apiKeysMap.get(ckanUsername);
if(bean.timestamp + EXPIRE_KEY_TIME > System.currentTimeMillis()){ // it's still ok
return bean.apiKey;
}
}
LOG.debug("Api key was not in cache or it expired");
try{
String apiToReturn = dbCaller.getApiKeyFromUsername(username, State.ACTIVE.name().toLowerCase());
// save into the hashmap
if(apiToReturn != null)
apiKeysMap.put(ckanUsername, new CKANTokenBean(apiToReturn, System.currentTimeMillis()));
return apiToReturn;
}catch(Exception e){
LOG.error("Unable to retrieve key for user " + ckanUsername, e);
}
return null;
}
/*
*
*
*
*
*
*
*
*
*
* WRITE OPERATIONS
*
*
*
*
*
*
*
*
*
*
*/
public boolean patchProductCustomFields(String productId, Map<String, List<String>> customFieldsToChange,
boolean removeOld) {
return false;
}
public String addResourceToDataset(ResourceBean resource) throws Exception {
return null;
}
public boolean deleteResourceFromDataset(String resourceId) {
return false;
}
public boolean existProductWithNameOrId(String nameOrId) {
return false;
}
}

View File

@ -0,0 +1,690 @@
package org.gcube.datacatalogue.ckanutillibrary.server;
import static org.gcube.resources.discovery.icclient.ICFactory.client;
import static org.gcube.resources.discovery.icclient.ICFactory.clientFor;
import static org.gcube.resources.discovery.icclient.ICFactory.queryFor;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.gcube.common.encryption.StringEncrypter;
import org.gcube.common.resources.gcore.ServiceEndpoint;
import org.gcube.common.resources.gcore.ServiceEndpoint.AccessPoint;
import org.gcube.common.resources.gcore.ServiceEndpoint.Property;
import org.gcube.common.resources.gcore.utils.XPathHelper;
import org.gcube.common.scope.api.ScopeProvider;
import org.gcube.datacatalogue.ckanutillibrary.shared.ex.ApplicationProfileNotFoundException;
import org.gcube.datacatalogue.ckanutillibrary.shared.ex.NoApplicationProfileMasterException;
import org.gcube.datacatalogue.ckanutillibrary.shared.ex.NoDataCatalogueRuntimeResourceException;
import org.gcube.datacatalogue.ckanutillibrary.shared.ex.ServiceEndPointException;
import org.gcube.resources.discovery.client.api.DiscoveryClient;
import org.gcube.resources.discovery.client.queries.api.Query;
import org.gcube.resources.discovery.client.queries.api.SimpleQuery;
import org.gcube.resources.discovery.client.queries.impl.QueryBox;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
/**
* Retrieve ckan running instance information in the infrastructure (for both its database and data catalogue url).
*
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
* updated by Francesco Mangiacrapa at ISTI-CNR (francesco.mangiacrapa@isti.cnr.it)
*/
public class DataCatalogueRunningCluster {
//logger
private static final Logger logger = LoggerFactory.getLogger(DataCatalogueRunningCluster.class);
// database of the datacatalogue info
private final static String RUNTIME_DB_RESOURCE_NAME = "CKanDatabase";
private final static String PLATFORM_DB_NAME = "postgres";
private final static String APPLICATION_PROFILE_NAME = "CkanPortlet";
// data catalogue info
private final static String RUNTIME_CATALOGUE_RESOURCE_NAME = "CKanDataCatalogue";
private final static String PLATFORM_CATALOGUE_NAME = "Tomcat";
// api key property for SYSADMIN
private final static String API_KEY_PROPERTY = "API_KEY";
// catalogue email
private final static String CKAN_EMAIL_PROPERTY = "CATALOGUE_EMAIL";
// property to retrieve the master service endpoint into the /root scope
private final static String IS_MASTER_ROOT_KEY_PROPERTY = "IS_ROOT_MASTER"; // true, false.. missing means false as well
private final static String IS_MANAGE_PRODUCT_ENABLED = "IS_MANAGE_PRODUCT_ENABLED"; // true, false.. missing means false as well (for GRSF records)
private final static String SOCIAL_POST = "SOCIAL_POST";
private final static String ALERT_USERS_ON_POST_CREATION = "ALERT_USERS_ON_POST_CREATION";
private final static String SOLR_INDEX_ADDRESS = "SOLR_INDEX_ADDRESS";
// url of the http uri for this scope
private final static String URL_RESOLVER = "URL_RESOLVER";
// Other generic resource for delegating roles in groups to users
private final static String CATALOGUE_EXTENDING_ROLES = "CatalogueDelegateRoles";
// retrieved data
private List<String> datacatalogueUrls = new ArrayList<String>();
private List<String> hostsDB = new ArrayList<String>();
private List<Integer> portsDB = new ArrayList<Integer>();
private String nameDB;
private String userDB;
private String passwordDB;
private String portletUrl;
private String urlSolr;
private boolean manageProductEnabled;
private String urlResolver;
private boolean socialPost;
private boolean alertUsers;
private Map<String, String> extendRoleInOrganization = new HashMap<String, String>(0);
// generic role key
public static final String CKAN_GENERIC_ROLE = "*";
public static final String ROLE_ORGANIZATION_SEPARATOR = "|";
public static final String TUPLES_SEPARATOR = ",";
private static final String DEFAULT_CATALOGUE_EMAIL = "catalogue@d4science.org";
/**
* The Enum ACCESS_LEVEL_TO_CATALOGUE_PORTLET.
*
* @author Francesco Mangiacrapa at ISTI-CNR (francesco.mangiacrapa@isti.cnr.it)
*
* Nov 12, 2019
*/
//Added by Francesco, see #18039
public static final String PUBLIC_VRE_CATALOGUE_URL = "public-vre-url";
public static enum ACCESS_LEVEL_TO_CATALOGUE_PORTLET {PUBLIC_GATEWAY, PUBLIC_VRE, PRIVATE_VRE};
public Map<ACCESS_LEVEL_TO_CATALOGUE_PORTLET, String> mapAccessURLToCatalogue;
// this token is needed in order to assign roles to user
private String sysAdminToken;
private String catalogueEmail;
/**
* Instantiates a new data catalogue running cluster.
*
* @param scope the scope
* @throws Exception the exception
*/
public DataCatalogueRunningCluster(String scope) throws Exception{
if(scope == null || scope.isEmpty())
throw new Exception("Invalid scope!!");
// retrieve the current scope and save it (it will be reset later)
String currentScope = ScopeProvider.instance.get();
logger.info("Retrieving ckan database service end point information for scope " + scope);
try {
// set the scope
ScopeProvider.instance.set(scope);
logger.debug("Retrieving database information.");
List<ServiceEndpoint> resources = getConfigurationFromISFORDB();
evaluateRightConfigurationDB(resources);
logger.debug("Retrieving ckan data catalogue service end point information and sysadmin token.");
resources = getConfigurationFromISFORCatalogueUrl();
evaluateRightConfigurationCatalogue(resources);
// finally get the url in which the ckan portlet is deployed
logger.debug("Looking for portlet url in " + ScopeProvider.instance.get() + " scope" );
//portletUrl = getPortletUrlFromInfrastrucure();
mapAccessURLToCatalogue = getPortletUrlFromInfrastrucure();
portletUrl = mapAccessURLToCatalogue.get(ACCESS_LEVEL_TO_CATALOGUE_PORTLET.PRIVATE_VRE);
// and parse the CatalogueDelegateRole resource, if any, in this context
parseExtendingRoles();
}catch(Exception e) {
logger.warn("The following error occurred: " + e.toString());
throw e;
}finally{
ScopeProvider.instance.set(currentScope);
}
}
/**
* Evaluate the right configuration about ckan.
*
* @param resources the resources
* @throws NoDataCatalogueRuntimeResourceException the no data catalogue runtime resource exception
* @throws ServiceEndPointException the service end point exception
*/
private void evaluateRightConfigurationCatalogue(
List<ServiceEndpoint> resources) throws NoDataCatalogueRuntimeResourceException, ServiceEndPointException {
if (resources.size() == 0){
logger.error("There is no Runtime Resource having name " + RUNTIME_CATALOGUE_RESOURCE_NAME +" and Platform " + PLATFORM_CATALOGUE_NAME + " in this scope.");
throw new NoDataCatalogueRuntimeResourceException();
}
else {
logger.debug(resources.toString());
try{
if(resources.size() > 1){
boolean oneWasMaster = false;
logger.info("Too many Runtime Resource having name " + RUNTIME_CATALOGUE_RESOURCE_NAME +" in this scope.. Looking for the one that has the property " + IS_MASTER_ROOT_KEY_PROPERTY);
for (ServiceEndpoint res : resources) {
Iterator<AccessPoint> accessPointIterator = res.profile().accessPoints().iterator();
while (accessPointIterator.hasNext()) {
ServiceEndpoint.AccessPoint accessPoint = accessPointIterator
.next();
// get the is master property
Property entry = accessPoint.propertyMap().get(IS_MASTER_ROOT_KEY_PROPERTY);
String isMaster = entry != null ? entry.value() : null;
if(isMaster == null || !isMaster.equals("true"))
continue;
// set this variable
oneWasMaster = true;
// add this host
datacatalogueUrls.add(accessPoint.address());
// retrieve sys admin token
sysAdminToken = accessPoint.propertyMap().get(API_KEY_PROPERTY).value();
sysAdminToken = StringEncrypter.getEncrypter().decrypt(sysAdminToken);
// retrieve catalogue email
if(accessPoint.propertyMap().containsKey(CKAN_EMAIL_PROPERTY)){
catalogueEmail = accessPoint.propertyMap().get(CKAN_EMAIL_PROPERTY).value();
catalogueEmail = StringEncrypter.getEncrypter().decrypt(catalogueEmail);
}
// retrieve URL_RESOLVER
if(accessPoint.propertyMap().containsKey(URL_RESOLVER))
urlResolver = accessPoint.propertyMap().get(URL_RESOLVER).value();
// break now
break;
}
}
// if none of them was master, throw an exception
if(!oneWasMaster)
throw new NoApplicationProfileMasterException("There is no application profile with MASTER property");
}else{
ServiceEndpoint res = resources.get(0);
Iterator<AccessPoint> accessPointIterator = res.profile().accessPoints().iterator();
while (accessPointIterator.hasNext()) {
ServiceEndpoint.AccessPoint accessPoint = accessPointIterator
.next();
// add this host
datacatalogueUrls.add(accessPoint.address());
// retrieve sys admin token
sysAdminToken = accessPoint.propertyMap().get(API_KEY_PROPERTY).value();
sysAdminToken = StringEncrypter.getEncrypter().decrypt(sysAdminToken);
// retrieve catalogue email
if(accessPoint.propertyMap().containsKey(CKAN_EMAIL_PROPERTY)){
catalogueEmail = accessPoint.propertyMap().get(CKAN_EMAIL_PROPERTY).value();
catalogueEmail = StringEncrypter.getEncrypter().decrypt(catalogueEmail);
}
// get the is manage product property
Property entry = accessPoint.propertyMap().get(IS_MANAGE_PRODUCT_ENABLED);
String isManageProduct = entry != null ? entry.value() : null;
if(isManageProduct != null && isManageProduct.equals("true")){
logger.info("Manage product is enabled in this scope");
manageProductEnabled = true;
}
// retrieve option to check if the social post has to be made
socialPost = true; // default is true
if(accessPoint.propertyMap().containsKey(SOCIAL_POST))
if(accessPoint.propertyMap().get(SOCIAL_POST).value().trim().equalsIgnoreCase("false"))
socialPost = false;
// retrieve option for user alert
if(accessPoint.propertyMap().containsKey(ALERT_USERS_ON_POST_CREATION))
if(accessPoint.propertyMap().get(ALERT_USERS_ON_POST_CREATION).value().trim().equalsIgnoreCase("true"))
alertUsers = true;
// retrieve URL_RESOLVER
if(accessPoint.propertyMap().containsKey(URL_RESOLVER))
urlResolver = accessPoint.propertyMap().get(URL_RESOLVER).value();
// retrieve url of the solr index for further queries
if(accessPoint.propertyMap().containsKey(SOLR_INDEX_ADDRESS))
urlSolr = accessPoint.propertyMap().get(SOLR_INDEX_ADDRESS).value();
}
}
}catch(Exception e){
throw new ServiceEndPointException("There is no service end point for such information" + e.toString());
}
}
}
/**
* Retrieve the right DB information.
*
* @param resources the resources
* @throws ServiceEndPointException the service end point exception
* @throws NoDataCatalogueRuntimeResourceException the no data catalogue runtime resource exception
*/
private void evaluateRightConfigurationDB(List<ServiceEndpoint> resources) throws ServiceEndPointException, NoDataCatalogueRuntimeResourceException {
if (resources.size() == 0){
throw new NoDataCatalogueRuntimeResourceException("There is no Runtime Resource having name " + RUNTIME_DB_RESOURCE_NAME +" and Platform " + PLATFORM_DB_NAME + " in this scope.");
}
else {
try{
if(resources.size() > 1){
boolean oneWasMaster = false;
logger.info("Too many Runtime Resource having name " + RUNTIME_DB_RESOURCE_NAME +" in this scope.. Looking for the one that has the property " + IS_MASTER_ROOT_KEY_PROPERTY);
for (ServiceEndpoint res : resources) {
Iterator<AccessPoint> accessPointIterator = res.profile().accessPoints().iterator();
while (accessPointIterator.hasNext()) {
ServiceEndpoint.AccessPoint accessPoint = accessPointIterator
.next();
// get the is master property
Property entry = accessPoint.propertyMap().get(IS_MASTER_ROOT_KEY_PROPERTY);
String isMaster = entry != null ? entry.value() : null;
if(isMaster == null || !isMaster.equals("true"))
continue;
// set this variable
oneWasMaster = true;
// add this host
hostsDB.add(accessPoint.address().split(":")[0]);
// save the port
int port = Integer.parseInt(accessPoint.address().split(":")[1]);
portsDB.add(port);
// save the name of the cluster (this should be unique)
nameDB = accessPoint.name();
// save user and password
passwordDB = StringEncrypter.getEncrypter().decrypt(accessPoint.password());
userDB = accessPoint.username();
// now break
break;
}
}
// if none of them was master, throw an exception
if(!oneWasMaster)
throw new NoApplicationProfileMasterException("There is no application profile with MASTER property");
}else{
logger.debug(resources.toString());
ServiceEndpoint res = resources.get(0);
Iterator<AccessPoint> accessPointIterator = res.profile().accessPoints().iterator();
while (accessPointIterator.hasNext()) {
ServiceEndpoint.AccessPoint accessPoint = accessPointIterator
.next();
// add this host
hostsDB.add(accessPoint.address().split(":")[0]);
// save the port
int port = Integer.parseInt(accessPoint.address().split(":")[1]);
portsDB.add(port);
// save the name of the cluster (this should be unique)
nameDB = accessPoint.name();
// save user and password
passwordDB = StringEncrypter.getEncrypter().decrypt(accessPoint.password());
userDB = accessPoint.username();
}
}
}catch(Exception e ){
throw new ServiceEndPointException(e.toString());
}
}
}
/**
* Retrieve endpoints information from IS for DB.
*
* @return list of endpoints for ckan database
* @throws Exception the exception
*/
private static List<ServiceEndpoint> getConfigurationFromISFORDB() throws Exception{
SimpleQuery query = queryFor(ServiceEndpoint.class);
query.addCondition("$resource/Profile/Name/text() eq '"+ RUNTIME_DB_RESOURCE_NAME +"'");
query.addCondition("$resource/Profile/Platform/Name/text() eq '"+ PLATFORM_DB_NAME +"'");
DiscoveryClient<ServiceEndpoint> client = clientFor(ServiceEndpoint.class);
List<ServiceEndpoint> toReturn = client.submit(query);
return toReturn;
}
/**
* Retrieve endpoints information from IS for DataCatalogue URL.
*
* @return list of endpoints for ckan data catalogue
* @throws Exception the exception
*/
private static List<ServiceEndpoint> getConfigurationFromISFORCatalogueUrl() throws Exception{
SimpleQuery query = queryFor(ServiceEndpoint.class);
query.addCondition("$resource/Profile/Name/text() eq '"+ RUNTIME_CATALOGUE_RESOURCE_NAME +"'");
query.addCondition("$resource/Profile/Platform/Name/text() eq '"+ PLATFORM_CATALOGUE_NAME +"'");
DiscoveryClient<ServiceEndpoint> client = clientFor(ServiceEndpoint.class);
List<ServiceEndpoint> toReturn = client.submit(query);
return toReturn;
}
/**
* Retrieve the url of the ckan portlet deployed into this scope
* updated by Francesco see Feature #18039.
*
* @return the portlet url from infrastrucure
*/
private static Map<ACCESS_LEVEL_TO_CATALOGUE_PORTLET,String> getPortletUrlFromInfrastrucure() {
String scope = ScopeProvider.instance.get();
logger.debug("Trying to fetch applicationProfile profile from the infrastructure for " + APPLICATION_PROFILE_NAME + " scope: " + scope);
Map<ACCESS_LEVEL_TO_CATALOGUE_PORTLET,String> mapAccess = new HashMap<ACCESS_LEVEL_TO_CATALOGUE_PORTLET,String>(3);
try {
Query q = new QueryBox("for $profile in collection('/db/Profiles/GenericResource')//Resource " +
"where $profile/Profile/SecondaryType/string() eq 'ApplicationProfile' and $profile/Profile/Name/string() " +
" eq '" + APPLICATION_PROFILE_NAME + "'" +
"return $profile");
DiscoveryClient<String> client = client();
List<String> appProfile = client.submit(q);
if (appProfile == null || appProfile.size() == 0)
throw new ApplicationProfileNotFoundException("Your applicationProfile is not registered in the infrastructure");
else {
String elem = appProfile.get(0);
DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Node node = docBuilder.parse(new InputSource(new StringReader(elem))).getDocumentElement();
XPathHelper helper = new XPathHelper(node);
List<String> currValue = null;
currValue = helper.evaluate("/Resource/Profile/Body/url/text()");
if (currValue != null && currValue.size() > 0) {
logger.debug("Private portlet url found is " + currValue.get(0));
//return currValue.get(0);
mapAccess.put(ACCESS_LEVEL_TO_CATALOGUE_PORTLET.PRIVATE_VRE, currValue.get(0));
}
currValue = null;
currValue = helper.evaluate("/Resource/Profile/Body/"+PUBLIC_VRE_CATALOGUE_URL+"/text()");
if (currValue != null && currValue.size() > 0) {
logger.debug(PUBLIC_VRE_CATALOGUE_URL+" portlet url found is " + currValue.get(0));
//return currValue.get(0);
mapAccess.put(ACCESS_LEVEL_TO_CATALOGUE_PORTLET.PUBLIC_VRE, currValue.get(0));
}
}
} catch (Exception e) {
logger.error("Error while trying to fetch applicationProfile profile from the infrastructure", e);
}
return mapAccess;
}
/**
* Parse the CatalogueDelegateRoles in this context.
*
* @throws ParserConfigurationException the parser configuration exception
* @throws SAXException the SAX exception
* @throws IOException Signals that an I/O exception has occurred.
*/
private void parseExtendingRoles() throws ParserConfigurationException, SAXException, IOException {
Query q = new QueryBox("for $profile in collection('/db/Profiles/GenericResource')//Resource " +
"where $profile/Profile/SecondaryType/string() eq 'ApplicationProfile' and $profile/Profile/Name/string() " +
" eq '" + CATALOGUE_EXTENDING_ROLES + "'" +
"return $profile");
DiscoveryClient<String> client = client();
List<String> appProfile = client.submit(q);
logger.debug("Resource for extending role has size " + appProfile.size());
if (appProfile == null || appProfile.size() == 0)
return;
else {
String profile = appProfile.get(0);
DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Node node = docBuilder.parse(new InputSource(new StringReader(profile))).getDocumentElement();
XPathHelper helper = new XPathHelper(node);
// fetch delegate elements
NodeList delegates = helper.evaluateForNodes("/Resource/Profile/Body/delegates/delegate");
if (delegates != null && delegates.getLength() > 0) {
for(int i = 0; i < delegates.getLength(); i++){
Node nodeI = delegates.item(i);
if(nodeI.getNodeType() == Node.ELEMENT_NODE) {
Element elem = (Element)nodeI;
String role = elem.getElementsByTagName("sourceRole").item(0).getTextContent();
String destOrg = elem.getElementsByTagName("destOrganization").item(0).getTextContent();
String sourceOrg = elem.getElementsByTagName("sourceOrganization").item(0).getTextContent();
if(destOrg == null || sourceOrg == null){
logger.warn("DestOrg or SourceOrg parameters missing");
continue;
}else{
String currentValueForKey = extendRoleInOrganization.get(sourceOrg);
if(currentValueForKey == null)
currentValueForKey = "";
else
currentValueForKey += TUPLES_SEPARATOR;
currentValueForKey += destOrg + ROLE_ORGANIZATION_SEPARATOR + role;
extendRoleInOrganization.put(sourceOrg, currentValueForKey);
}
}
}
}
}
logger.debug("Extended role map in this scope is " + extendRoleInOrganization);
}
/**
* Retrieve the ckan portlet url.
*
* @return the portletUrl
*/
public String getPortletUrl() {
return portletUrl;
}
/**
* Retrieve data catalogue url.
*
* @return the data catalogue url
*/
public List<String> getDataCatalogueUrl() {
return datacatalogueUrls;
}
/**
* Get the hosts for such resource.
*
* @return the database hosts
*/
public List<String> getDatabaseHosts() {
return hostsDB;
}
/**
* Get the ports for such resource.
*
* @return the database ports
*/
public List<Integer> getDatabasePorts() {
return portsDB;
}
/**
* Get the database name.
*
* @return the data base name
*/
public String getDataBaseName() {
return nameDB;
}
/**
* Get the database's user.
*
* @return the data base user
*/
public String getDataBaseUser() {
return userDB;
}
/**
* Get the database's password.
*
* @return the data base password
*/
public String getDataBasePassword() {
return passwordDB;
}
/**
* Gets the sys admin token.
*
* @return the sysAdminToken
*/
public String getSysAdminToken() {
return sysAdminToken;
}
/**
* Is manager product enabled (e.g., for GRSF records)
*
* @return true, if is manage product enabled
*/
public boolean isManageProductEnabled() {
return manageProductEnabled;
}
/**
* Get the url of the uri resolver for this instance/scope.
*
* @return the url resolver
*/
public String getUrlResolver() {
return urlResolver;
}
/**
* Check if alert user members is enabled.
*
* @return true, if is alert enabled
*/
public boolean isAlertEnabled() {
return alertUsers;
}
/**
* Get roles to extend.
*
* @return Map<String, String>
*/
public Map<String, String> getExtendRoleInOrganization() {
return extendRoleInOrganization;
}
/**
* Get the solr index base url.
*
* @return the url solr
*/
public String getUrlSolr() {
return urlSolr;
}
/**
* Gets the map access URL to catalogue.
*
* @return the map access URL to catalogue
*/
public Map<ACCESS_LEVEL_TO_CATALOGUE_PORTLET, String> getMapAccessURLToCatalogue() {
return mapAccessURLToCatalogue;
}
/**
* Get the catalogue email. Default is "catalogue@d4science.org"
*
* @return the email catalogue
*/
public String getEmailCatalogue() {
logger.debug("Read email from resource is " + catalogueEmail);
return catalogueEmail == null? DEFAULT_CATALOGUE_EMAIL : catalogueEmail;
}
/**
* Checks if is social post enabled.
*
* @return true, if is social post enabled
*/
public boolean isSocialPostEnabled() {
return socialPost;
}
}

View File

@ -0,0 +1,139 @@
package org.gcube.datacatalogue.ckanutillibrary.server.utils;
import java.net.HttpURLConnection;
import java.net.URL;
import org.gcube.common.scope.api.ScopeProvider;
import org.gcube.common.scope.impl.ScopeBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Some utility methods used within the library.
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
*/
public class CatalogueUtilMethods {
private static final Logger logger = LoggerFactory.getLogger(CatalogueUtilMethods.class);
private final static String HTTPS = "https";
private final static String HTTP = "http";
/**
* Maps the scope name to the ckan organization name
* Use getCKANOrganization() which uses current scope
* @return
*/
@Deprecated
public static String getOrganizationNameFromScope(String scope){
if(scope == null || scope.isEmpty()) {
throw new IllegalArgumentException("scope cannot be null");
}
ScopeBean scopeBean = new ScopeBean(scope);
return scopeBean.name().toLowerCase().replace(" ", "_").replace("-", "_");
}
/**
* Get CKAN Organization name by using scope name
*
*/
public static String getCKANOrganization() {
ScopeBean scopeBean = new ScopeBean(ScopeProvider.instance.get());
return scopeBean.name().toLowerCase().replace(" ", "_").replace("-", "_");
}
/**
* Ckan username has _ instead of . (that is, costantino.perciante -> costantino_perciante)
* @param owner
* @return
*/
public static String fromUsernameToCKanUsername(String username){
if(username == null)
return null;
return username.trim().replaceAll("\\.", "_");
}
/**
* Liferay username has . instead of _ (that is, costantino_perciante -> costantino.perciante)
* @param owner
* @return
*/
public static String fromCKanUsernameToUsername(String ckanUsername){
if(ckanUsername == null)
return null;
return ckanUsername.trim().replaceAll("_", ".");
}
/**
* Generate the catalogue's dataset name from its title
* @param title
* @return
*/
public static String fromProductTitleToName(String title) {
if(title == null)
return null;
String regexTitleNameTransform = "[^A-Za-z0-9_-]";
return title.trim().replaceAll(regexTitleNameTransform, "_").replaceAll("_+", "_").toLowerCase();
}
/**
* Convert a display group name to group id
* @param groupName
* @return
*/
public static String fromGroupTitleToName(String groupName){
if(groupName == null)
return null;
String regexGroupNameTransform = "[^A-Za-z0-9-]";
String modified = groupName.trim().replaceAll(regexGroupNameTransform, "-").replaceAll("-+", "-").toLowerCase();
if(modified.startsWith("-"))
modified = modified.substring(1);
if(modified.endsWith("-"))
modified = modified.substring(0, modified.length() -1);
return modified;
}
/**
* Utility method to check if a something at this url actually exists
* @param URLName
* @return
*/
public static boolean resourceExists(String URLName){
if(URLName == null || URLName.isEmpty())
return false;
try {
// replace https
String urlToTest = URLName.replace(HTTPS, HTTP);
HttpURLConnection.setFollowRedirects(true);
HttpURLConnection con = (HttpURLConnection) new URL(urlToTest).openConnection();
con.setRequestMethod("HEAD");
logger.debug("Return code is " + con.getResponseCode());
return (con.getResponseCode() == HttpURLConnection.HTTP_OK);
}
catch (Exception e) {
logger.error("Exception while checking url", e);
return false;
}
}
/**
* Builds a string made of key + scope
* @param key
* @param scope
* @return
*/
public static String concatenateSessionKeyScope(String key, String scope){
if(key == null || scope == null)
throw new IllegalArgumentException("Key or scope null");
return key.concat(scope);
}
}

View File

@ -0,0 +1,17 @@
package org.gcube.datacatalogue.ckanutillibrary.server.utils;
/**
* A list of attributes that are saved into http session.
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
*/
public class SessionCatalogueAttributes {
// CKAN KEYS (PLEASE NOTE THAT MOST OF THESE INFO ARE SAVED INTO SESSION PER SCOPE)
public static final String CKAN_ORGS_USER_KEY = "ckanOrgs"; // organizations to whom he belongs (shown into the portlet)
public static final String CKAN_HIGHEST_ROLE = "ckanHighestRole"; // editor, member, admin
public static final String CKAN_ORGANIZATIONS_PUBLISH_KEY = "ckanOrganizationsPublish"; // here he can publish (admin/editor role)
public static final String CKAN_LICENSES_KEY = "ckanLicenses"; // licenses
public static final String CKAN_PROFILES_KEY = "ckanProfiles"; // product profiles
public static final String CKAN_GROUPS_MEMBER = "ckanGroupsMember";
public static final String CKAN_GROUPS_USER_KEY = "ckanGroups"; // to show the list of groups in the portlet
}

View File

@ -0,0 +1,24 @@
package org.gcube.datacatalogue.ckanutillibrary.server.utils.url;
/**
* Entity context for uri resolver
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
*/
public enum EntityContext {
DATASET("dataset"),
GROUP("group"),
ORGANIZATION("organization");
private String entityAsString;
private EntityContext(String entityAsString) {
this.entityAsString = entityAsString;
}
@Override
public String toString() {
return this.entityAsString;
}
}

View File

@ -0,0 +1,134 @@
package org.gcube.datacatalogue.ckanutillibrary.shared;
import java.io.Serializable;
/**
* A CKan user.
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
*/
public class CKanUserWrapper implements Serializable{
private static final long serialVersionUID = 6264706263035722775L;
private String id;
private String name;
private String apiKey;
private long creationTimestamp;
private String about;
private String openId;
private String fullName;
private String email;
private boolean isAdmin;
public CKanUserWrapper() {
super();
}
/** Create a ckan user object.
* @param id
* @param name
* @param apiKey
* @param creationTimestamp
* @param about
* @param openId
* @param fullName
* @param email
* @param isAdmin
*/
public CKanUserWrapper(String id, String name, String apiKey,
long creationTimestamp, String about, String openId,
String fullName, String email, boolean isAdmin) {
super();
this.id = id;
this.name = name;
this.apiKey = apiKey;
this.creationTimestamp = creationTimestamp;
this.about = about;
this.openId = openId;
this.fullName = fullName;
this.email = email;
this.isAdmin = isAdmin;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getApiKey() {
return apiKey;
}
public void setApiKey(String apiKey) {
this.apiKey = apiKey;
}
public long getCreationTimestamp() {
return creationTimestamp;
}
public void setCreationTimestamp(long creationTimestamp) {
this.creationTimestamp = creationTimestamp;
}
public String getAbout() {
return about;
}
public void setAbout(String about) {
this.about = about;
}
public String getOpenId() {
return openId;
}
public void setOpenId(String openId) {
this.openId = openId;
}
public String getFullName() {
return fullName;
}
public void setFullName(String fullName) {
this.fullName = fullName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public boolean isAdmin() {
return isAdmin;
}
public void setAdmin(boolean isAdmin) {
this.isAdmin = isAdmin;
}
@Override
public String toString() {
return "CKanUserExtended [id=" + id + ", name=" + name + ", apiKey=" + apiKey.substring(0, 5) + "****************"
+ ", creationTimestamp=" + creationTimestamp + ", about="
+ about + ", openId=" + openId + ", fullName=" + fullName
+ ", email=" + email + ", isAdmin=" + isAdmin + "]";
}
}

View File

@ -0,0 +1,96 @@
package org.gcube.datacatalogue.ckanutillibrary.shared;
import static com.google.common.base.Preconditions.checkNotNull;
import org.json.simple.JSONObject;
/**
* A ckan dataset relationship. It is represented by the following fields
* <ul>
* <li> subject dataset id
* <li> object dataset id
* <li> type of the relationship
* <li> comment an optional comment
* </ul>
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
*/
public class CkanDatasetRelationship {
private String subject;
private String object;
private String comment;
private String type;
public CkanDatasetRelationship(){
super();
}
/**
* @param subject
* @param object
* @param comment
* @param type
*/
public CkanDatasetRelationship(String subject, String object,
String comment, String type) {
super();
this.subject = subject;
this.object = object;
this.comment = comment;
this.type = type;
}
/**
* From a json object that must have the properties listed in the class header (comment is optional)
* @param object
*/
public CkanDatasetRelationship(JSONObject object) {
this.comment = (String) object.get("comment");
this.object = (String) object.get("object");
this.subject = (String) object.get("subject");
this.type = (String) object.get("type"); // TODO convert to one of enums DatasetRelationships
checkNotNull(object);
checkNotNull(subject);
checkNotNull(type);
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public String getObject() {
return object;
}
public void setObject(String object) {
this.object = object;
}
public String getComment() {
return comment;
}
public void setComment(String comment) {
this.comment = comment;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
@Override
public String toString() {
return "CkanDatasetRelationship [subject=" + subject + ", object="
+ object + ", comment=" + comment + ", type=" + type
+ "]";
}
}

View File

@ -0,0 +1,27 @@
package org.gcube.datacatalogue.ckanutillibrary.shared;
/**
* Allowed relationships between packages(datasets). Some of them are not supported yet due to the problem
* reported here https://support.d4science.org/issues/4455
* <ul>
* <li> depends_on
* <li> dependency_of
* <li> derives_from
* <li> has_derivation
* <li> child_of
* <li> parent_of
* <li> links_to
* <li> linked_from
* </ul>
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
*/
public enum DatasetRelationships {
depends_on,
dependency_of,
derives_from,
has_derivation,
child_of,
parent_of,
links_to,
linked_from
}

View File

@ -0,0 +1,57 @@
package org.gcube.datacatalogue.ckanutillibrary.shared;
import java.io.Serializable;
/**
* This bean offers the following information:
* <ul>
* <li> landing page url to the items page (within the portlet)
* <li> landing page url to the orgs page (within the portlet)
* <li> landing page url to the groups page (within the portlet)
* <li> landing page url to the types page (within the portlet)
* </ul>
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
*/
public class LandingPages implements Serializable {
private static final long serialVersionUID = -5617896049674346109L;
private String urlTypes;
private String urlOrganizations;
private String urlGroups;
private String urlItems;
public LandingPages() {
super();
}
public String getUrlTypes() {
return urlTypes;
}
public void setUrlTypes(String urlTypes) {
this.urlTypes = urlTypes;
}
public String getUrlOrganizations() {
return urlOrganizations;
}
public void setUrlOrganizations(String urlOrganizations) {
this.urlOrganizations = urlOrganizations;
}
public String getUrlGroups() {
return urlGroups;
}
public void setUrlGroups(String urlGroups) {
this.urlGroups = urlGroups;
}
public String getUrlItems() {
return urlItems;
}
public void setUrlItems(String urlItems) {
this.urlItems = urlItems;
}
@Override
public String toString() {
return "LandingPages [urlTypes=" + urlTypes + ", urlOrganizations="
+ urlOrganizations + ", urlGroups=" + urlGroups + ", urlItems="
+ urlItems + "]";
}
}

View File

@ -0,0 +1,152 @@
package org.gcube.datacatalogue.ckanutillibrary.shared;
import java.io.Serializable;
/**
* A bean that resembles the CKanResource bean object
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
*/
public class ResourceBean implements Serializable {
private static final long serialVersionUID = -5275448097250176185L;
private String url;
private String name;
private String description;
private String id;
private String owner;
private String datasetId;
private String mimeType;
public ResourceBean(){
super();
}
/**
* @param url
* @param name
* @param description
* @param id
* @param owner
* @param datasetId
* @param mimeType
*/
public ResourceBean(String url, String name, String description, String id,
String owner, String datasetId, String mimeType) {
super();
this.url = url;
this.name = name;
this.description = description;
this.id = id;
this.owner = owner;
this.datasetId = datasetId;
this.mimeType = mimeType;
}
/**
* @return the url
*/
public String getUrl() {
return url;
}
/**
* @param url the url to set
*/
public void setUrl(String url) {
this.url = url;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the description
*/
public String getDescription() {
return description;
}
/**
* @param description the description to set
*/
public void setDescription(String description) {
this.description = description;
}
/**
* @return the id
*/
public String getId() {
return id;
}
/**
* @param id the id to set
*/
public void setId(String id) {
this.id = id;
}
/**
* @return the owner
*/
public String getOwner() {
return owner;
}
/**
* @param owner the owner to set
*/
public void setOwner(String owner) {
this.owner = owner;
}
/**
* @return the datasetId
*/
public String getDatasetId() {
return datasetId;
}
/**
* @param datasetId the datasetId to set
*/
public void setDatasetId(String datasetId) {
this.datasetId = datasetId;
}
/**
* @return the mimeType
*/
public String getMimeType() {
return mimeType;
}
/**
* @param mimeType the mimeType to set
*/
public void setMimeType(String mimeType) {
this.mimeType = mimeType;
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "ResourceBean [url=" + url + ", name=" + name + ", description="
+ description + ", id=" + id + ", owner=" + owner
+ ", datasetId=" + datasetId + ", mimeType=" + mimeType + "]";
}
}

View File

@ -0,0 +1,39 @@
package org.gcube.datacatalogue.ckanutillibrary.shared;
/**
* Roles that user can have into organizations/groups.
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
*/
public enum RolesCkanGroupOrOrg{
MEMBER,
EDITOR,
ADMIN;
public static String convertToCkanCapacity(RolesCkanGroupOrOrg role){
if(role == null)
return null;
else
return role.toString().toLowerCase();
}
public static RolesCkanGroupOrOrg convertFromCapacity(String capacity){
if(capacity == null)
return null;
else
return RolesCkanGroupOrOrg.valueOf(capacity.toUpperCase());
}
/**
* Get the higher role between role1 and role2
* @param role1
* @param role2
* @return the higher role
*/
public static RolesCkanGroupOrOrg getHigher(RolesCkanGroupOrOrg role1, RolesCkanGroupOrOrg role2){
return role1.ordinal() > role2.ordinal() ? role1 : role2;
}
}

View File

@ -0,0 +1,10 @@
package org.gcube.datacatalogue.ckanutillibrary.shared;
/**
* The current state of this group/user
* @author Costantino Perciante at ISTI-CNR
* (costantino.perciante@isti.cnr.it)
*/
public enum State{
DELETED, ACTIVE
}

View File

@ -0,0 +1,54 @@
package org.gcube.datacatalogue.ckanutillibrary.shared;
import java.io.Serializable;
/**
* This bean offers the following statistics:
* <ul>
* <li> number of items of the catalogue
* <li> number of organizations of the catalogue
* <li> number of groups of the catalogue
* <li> number of types of the catalogue
* </ul>
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
*/
public class Statistics implements Serializable{
private static final long serialVersionUID = 2871906712366452266L;
private long numTypes;
private long numOrganizations;
private long numGroups;
private long numItems;
public long getNumTypes() {
return numTypes;
}
public void setNumTypes(long numTypes) {
this.numTypes = numTypes;
}
public long getNumOrganizations() {
return numOrganizations;
}
public void setNumOrganizations(long numOrganizations) {
this.numOrganizations = numOrganizations;
}
public long getNumGroups() {
return numGroups;
}
public void setNumGroups(long numGroups) {
this.numGroups = numGroups;
}
public long getNumItems() {
return numItems;
}
public void setNumItems(long numItems) {
this.numItems = numItems;
}
@Override
public String toString() {
return "Statistics [numTypes=" + numTypes + ", numOrganizations="
+ numOrganizations + ", numGroups=" + numGroups + ", numItems="
+ numItems + "]";
}
}

View File

@ -0,0 +1,12 @@
package org.gcube.datacatalogue.ckanutillibrary.shared.ex;
@SuppressWarnings("serial")
/**
* Thrown when no application profile with such information is found
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
*/
public class ApplicationProfileNotFoundException extends Exception {
public ApplicationProfileNotFoundException(String message) {
super(message);
}
}

View File

@ -0,0 +1,20 @@
package org.gcube.datacatalogue.ckanutillibrary.shared.ex;
/**
* Thrown when there are more than one application profile, but none of them was set as master
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
*/
public class NoApplicationProfileMasterException extends Exception {
private static final long serialVersionUID = 5874713540422734005L;
private static final String DEFAULT_MESSAGE = "There is more than one application profile into this scope"
+ " but none of them is set as master!";
public NoApplicationProfileMasterException(){
super(DEFAULT_MESSAGE);
}
public NoApplicationProfileMasterException(String message) {
super(message);
}
}

View File

@ -0,0 +1,21 @@
package org.gcube.datacatalogue.ckanutillibrary.shared.ex;
/**
* No Data Catalogue node found.
* @author Costantino Perciante at ISTI-CNR
* (costantino.perciante@isti.cnr.it)
*/
public class NoDataCatalogueRuntimeResourceException extends Exception {
private static final long serialVersionUID = -40748130477807648L;
private static final String DEFAULT_MESSAGE = "No Data Catalogue instance for this scope!";
public NoDataCatalogueRuntimeResourceException(){
super(DEFAULT_MESSAGE);
}
public NoDataCatalogueRuntimeResourceException(String message) {
super(message);
}
}

View File

@ -0,0 +1,19 @@
package org.gcube.datacatalogue.ckanutillibrary.shared.ex;
/**
* Exception thrown when it is not possible retrieve information from the ServiceEndpoint
* related to the Data Catalogue
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
*/
public class ServiceEndPointException extends Exception {
private static final long serialVersionUID = 7057074369001221035L;
private static final String DEFAULT_MESSAGE = "Unable to retrieve information from Data Catalogue endpoint!";
public ServiceEndPointException(){
super(DEFAULT_MESSAGE);
}
public ServiceEndPointException(String string) {
super(string);
}
}

View File

@ -0,0 +1,22 @@
package org.gcube.datacatalogue.ckanutillibrary.shared.ex;
/**
* Too many clusters in this scope exception.
* @author Costantino Perciante at ISTI-CNR
* (costantino.perciante@isti.cnr.it)
*
*/
public class TooManyRunningClustersException extends Exception {
private static final long serialVersionUID = -7847493730006647045L;
private static final String DEFAULT_MESSAGE = "Too many CKan data catalague instances for this scope!";
public TooManyRunningClustersException(){
super(DEFAULT_MESSAGE);
}
public TooManyRunningClustersException(String message) {
super(message);
}
}