initial commit
This commit is contained in:
commit
bffb8f3d98
|
@ -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>
|
|
@ -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>
|
|
@ -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
|
|
@ -0,0 +1,4 @@
|
|||
activeProfiles=
|
||||
eclipse.preferences.version=1
|
||||
resolveWorkspaceProjects=true
|
||||
version=1
|
|
@ -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>
|
|
@ -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>
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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 + "]";
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
||||
+ "]";
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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 + "]";
|
||||
}
|
||||
|
||||
}
|
|
@ -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 + "]";
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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 + "]";
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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}
|
||||
|
|
@ -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
|
|
@ -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>
|
|
@ -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>
|
Binary file not shown.
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -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);
|
||||
|
||||
}
|
Binary file not shown.
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
|
@ -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;
|
||||
}
|
||||
}
|
Binary file not shown.
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
|
@ -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);
|
||||
|
||||
}
|
Binary file not shown.
Binary file not shown.
|
@ -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());
|
||||
}
|
||||
}
|
Binary file not shown.
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
Binary file not shown.
Binary file not shown.
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
|
@ -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
|
||||
}
|
Binary file not shown.
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
|
@ -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 + "]";
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
|
@ -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
|
||||
+ "]";
|
||||
}
|
||||
}
|
Binary file not shown.
|
@ -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
|
||||
}
|
Binary file not shown.
|
@ -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 + "]";
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
|
@ -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 + "]";
|
||||
}
|
||||
}
|
Binary file not shown.
|
@ -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;
|
||||
}
|
||||
}
|
Binary file not shown.
|
@ -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
|
||||
}
|
Binary file not shown.
|
@ -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 + "]";
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
|
@ -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);
|
||||
}
|
||||
}
|
Binary file not shown.
|
@ -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);
|
||||
}
|
||||
}
|
Binary file not shown.
|
@ -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);
|
||||
}
|
||||
}
|
Binary file not shown.
|
@ -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);
|
||||
}
|
||||
}
|
Binary file not shown.
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue