ckan-util-library/src/main/java/org/gcube/datacatalogue/ckanutillibrary/server/DataCatalogueImpl.java

2515 lines
80 KiB
Java

package org.gcube.datacatalogue.ckanutillibrary.server;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import net.htmlparser.jericho.Renderer;
import net.htmlparser.jericho.Segment;
import net.htmlparser.jericho.Source;
import org.gcube.datacatalogue.ckanutillibrary.server.models.CKanUserWrapper;
import org.gcube.datacatalogue.ckanutillibrary.server.models.CkanDatasetRelationship;
import org.gcube.datacatalogue.ckanutillibrary.server.models.DatasetRelationships;
import org.gcube.datacatalogue.ckanutillibrary.server.models.ResourceBean;
import org.gcube.datacatalogue.ckanutillibrary.server.models.State;
import org.gcube.datacatalogue.ckanutillibrary.server.utils.UtilMethods;
import org.gcube.datacatalogue.ckanutillibrary.server.utils.url.EntityContext;
import org.gcube.datacatalogue.ckanutillibrary.shared.RolesCkanGroupOrOrg;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.JSONValue;
import org.json.simple.parser.JSONParser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import eu.trentorise.opendata.jackan.CheckedCkanClient;
import eu.trentorise.opendata.jackan.CkanClient;
import eu.trentorise.opendata.jackan.exceptions.JackanException;
import eu.trentorise.opendata.jackan.internal.org.apache.http.HttpEntity;
import eu.trentorise.opendata.jackan.internal.org.apache.http.HttpResponse;
import eu.trentorise.opendata.jackan.internal.org.apache.http.HttpStatus;
import eu.trentorise.opendata.jackan.internal.org.apache.http.client.methods.HttpGet;
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.entity.mime.MultipartEntityBuilder;
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.CkanPair;
import eu.trentorise.opendata.jackan.model.CkanResource;
import eu.trentorise.opendata.jackan.model.CkanTag;
import eu.trentorise.opendata.jackan.model.CkanUser;
/**
* This is the Ckan Utils implementation class.
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
*/
public class DataCatalogueImpl implements DataCatalogue{
private static final Logger logger = 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 CKAN_TOKEN_SYS;
private String URI_RESOLVER_URL;
private boolean MANAGE_PRODUCT_BUTTON;
private String CONTEXT;
// ckan client
private CkanClient client;
// 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 = 5 * 60 * 1000;
private class CKANTokenBean{
private String apiKey;
private long timestamp;
public CKANTokenBean(String apiKey, long timestamp) {
super();
this.apiKey = apiKey;
this.timestamp = timestamp;
}
}
/**
* 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_NAME = runningInstance.getDataBaseName().trim();
CKAN_DB_USER = runningInstance.getDataBaseUser().trim();
CKAN_DB_PASSWORD = runningInstance.getDataBasePassword().trim();
CKAN_TOKEN_SYS = runningInstance.getSysAdminToken().trim();
CKAN_DB_PORT = runningInstance.getDatabasePorts().get(0);
CKAN_CATALOGUE_URL = runningInstance.getDataCatalogueUrl().get(0).trim();
PORTLET_URL_FOR_SCOPE = runningInstance.getPortletUrl().trim();
MANAGE_PRODUCT_BUTTON = runningInstance.isManageProductEnabled();
URI_RESOLVER_URL = runningInstance.getUrlResolver();
logger.debug("Plain sys admin token first 3 chars are " + CKAN_TOKEN_SYS.substring(0, 3));
logger.debug("Plain db password first 3 chars are " + CKAN_DB_PASSWORD.substring(0, 3));
// build the client
client = new CkanClient(CKAN_CATALOGUE_URL);
// init map
apiKeysMap = new ConcurrentHashMap<String, CKANTokenBean>();
// save the context
CONTEXT = scope;
}
@Override
public String getCatalogueUrl() {
return CKAN_CATALOGUE_URL;
}
@Override
public String getPortletUrl() {
return PORTLET_URL_FOR_SCOPE;
}
@Override
public String getUriResolverUrl() {
return URI_RESOLVER_URL;
}
/**
* Retrieve connection from the pool
* @return a connection available within the pool
* @throws SQLException
* @throws ClassNotFoundException
*/
private Connection getConnection() throws SQLException, ClassNotFoundException{
logger.debug("CONNECTION REQUEST");
// create db connection
Class.forName("org.postgresql.Driver");
Connection connection = DriverManager.getConnection(
"jdbc:postgresql://" + CKAN_DB_URL + ":" + CKAN_DB_PORT + "/" + CKAN_DB_NAME, CKAN_DB_USER, CKAN_DB_PASSWORD);
return connection;
}
/**
* Check if the manage product is enabled
* @return
*/
@Override
public boolean isManageProductEnabled() {
return MANAGE_PRODUCT_BUTTON;
}
/**
* Tries to close a connection
* @param connection
*/
private void closeConnection(Connection connection){
if(connection != null){
try{
connection.close();
}catch(Exception e){
logger.error("Unable to close this connection ", e);
}
}
}
@Override
public String getApiKeyFromUsername(String username) {
logger.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 = UtilMethods.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;
}
}
logger.debug("Api key was not in cache or it expired");
// 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, ckanUsername);
preparedStatement.setString(2, State.ACTIVE.toString().toLowerCase());
ResultSet rs = preparedStatement.executeQuery();
while (rs.next()) {
apiToReturn = rs.getString("apikey");
logger.debug("Api key retrieved for user " + ckanUsername);
break;
}
// save into the hashmap
if(apiToReturn != null)
apiKeysMap.put(ckanUsername, new CKANTokenBean(apiToReturn, System.currentTimeMillis()));
return apiToReturn;
}catch(Exception e){
logger.error("Unable to retrieve key for user " + ckanUsername, e);
return null;
}finally{
closeConnection(connection);
}
}
@Override
public CKanUserWrapper getUserFromApiKey(String apiKey) {
logger.debug("Request user whose api key is = " + apiKey.substring(0, 3) + "*************");
// checks
checkNotNull(apiKey);
checkArgument(!apiKey.isEmpty());
CKanUserWrapper user = null;
// the connection
Connection connection = null;
try{
connection = getConnection();
String query = "SELECT * FROM \"user\" WHERE \"apikey\"=? and \"state\"=?;";
PreparedStatement preparedStatement = connection.prepareStatement(query);
preparedStatement.setString(1, apiKey);
preparedStatement.setString(2, State.ACTIVE.toString().toLowerCase());
ResultSet rs = preparedStatement.executeQuery();
while (rs.next()) {
user = new CKanUserWrapper();
user.setId(rs.getString("id"));
user.setName(rs.getString("name"));
user.setApiKey(apiKey);
user.setCreationTimestamp(rs.getTimestamp("created").getTime());
user.setAbout(rs.getString("about"));
user.setOpenId(rs.getString("openid"));
user.setFullName(rs.getString("fullname"));
user.setEmail(rs.getString("email"));
user.setAdmin(rs.getBoolean("sysadmin"));
logger.debug("User retrieved");
break;
}
}catch(Exception e){
logger.error("Unable to retrieve user with api key " + apiKey, e);
}finally{
closeConnection(connection);
}
return user;
}
@Override
public List<CkanOrganization> getOrganizationsByUser(String username) {
logger.debug("Requested organizations for user " + username);
// checks
checkNotNull(username);
// in order to avoid errors, the username is always converted
String ckanUsername = UtilMethods.fromUsernameToCKanUsername(username);
// list to return
List<CkanOrganization> toReturn = new ArrayList<CkanOrganization>();
try{
// get the list of all organizations
List<CkanOrganization> organizations = client.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 = client.getOrganization(ckanOrganization.getName()).getUsers();
// check if the current user is among them
for (CkanUser ckanUser : users) {
if(ckanUser.getName().equals(ckanUsername)){
logger.debug("User " + ckanUsername + " is into " + ckanOrganization.getName());
toReturn.add(ckanOrganization);
break;
}
}
}
}catch(Exception e){
logger.error("Unable to get user's organizations", e);
}
return toReturn;
}
@Override
public List<CkanGroup> getGroupsByUser(String username) {
logger.debug("Requested groups for user " + username);
// checks
checkNotNull(username);
// in order to avoid errors, the username is always converted
String ckanUsername = UtilMethods.fromUsernameToCKanUsername(username);
// list to return
List<CkanGroup> toReturn = new ArrayList<CkanGroup>();
try{
// get the list of all organizations
List<CkanGroup> groups = client.getGroupList();
// iterate over them
for (CkanGroup ckanGroup : groups) {
List<CkanUser> users = client.getGroup(ckanGroup.getName()).getUsers();
// check if the current user is among them
for (CkanUser ckanUser : users) {
if(ckanUser.getName().equals(ckanUsername)){
logger.debug("User " + ckanUsername + " is into " + ckanGroup.getName());
toReturn.add(ckanGroup);
break;
}
}
}
}catch(Exception e){
logger.error("Unable to get user's groups", e);
}
return toReturn;
}
@Override
public Map<String, List<RolesCkanGroupOrOrg>> getOrganizationsAndRolesByUser(
String username, List<RolesCkanGroupOrOrg> rolesToMatch) {
// checks
checkNotNull(username);
checkArgument(!rolesToMatch.isEmpty());
logger.debug("Requested roles that the user " + username + " has into his organizations");
logger.debug("Roles to check are " + rolesToMatch);
Map<String, List<RolesCkanGroupOrOrg>> toReturn = new HashMap<String, List<RolesCkanGroupOrOrg>>();
try{
// in order to avoid errors, the username is always converted
String ckanUsername = UtilMethods.fromUsernameToCKanUsername(username);
// get the list of organizations in which the user is present
List<CkanOrganization> organizationsByUser = getOrganizationsByUser(ckanUsername);
// iterate over them
for (CkanOrganization ckanOrganization : organizationsByUser) {
// get the list of users in it (if you try ckanOrganization.getUsers() it returns null.. maybe a bug TODO)
List<CkanUser> users = client.getOrganization(ckanOrganization.getName()).getUsers();
// check if the current user is among them
for (CkanUser ckanUser : users) {
if(ckanUser.getName().equals(ckanUsername)){
// the role (admin, editor, member)
String capacity = ckanUser.getCapacity();
// list of roles
List<RolesCkanGroupOrOrg> rolesIntoOrg = new ArrayList<RolesCkanGroupOrOrg>();
if(rolesToMatch.contains(RolesCkanGroupOrOrg.convertFromCapacity(capacity))){
RolesCkanGroupOrOrg enumRole = RolesCkanGroupOrOrg.convertFromCapacity(capacity);
rolesIntoOrg.add(enumRole);
logger.debug("User " + ckanUsername + " has role " + enumRole +
" into organization with name " + ckanOrganization.getName());
}
// save it
if(!rolesIntoOrg.isEmpty()){
String orgName = ckanOrganization.getName();
toReturn.put(orgName, rolesIntoOrg);
}
break;
}
}
}
logger.debug("Result is " + toReturn);
return toReturn;
}catch(Exception e){
logger.error("Unable to analyze user's roles", e);
}
return null;
}
@Override
public List<String> getOrganizationsIds(){
List<String> toReturn = new ArrayList<String>();
List<CkanOrganization> orgs = client.getOrganizationList();
for (CkanOrganization ckanOrganization : orgs) {
logger.debug("Retrieved org " + ckanOrganization.getName());
toReturn.add(ckanOrganization.getId());
}
return toReturn;
}
@Override
public List<String> getOrganizationsNames(){
List<String> toReturn = new ArrayList<String>();
List<CkanOrganization> orgs = client.getOrganizationList();
for (CkanOrganization ckanOrganization : orgs) {
logger.debug("Retrieved org " + ckanOrganization.getName());
toReturn.add(ckanOrganization.getName());
}
return toReturn;
}
@Override
public List<String> getOrganizationsNamesByUser(String username) {
logger.debug("Requested organizations for user " + username);
// checks
checkNotNull(username);
// in order to avoid errors, the username is always converted
String ckanUsername = UtilMethods.fromUsernameToCKanUsername(username);
List<CkanOrganization> orgs = getOrganizationsByUser(ckanUsername);
List<String> orgsName = new ArrayList<String>();
for (CkanOrganization ckanOrganization : orgs) {
orgsName.add(ckanOrganization.getName());
logger.debug("Organization name is " + ckanOrganization.getName());
}
return orgsName;
}
@Override
public String findLicenseIdByLicenseTitle(String chosenLicense) {
logger.debug("Requested license id");
// checks
checkNotNull(chosenLicense);
//retrieve the list of available licenses
List<CkanLicense> licenses = client.getLicenseList();
for (CkanLicense ckanLicense : licenses) {
if(ckanLicense.getTitle().equals(chosenLicense))
return ckanLicense.getId();
}
return null;
}
@Override
public List<String> getLicenseTitles() {
logger.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 = client.getLicenseList();
for (CkanLicense ckanLicense : licenses) {
result.add(ckanLicense.getTitle());
logger.debug("License is " + ckanLicense.getTitle() + " and id " + ckanLicense.getId());
}
return result;
}
@Override
public List<CkanLicense> getLicenses() {
logger.debug("Request for CKAN licenses (original jackan objects are going to be retrieved)");
//retrieve the list of available licenses
return client.getLicenseList();
}
/**
* Set dataset private
* @param priv
* @param organizationId (NOTE: The ID, not the name!)
* @param datasetId (NOTE: The ID, not the name!)
* @param apiKey the user's api key
* @return true on success, false otherwise
*/
protected boolean setDatasetPrivate(boolean priv, String organizationId,
String datasetId, String apiKey) {
// checks
checkNotNull(organizationId);
checkNotNull(apiKey);
checkNotNull(datasetId);
checkArgument(!apiKey.isEmpty());
checkArgument(!datasetId.isEmpty());
checkArgument(!organizationId.isEmpty());
String pathSetPrivate = "/api/3/action/bulk_update_private";
String pathSetPublic = "/api/3/action/bulk_update_public";
// Request parameters to be replaced
String parameter = "{"
+ "\"org_id\":\"ORGANIZATION_ID\","
+ "\"datasets\":[\"DATASET_ID\"]"
+ "}";
// replace with right data
parameter = parameter.replace("ORGANIZATION_ID", organizationId);
parameter = parameter.replace("DATASET_ID", datasetId);
if(priv){
try(CloseableHttpClient httpClient = HttpClientBuilder.create().build();) {
HttpPost request = new HttpPost(CKAN_CATALOGUE_URL + pathSetPrivate);
request.addHeader("Authorization", apiKey);
StringEntity params = new StringEntity(parameter);
request.setEntity(params);
HttpResponse response = httpClient.execute(request);
logger.debug("[PRIVATE]Response code is " + response.getStatusLine().getStatusCode() + " and response message is " + response.getStatusLine().getReasonPhrase());
if(response.getStatusLine().getStatusCode() == HttpStatus.SC_OK)
return true;
}catch (Exception ex) {
logger.error("Error while trying to set private the dataset ", ex);
}
}else
{
try(CloseableHttpClient httpClient = HttpClientBuilder.create().build();) {
HttpPost request = new HttpPost(CKAN_CATALOGUE_URL + pathSetPublic);
StringEntity params = new StringEntity(parameter);
request.addHeader("Authorization", apiKey);
request.setEntity(params);
HttpResponse response = httpClient.execute(request);
logger.debug("[PUBLIC]Response code is " + response.getStatusLine().getStatusCode() + " and response message is " + response.getStatusLine().getReasonPhrase());
if(response.getStatusLine().getStatusCode() == HttpStatus.SC_OK)
return true;
}catch (Exception ex) {
logger.error("Error while trying to set public the dataset ", ex);
}
}
return false;
}
@Override
public String addResourceToDataset(ResourceBean resourceBean, String apiKey) {
logger.debug("Request to add a resource described by this bean " + resourceBean);
// checks
checkNotNull(resourceBean);
checkNotNull(apiKey);
checkArgument(!apiKey.isEmpty());
try{
if(UtilMethods.resourceExists(resourceBean.getUrl())){
// in order to avoid errors, the username is always converted
String ckanUsername = UtilMethods.fromUsernameToCKanUsername(resourceBean.getOwner());
CkanResource resource = new CkanResource(CKAN_CATALOGUE_URL, resourceBean.getDatasetId());
resource.setName(resourceBean.getName());
// escape description
Source description = new Source(resourceBean.getDescription());
Segment htmlSeg = new Segment(description, 0, description.length());
Renderer htmlRend = new Renderer(htmlSeg);
resource.setDescription(htmlRend.toString());
resource.setUrl(resourceBean.getUrl());
resource.setOwner(ckanUsername);
// Checked client
CheckedCkanClient client = new CheckedCkanClient(CKAN_CATALOGUE_URL, apiKey);
CkanResource createdRes = client.createResource(resource);
if(createdRes != null){
logger.debug("Resource " + createdRes.getName() + " is now available");
return createdRes.getId();
}
}else
logger.error("There is no resource at this url " + resourceBean.getUrl());
}catch(Exception e){
logger.error("Unable to create the resource described by the bean " + resourceBean, e);
}
return null;
}
@Override
public boolean deleteResourceFromDataset(String resourceId, String apiKey) {
logger.error("Request to delete a resource with id " + resourceId + " coming by user with key " + apiKey);
// checks
checkNotNull(apiKey);
checkNotNull(resourceId);
checkArgument(!apiKey.isEmpty());
checkArgument(!resourceId.isEmpty());
try{
CheckedCkanClient client = new CheckedCkanClient(CKAN_CATALOGUE_URL, apiKey);
client.deleteResource(resourceId);
return true;
}catch(Exception e){
logger.error("Unable to delete resource whose id is " + resourceId, e);
}
return false;
}
@Override
public String createCKanDataset(String apiKey,
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, String> customFields,
List<ResourceBean> resources, boolean setPublic) {
// delegate the private method
return createCkanDatasetBody(apiKey,
title, name, organizationNameOrId, author,
authorMail, maintainer,maintainerMail,
version, description, licenseId,
tags, customFields, null,
resources, setPublic);
}
@Override
public String createCKanDatasetMultipleCustomFields(String apiKey,
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>> customFieldsMultiple,
List<ResourceBean> resources, boolean setPublic) {
// delegate the private method
return createCkanDatasetBody(apiKey,
title, name, organizationNameOrId, author,
authorMail, maintainer,maintainerMail,
version, description, licenseId,
tags, null, customFieldsMultiple,
resources, setPublic);
}
// the body of the actual dataset creation methods
private String createCkanDatasetBody(String apiKey,
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, String> customFields,
Map<String, List<String>> customFieldsMultipleValues,
List<ResourceBean> resources, boolean setPublic){
// checks (minimum)
checkNotNull(apiKey);
checkNotNull(organizationNameOrId);
checkArgument(!apiKey.isEmpty());
checkArgument(!organizationNameOrId.isEmpty());
checkArgument(!((title == null && name == null) || (title.isEmpty() && name.isEmpty())), "Name and Title cannot be empty/null at the same time!");
logger.debug("Request for dataset creation");
CheckedCkanClient client = new CheckedCkanClient(CKAN_CATALOGUE_URL, apiKey);
// get client from apiKey
String ckanUsername = getUserFromApiKey(apiKey).getName();
// create the base dataset and fill it
CkanDataset dataset = new CkanDataset();
// get the name from the title
String nameToUse = name;
if(nameToUse == null)
nameToUse = UtilMethods.fromProductTitleToName(title);
logger.debug("Name of the dataset is going to be " + nameToUse + ". Title is going to be " + title);
dataset.setName(nameToUse);
dataset.setTitle(title);
CkanOrganization orgOwner = client.getOrganization(organizationNameOrId);
dataset.setOwnerOrg(orgOwner.getId());
dataset.setAuthor(author);
dataset.setAuthorEmail(authorMail);
dataset.setMaintainer(maintainer);
dataset.setMaintainerEmail(maintainerMail);
dataset.setVersion(String.valueOf(version));
// description must be escaped
if(description != null && !description.isEmpty()){
Source descriptionEscaped = new Source(description);
Segment htmlSeg = new Segment(descriptionEscaped, 0, descriptionEscaped.length());
Renderer htmlRend = new Renderer(htmlSeg);
dataset.setNotes(htmlRend.toString());
logger.debug("Description (escaped is ) " + htmlRend.toString());
}
dataset.setLicenseId(licenseId);
// set the tags, if any
if(tags != null && !tags.isEmpty()){
// convert to ckan tags
List<CkanTag> ckanTags = new ArrayList<CkanTag>(tags.size());
for (String stringTag : tags) {
ckanTags.add(new CkanTag(stringTag));
}
dataset.setTags(ckanTags);
}
// set the custom fields, if any
if(customFields != null && !customFields.isEmpty()){
// iterate and create
Iterator<Entry<String, String>> iterator = customFields.entrySet().iterator();
List<CkanPair> extras = new ArrayList<CkanPair>();
while (iterator.hasNext()) {
Map.Entry<String, String> entry = (Map.Entry<String, String>) iterator.next();
extras.add(new CkanPair(entry.getKey(), entry.getValue()));
}
dataset.setExtras(extras);
}else if(customFieldsMultipleValues != null && !customFieldsMultipleValues.isEmpty()){
// iterate and create
Iterator<Entry<String, List<String>>> iterator = customFieldsMultipleValues.entrySet().iterator();
List<CkanPair> extras = new ArrayList<CkanPair>();
while (iterator.hasNext()) {
Map.Entry<String, List<String>> entry = (Map.Entry<String, List<String>>) iterator.next();
List<String> valuesForEntry = entry.getValue();
for (String value : valuesForEntry) {
extras.add(new CkanPair(entry.getKey(), value));
}
}
// sort them
Collections.sort(extras, new Comparator<CkanPair>() {
@Override public int compare(CkanPair b1, CkanPair b2) {
return b1.getKey().compareTo(b2.getKey());
}
});
dataset.setExtras(extras);
}
// check if we need to add the resources
if(resources != null && !resources.isEmpty()){
logger.debug("We need to add resources to the dataset");
try{
List<CkanResource> resourcesCkan = new ArrayList<CkanResource>();
for(ResourceBean resource: resources){
CkanResource newResource = new CkanResource();
newResource.setDescription(resource.getDescription());
newResource.setId(resource.getId());
newResource.setUrl(resource.getUrl());
newResource.setName(resource.getName());
newResource.setMimetype(resource.getMimeType());
newResource.setOwner(ckanUsername);
resourcesCkan.add(newResource);
}
// add to the dataset
dataset.setResources(resourcesCkan);
}catch(Exception e){
logger.error("Unable to add those resources to the dataset", e);
}
}
// try to create
CkanDataset res = null;
try{
res = client.createDataset(dataset);
if(res != null){
logger.debug("Dataset with name " + res.getName() + " has been created. Setting visibility");
// set visibility
boolean visibilitySet = setDatasetPrivate(
!setPublic, // swap to private
res.getOrganization().getId(),
res.getId(),
CKAN_TOKEN_SYS); // use sysadmin api key to be sure it will be set
logger.info("Was visibility set to " + (setPublic ? "public" : "private") + "? " + visibilitySet);
// set searchable to true if dataset visibility is private
if(!setPublic){ // (swap to private)
boolean searchableSet = setSearchableField(res.getId(), true);
logger.info("Was searchable set to True? " + searchableSet);
}
return res.getId();
}
}catch(Exception e){
// try to update
logger.error("Error while creating the dataset.", e);
}
return null;
}
@Override
public String getUrlFromDatasetIdOrName(String datasetIdOrName) {
logger.debug("Request coming for getting dataset url (encrypted) of dataset with name/id " + datasetIdOrName);
// checks
checkNotNull(datasetIdOrName);
checkArgument(!datasetIdOrName.isEmpty());
String url = null;
try{
// get the dataset from name
CheckedCkanClient client = new CheckedCkanClient(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.PRODUCT, name, false);
if(url == null || url.isEmpty())
url = getPortletUrl() + "?" + URLEncoder.encode("path=/dataset/" + name, "UTF-8");
}
}catch(Exception e){
logger.error("Error while retrieving dataset with id/name=" + datasetIdOrName, e);
}
return url;
}
@Override
public String getUnencryptedUrlFromDatasetIdOrName(String datasetIdOrName) {
logger.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
CheckedCkanClient client = new CheckedCkanClient(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.PRODUCT, name, true);
if(url == null || url.isEmpty())
url = getPortletUrl() + "?" + URLEncoder.encode("path=/dataset/" + name, "UTF-8");
}
}catch(Exception e){
logger.error("Error while retrieving dataset with id/name=" + datasetIdOrName, e);
}
return url;
}
/**
* Retrieve an url for the tuple scope, entity, entity name
* @param context
* @param entityContext
* @param entityName
* @return the url for the product
*/
@SuppressWarnings("unchecked")
private String getUrlForProduct(String context, EntityContext entityContext, String entityName, boolean unencrypted){
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);
requestEntity.put("clear_url", Boolean.toString(unencrypted));
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());
logger.debug("Result is " + toReturn);
}catch(Exception e){
logger.error("Failed to get an url for this product", e);
}
return toReturn;
}
@Override
public boolean checkRoleIntoOrganization(String username, String organizationName,
RolesCkanGroupOrOrg correspondentRoleToCheck) {
logger.debug("Request for checking if " + username + " into organization " + organizationName + " has role " + correspondentRoleToCheck);
// checks
checkNotNull(username);
checkNotNull(organizationName);
checkNotNull(correspondentRoleToCheck);
checkArgument(!username.isEmpty());
checkArgument(!organizationName.isEmpty());
// convert ckan username
String ckanUsername = UtilMethods.fromUsernameToCKanUsername(username);
// check if this role is already present in ckan for this user within the organization
String organizationNameToCheck = organizationName.toLowerCase();
try{
boolean alreadyPresent = isRoleAlreadySet(ckanUsername, organizationNameToCheck, correspondentRoleToCheck, false);
if(alreadyPresent)
return true; // just return
else{
// we need to use the apis to make it
String path = "/api/3/action/organization_member_create";
// Request parameters to be replaced
String parameter = "{"
+ "\"id\":\"ORGANIZATION_ID_NAME\","
+ "\"username\":\"USERNAME_ID_NAME\","
+ "\"role\":\"ROLE\""
+ "}";
// replace those values
parameter = parameter.replace("ORGANIZATION_ID_NAME", organizationNameToCheck);
parameter = parameter.replace("USERNAME_ID_NAME", ckanUsername);
parameter = parameter.replace("ROLE", RolesCkanGroupOrOrg.convertToCkanCapacity(correspondentRoleToCheck));
logger.debug("API request for organization membership is going to be " + parameter);
try(CloseableHttpClient httpClient = HttpClientBuilder.create().build();) {
HttpPost request = new HttpPost(CKAN_CATALOGUE_URL + path);
request.addHeader("Authorization", CKAN_TOKEN_SYS); // sys token
StringEntity params = new StringEntity(parameter);
request.setEntity(params);
HttpResponse response = httpClient.execute(request);
logger.debug("Response code is " + response.getStatusLine().getStatusCode() + " and response message is " + response.getStatusLine().getReasonPhrase());
return (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK);
}catch (Exception ex) {
logger.error("Error while trying to change the role for this user ", ex);
}
}
}catch (Exception ex) {
logger.error("Unable to check if this role was already set, please check your parameters! ", ex);
}
return false;
}
/**
* Check if the user has this role into the organization/group with groupOrOrganization name
* @param ckanUsername
* @param organizationName
* @param correspondentRoleToCheck
* @return true if he has the role, false otherwise
*/
protected boolean isRoleAlreadySet(String ckanUsername, String groupOrOrganization, RolesCkanGroupOrOrg correspondentRoleToCheck, boolean group) throws Exception{
// get the users (if you try ckanOrganization.getUsers() it returns null.. maybe a bug TODO)
List<CkanUser> users;
if(group)
users = client.getGroup(groupOrOrganization).getUsers();
else
users = client.getOrganization(groupOrOrganization).getUsers();
for (CkanUser ckanUser : users) {
if(ckanUser.getName().equals(ckanUsername))
if(ckanUser.getCapacity().equals(RolesCkanGroupOrOrg.convertToCkanCapacity(correspondentRoleToCheck)))
return true;
else
break;
}
return false;
}
@Override
public boolean checkRoleIntoGroup(String username, String groupName, RolesCkanGroupOrOrg correspondentRoleToCheck) {
logger.debug("Request for checking if " + username + " into group " + groupName + " has role " + correspondentRoleToCheck);
// checks
checkNotNull(username);
checkNotNull(groupName);
checkNotNull(correspondentRoleToCheck);
checkArgument(!username.isEmpty());
checkArgument(!groupName.isEmpty());
// convert ckan username
String ckanUsername = UtilMethods.fromUsernameToCKanUsername(username);
// check if this role is already present in ckan for this user within the group
String groupNameToCheck = UtilMethods.fromGroupTitleToName(groupName);
try{
boolean alreadyPresent = isRoleAlreadySet(ckanUsername, groupNameToCheck, correspondentRoleToCheck, true);
if(alreadyPresent)
return true; // just return
else{
// we need to use the apis to make it
String path = "/api/3/action/group_member_create";
// Request parameters to be replaced
String parameter = "{"
+ "\"id\":\"ORGANIZATION_ID_NAME\","
+ "\"username\":\"USERNAME_ID_NAME\","
+ "\"role\":\"ROLE\""
+ "}";
// replace those values
parameter = parameter.replace("ORGANIZATION_ID_NAME", groupNameToCheck);
parameter = parameter.replace("USERNAME_ID_NAME", ckanUsername);
parameter = parameter.replace("ROLE", RolesCkanGroupOrOrg.convertToCkanCapacity(correspondentRoleToCheck));
logger.debug("API request for organization membership is going to be " + parameter);
try(CloseableHttpClient httpClient = HttpClientBuilder.create().build();) {
HttpPost request = new HttpPost(CKAN_CATALOGUE_URL + path);
request.addHeader("Authorization", CKAN_TOKEN_SYS); // sys token
StringEntity params = new StringEntity(parameter);
request.setEntity(params);
HttpResponse response = httpClient.execute(request);
logger.debug("Response code is " + response.getStatusLine().getStatusCode() + " and response message is " + response.getStatusLine().getReasonPhrase());
return (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK);
}catch (Exception ex) {
logger.error("Error while trying to change the role for this user ", ex);
}
}
}catch (Exception ex) {
logger.error("Unable to check if this role was already set, please check your parameters! ", ex);
}
return false;
}
@Override
public boolean isSysAdmin(String username) {
// checks
checkNotNull(username);
checkArgument(!username.isEmpty());
// in order to avoid errors, the username is always converted
String ckanUsername = UtilMethods.fromUsernameToCKanUsername(username);
try{
return client.getUser(ckanUsername).isSysadmin();
}catch(Exception e){
logger.error("Failed to check if the user " + username + " has role sysadmin", e);
}
return false;
}
@Override
public boolean createDatasetRelationship(String datasetIdSubject,
String datasetIdObject, DatasetRelationships relation, String relationComment, String apiKey) {
// checks
checkNotNull(datasetIdSubject);
checkNotNull(datasetIdObject);
checkNotNull(relation);
checkNotNull(apiKey);
checkArgument(!datasetIdSubject.isEmpty());
checkArgument(!datasetIdObject.isEmpty());
checkArgument(!apiKey.isEmpty());
try(CloseableHttpClient httpClient = HttpClientBuilder.create().build();){
// we need to use the apis to make it
String path = "/api/3/action/package_relationship_create";
// Request parameters to be replaced
String parameter = "{"
+ "\"subject\":\"SUBJECT\","
+ "\"object\":\"OBJECT\","
+ "\"type\":\"RELATIONSHIP\","
+ "\"comment\" : \"COMMENT\""
+ "}";
// replace those values
parameter = parameter.replace("SUBJECT", datasetIdSubject);
parameter = parameter.replace("OBJECT", datasetIdObject);
parameter = parameter.replace("RELATIONSHIP", relation.toString());
if(relationComment != null && !relationComment.isEmpty())
parameter = parameter.replace("COMMENT", relationComment);
logger.debug("API request for relationship create is going to be " + parameter);
HttpPost request = new HttpPost(CKAN_CATALOGUE_URL + path);
request.addHeader("Authorization", apiKey);
StringEntity params = new StringEntity(parameter);
request.setEntity(params);
HttpResponse response = httpClient.execute(request);
logger.debug("Response code is " + response.getStatusLine().getStatusCode() + " and response message is " + response.getStatusLine().getReasonPhrase());
return (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK);
}catch(Exception e){
logger.error("Failed to create the relationship between dataset subject = " + datasetIdSubject
+ " and " + " dataset subject " + datasetIdObject, e);
}
return false;
}
@Override
public boolean deleteDatasetRelationship(String datasetIdSubject,
String datasetIdObject, DatasetRelationships relation, String apiKey) {
// checks
checkNotNull(datasetIdSubject);
checkNotNull(datasetIdObject);
checkNotNull(relation);
checkNotNull(apiKey);
checkArgument(!datasetIdSubject.isEmpty());
checkArgument(!datasetIdObject.isEmpty());
checkArgument(!apiKey.isEmpty());
try(CloseableHttpClient httpClient = HttpClientBuilder.create().build();){
// we need to use the apis to make it
String path = "/api/3/action/package_relationship_delete";
// Request parameters to be replaced
String parameter = "{"
+ "\"subject\":\"SUBJECT\","
+ "\"object\":\"OBJECT\","
+ "\"type\":\"RELATIONSHIP\""
+ "}";
// replace those values
parameter = parameter.replace("SUBJECT", datasetIdSubject);
parameter = parameter.replace("OBJECT", datasetIdObject);
parameter = parameter.replace("RELATIONSHIP", relation.toString());
logger.debug("API request for delete relationship is going to be " + parameter);
HttpPost request = new HttpPost(CKAN_CATALOGUE_URL + path);
request.addHeader("Authorization", apiKey);
StringEntity params = new StringEntity(parameter);
request.setEntity(params);
HttpResponse response = httpClient.execute(request);
logger.debug("Response code is " + response.getStatusLine().getStatusCode() + " and response message is " + response.getStatusLine().getReasonPhrase());
return (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK);
}catch(Exception e){
logger.error("Failed to delete the relationship between dataset subject = " + datasetIdSubject
+ " and " + " dataset subject " + datasetIdObject, e);
}
return false;
}
@SuppressWarnings("unchecked")
@Override
public List<CkanDatasetRelationship> getRelationshipDatasets(
String datasetIdSubject, String datasetIdObject, String apiKey) {
// checks
checkNotNull(datasetIdSubject);
checkNotNull(apiKey);
checkArgument(!datasetIdSubject.isEmpty());
checkArgument(!apiKey.isEmpty());
try(CloseableHttpClient httpClient = HttpClientBuilder.create().build();){
List<CkanDatasetRelationship> toReturn = new ArrayList<CkanDatasetRelationship>();
// we need to use the apis to make it
String path = "/api/3/action/package_relationships_list";
String parameter;
// Request parameters to be replaced
if(datasetIdObject == null || datasetIdObject.isEmpty())
parameter = "{"
+ "\"id\":\"SUBJECT\""
+ "}";
else
parameter = "{"
+ "\"id\":\"SUBJECT\","
+ "\"id2\":\"OBJECT\""
+ "}";
// replace those values
parameter = parameter.replace("SUBJECT", datasetIdSubject);
if(datasetIdObject != null && !datasetIdObject.isEmpty())
parameter = parameter.replace("OBJECT", datasetIdObject);
logger.debug("API request for getting relationship is going to be " + parameter);
HttpPost request = new HttpPost(CKAN_CATALOGUE_URL + path);
request.addHeader("Authorization", apiKey);
StringEntity params = new StringEntity(parameter);
request.setEntity(params);
HttpResponse response = httpClient.execute(request);
logger.debug("Response code is " + response.getStatusLine().getStatusCode() + " and response message is " + response.getStatusLine().getReasonPhrase());
if(response.getStatusLine().getStatusCode() == HttpStatus.SC_OK){
// parse the json and convert to java beans
BufferedReader br = new BufferedReader(
new InputStreamReader((response.getEntity().getContent())));
String output;
String res = "";
while ((output = br.readLine()) != null) {
res += output;
}
if(res == "")
return toReturn;
// parse the json object returned
JSONParser parser = new JSONParser();
JSONObject json = (JSONObject) parser.parse(res);
JSONArray resultJson = (JSONArray) json.get("result");
Iterator<JSONObject> it = resultJson.iterator();
while (it.hasNext()) {
JSONObject object = (JSONObject) it.next();
try{
CkanDatasetRelationship relation = new CkanDatasetRelationship(object);
toReturn.add(relation);
}catch(Exception e){
logger.error("Error while building CkanRelationship bean from object " + object, e);
}
}
}
return toReturn;
}catch(Exception e){
logger.error("Failed to retrieve the relationship between dataset subject = " + datasetIdSubject
+ " and " + " dataset object " + datasetIdObject, e);
}
return null;
}
@Override
public boolean existProductWithNameOrId(String nameOrId) {
// checks
checkNotNull(nameOrId);
checkArgument(!nameOrId.isEmpty());
try{
CheckedCkanClient client = new CheckedCkanClient(CKAN_CATALOGUE_URL, CKAN_TOKEN_SYS);
CkanDataset product = client.getDataset(nameOrId);
return product != null;
}catch(Exception e){
logger.debug("A dataset with name " + nameOrId + " doesn't exist");
return false;
}
}
@Override
public CkanGroup createGroup(String nameOrId, String title, String description) {
// checks
checkNotNull(nameOrId);
checkArgument(!nameOrId.trim().isEmpty());
// check if it exists
CkanGroup toCreate = null;
CheckedCkanClient client = new CheckedCkanClient(CKAN_CATALOGUE_URL, CKAN_TOKEN_SYS);
logger.debug("Request for creating group with name " + nameOrId + " title " + title + " and description " + description);
String name = UtilMethods.fromGroupTitleToName(nameOrId);
if((toCreate = groupExists(name, client))!= null)
return toCreate;
else{
try{
CkanGroup group = new CkanGroup(name);
group.setTitle(title);
group.setDisplayName(title);
group.setDescription(description);
toCreate = client.createGroup(group);
}catch(JackanException je){
logger.error("Unable to create such a group", je);
}
}
return toCreate;
}
/**
* Just check if the group exists
* @param nameOrId
* @param client
* @return
*/
private CkanGroup groupExists(String nameOrId, CheckedCkanClient client){
CkanGroup toReturn = null;
try{
toReturn = client.getGroup(nameOrId);
}catch(JackanException je){
logger.error("This group doesn't exist");
}
return toReturn;
}
@SuppressWarnings("unchecked")
@Override
public boolean assignDatasetToGroup(String groupNameOrId, String datasetNameOrId, String apiKey) {
// checks
checkNotNull(groupNameOrId);
checkArgument(!groupNameOrId.isEmpty());
checkNotNull(datasetNameOrId);
checkArgument(!datasetNameOrId.isEmpty());
checkNotNull(apiKey);
checkArgument(!apiKey.isEmpty());
String groupNameToCheck = UtilMethods.fromGroupTitleToName(groupNameOrId);
try(CloseableHttpClient httpClient = HttpClientBuilder.create().build();){
CheckedCkanClient client = new CheckedCkanClient(CKAN_CATALOGUE_URL, CKAN_TOKEN_SYS);
// check the group exists
CkanGroup group = client.getGroup(groupNameToCheck);
// we need to use the apis to make it
String pathPackageShow = CKAN_CATALOGUE_URL + "/api/3/action/package_show?id=" + datasetNameOrId;
HttpGet getRequest = new HttpGet(pathPackageShow);
getRequest.addHeader("Authorization", CKAN_TOKEN_SYS);
HttpResponse response = httpClient.execute(getRequest);
List<String> fetchedGroups = new ArrayList<String>();
logger.debug("Response is " + response.getStatusLine().getStatusCode() + " and message is " + response.getStatusLine().getReasonPhrase());
// read the json dataset and fetch the groups and fetch the groups' names, if any
if(response.getStatusLine().getStatusCode() == HttpStatus.SC_OK){
// parse the json and convert to java beans
String jsonAsString = EntityUtils.toString(response.getEntity());
JSONParser parser = new JSONParser();
JSONObject json = (JSONObject) parser.parse(jsonAsString);
JSONObject resultJson = (JSONObject) json.get("result");
JSONArray groupsJson = (JSONArray)resultJson.get("groups");
Iterator<JSONObject> it = groupsJson.iterator();
while (it.hasNext()) {
JSONObject object = (JSONObject) it.next();
try{
if(object.containsKey("name"))
fetchedGroups.add((String)object.get("name"));
}catch(Exception e){
logger.error("Error while building CkanRelationship bean from object " + object, e);
}
}
// add the new one
if(!fetchedGroups.contains(group.getName()))
fetchedGroups.add(group.getName());
logger.debug("Groups to be added are " + fetchedGroups);
// now we patch the dataset with the new group
String pathUpdatePatch = CKAN_CATALOGUE_URL + "/api/3/action/package_patch";
String parameterPostPatch = "{\"id\":\"PACKAGE_ID\", \"groups\":[GROUPS]}";
parameterPostPatch = parameterPostPatch.replace("PACKAGE_ID", datasetNameOrId);
String singleGroup = "{\"name\":\"GROUP_ID\"}";
// evaluate parameterPostPatch
String replaceGROUPS = "";
for (int i = 0; i < fetchedGroups.size(); i++) {
replaceGROUPS += singleGroup.replace("GROUP_ID", fetchedGroups.get(i));
if(i != fetchedGroups.size() - 1)
replaceGROUPS += ",";
}
// replace this into parameterPostPatch
parameterPostPatch = parameterPostPatch.replace("GROUPS", replaceGROUPS);
logger.debug("Request for patch is going to be " + parameterPostPatch);
HttpPost request = new HttpPost(pathUpdatePatch);
request.addHeader("Authorization", CKAN_TOKEN_SYS);
StringEntity params = new StringEntity(parameterPostPatch);
request.setEntity(params);
HttpResponse responsePatch = httpClient.execute(request);
logger.debug("Response code is " + responsePatch.getStatusLine().getStatusCode() + " and response message is " + responsePatch.getStatusLine().getReasonPhrase());
if(responsePatch.getStatusLine().getStatusCode() == HttpStatus.SC_OK){
logger.info("Dataset Added to the group!!");
return true;
}
}
}catch(Exception e){
logger.error("Unable to make this association", e);
}
return false;
}
@SuppressWarnings("unchecked")
@Override
public boolean removeDatasetFromGroup(String groupNameOrId,
String datasetNameOrId, String apiKey) {
// checks
checkNotNull(groupNameOrId);
checkNotNull(datasetNameOrId);
checkNotNull(apiKey);
try (CloseableHttpClient httpClient = HttpClientBuilder.create().build()) {
String apiRequestUrl = CKAN_CATALOGUE_URL + "/api/3/action/package_patch";
HttpPost httpPostRequest = new HttpPost(apiRequestUrl);
httpPostRequest.setHeader("Authorization", CKAN_TOKEN_SYS);
// Request parameters to be replaced
JSONObject jsonRequest = new JSONObject();
JSONArray groupsAsJson = new JSONArray();
CheckedCkanClient client = new CheckedCkanClient(CKAN_CATALOGUE_URL, CKAN_TOKEN_SYS);
CkanDataset dataset = client.getDataset(datasetNameOrId);
List<CkanGroup> currentGroups = dataset.getGroups();
// build the json array for the "groups" field.. each object looks like
// {
//
// "display_name": "Fishery activity",
// "description": "",
// "image_display_url": "",
// "title": "Fishery activity",
// "id": "20b8d23c-d2dd-4613-9e1e-856311862e87",
// "name": "fishery-activity"
//
// }
// get the id of the group to be removed
String groupId = client.getGroup(groupNameOrId).getId();
for(CkanGroup ckanGroup : currentGroups){
if(!ckanGroup.getId().equals(groupId)){
JSONObject obj = new JSONObject();
obj.put("display_name", ckanGroup.getDisplayName());
obj.put("description", ckanGroup.getDescription());
obj.put("image_display_url", ckanGroup.getImageDisplayUrl());
obj.put("title", ckanGroup.getTitle());
obj.put("id", ckanGroup.getId());
obj.put("name", ckanGroup.getName());
groupsAsJson.add(obj);
}
}
// perform the request
jsonRequest.put("id", datasetNameOrId);
jsonRequest.put("groups", groupsAsJson);
logger.debug("Request param is going to be " + jsonRequest);
StringEntity params = new StringEntity(jsonRequest.toJSONString(), ContentType.APPLICATION_JSON);
httpPostRequest.setEntity(params);
HttpResponse response = httpClient.execute(httpPostRequest);
if (response.getStatusLine().getStatusCode() < 200 || response.getStatusLine().getStatusCode() >= 300) {
throw new RuntimeException("failed to patch the product. response status line from "
+ apiRequestUrl + " was: " + response.getStatusLine());
}
return true;
}catch(Exception e){
logger.error("Failed to remove the group " + groupNameOrId + " from product " + datasetNameOrId, e);
}
return false;
}
@Override
public Map<String, List<String>> getRolesAndUsersOrganization(String organizationName) {
// checks
checkNotNull(organizationName);
checkArgument(!organizationName.isEmpty());
Map<String, List<String>> capacityAndUsers = new HashMap<String, List<String>>();
CkanOrganization org = client.getOrganization(organizationName);
List<CkanUser> users = org.getUsers();
for (CkanUser ckanUser : users) {
logger.debug(ckanUser.getName());
List<String> listUsers;
if(capacityAndUsers.containsKey(ckanUser.getCapacity())){
listUsers = capacityAndUsers.get(ckanUser.getCapacity());
}else
listUsers = new ArrayList<String>();
listUsers.add(ckanUser.getName());
capacityAndUsers.put(ckanUser.getCapacity(), listUsers);
}
return capacityAndUsers;
}
@Override
public Map<RolesCkanGroupOrOrg, List<String>> getRolesAndUsersGroup(String groupName) {
// checks
checkNotNull(groupName);
checkArgument(!groupName.isEmpty());
Map<RolesCkanGroupOrOrg, List<String>> capacityAndUsers = null;
String groupNameToCheck = UtilMethods.fromGroupTitleToName(groupName);
CkanGroup group = client.getGroup(groupNameToCheck);
if(group != null){
capacityAndUsers = new HashMap<RolesCkanGroupOrOrg, List<String>>();
List<CkanUser> users = group.getUsers();
for (CkanUser ckanUser : users) {
List<String> listUsers;
if(capacityAndUsers.containsKey(RolesCkanGroupOrOrg.convertFromCapacity(ckanUser.getCapacity()))){
listUsers = capacityAndUsers.get(RolesCkanGroupOrOrg.convertFromCapacity(ckanUser.getCapacity()));
}else
listUsers = new ArrayList<String>();
listUsers.add(ckanUser.getName());
capacityAndUsers.put(RolesCkanGroupOrOrg.convertFromCapacity(ckanUser.getCapacity()), listUsers);
}
logger.info("Returning " + capacityAndUsers);
}
return capacityAndUsers;
}
@Override
public String getRoleOfUserInOrganization(String username, String orgName, String apiKey) {
String toReturn = null;
String usernameCkan = UtilMethods.fromUsernameToCKanUsername(username);
try{
CheckedCkanClient client = new CheckedCkanClient(CKAN_CATALOGUE_URL, apiKey);
List<CkanUser> users = client.getOrganization(orgName).getUsers();
for (CkanUser ckanUser : users) {
if(ckanUser.getName().equals(usernameCkan)){
toReturn = ckanUser.getCapacity();
break;
}
}
}catch(Exception e){
logger.error("Unable to retrieve the role the user has into this organization", e);
}
return toReturn;
}
@Override
public String getRoleOfUserInGroup(String username, String groupName, String apiKey) {
String toReturn = null;
String usernameCkan = UtilMethods.fromUsernameToCKanUsername(username);
try{
CheckedCkanClient client = new CheckedCkanClient(CKAN_CATALOGUE_URL, apiKey);
List<CkanUser> users = client.getGroup(groupName).getUsers();
for (CkanUser ckanUser : users) {
if(ckanUser.getName().equals(usernameCkan)){
toReturn = ckanUser.getCapacity();
break;
}
}
}catch(Exception e){
logger.error("Unable to retrieve the role the user has into this group", e);
}
return toReturn;
}
@Override
public boolean deleteProduct(String datasetId, String apiKey, boolean purge) {
// checks
checkNotNull(datasetId);
checkArgument(!datasetId.isEmpty());
checkNotNull(apiKey);
checkArgument(!apiKey.isEmpty());
logger.debug("Incoming request of deleting dataset with id " + datasetId);
try{
CheckedCkanClient client = new CheckedCkanClient(CKAN_CATALOGUE_URL, apiKey);
client.deleteDataset(datasetId);
logger.info("Dataset with id " + datasetId + " deleted!");
if(purge){
logger.debug("Purging also ....");
try(CloseableHttpClient httpClient = HttpClientBuilder.create().build();){
String path = CKAN_CATALOGUE_URL + "/api/3/action/dataset_purge";
HttpPost request = new HttpPost(path);
request.addHeader("Authorization", CKAN_TOKEN_SYS); // this must be a sys_admin key
String entityBody = "{\"id\": \"" + datasetId + "\"}";
StringEntity params = new StringEntity(entityBody);
request.setEntity(params);
HttpResponse response = httpClient.execute(request);
logger.debug("Response code is " + response.getStatusLine().getStatusCode() + " and response message is " + response.getStatusLine().getReasonPhrase());
if(response.getStatusLine().getStatusCode() == 200){
logger.info("Dataset with id " + datasetId + " delete and purged!");
return true;
}
return false;
}
}
return true;
}catch(Exception e){
logger.error("Unable to delete such dataset ", e);
}
return false;
}
@Override
public CkanDataset getDataset(String datasetId, String apiKey) {
logger.info("Request ckan dataset with id " + datasetId);
// checks
checkNotNull(datasetId);
checkArgument(!datasetId.isEmpty());
checkNotNull(apiKey);
checkArgument(!apiKey.isEmpty());
try{
CheckedCkanClient client = new CheckedCkanClient(CKAN_CATALOGUE_URL, apiKey);
return client.getDataset(datasetId);
}catch(Exception e){
logger.error("Unable to retrieve such dataset, returning null ...", e);
}
return null;
}
@Override
public boolean setSearchableField(String datasetId, boolean searchable) {
// checks
checkNotNull(datasetId);
checkArgument(!datasetId.isEmpty());
String searchableAsString = searchable ? "True" : "False";
// Patch package path
String patchPackage = CKAN_CATALOGUE_URL + "/api/3/action/package_patch";
// Request parameters to be replaced
String parameter = "{"
+ "\"id\":\"DATASET_ID\","
+ "\"searchable\":\"SEARCHABLE\""
+ "}";
// replace with right data
parameter = parameter.replace("DATASET_ID", datasetId);
parameter = parameter.replace("SEARCHABLE", searchableAsString);
try(CloseableHttpClient httpClient = HttpClientBuilder.create().build();) {
HttpPost request = new HttpPost(patchPackage);
request.addHeader("Authorization", CKAN_TOKEN_SYS);
StringEntity params = new StringEntity(parameter);
request.setEntity(params);
HttpResponse response = httpClient.execute(request);
logger.debug("Response code is " + response.getStatusLine().getStatusCode() + " and response message is " + response.getStatusLine().getReasonPhrase());
if(response.getStatusLine().getStatusCode() == HttpStatus.SC_OK)
return true;
}catch (Exception ex) {
logger.error("Error while trying to set searchable the dataset ", ex);
}
return false;
}
@Override
public List<CkanGroup> getGroups() {
try{
CkanClient client = new CkanClient(CKAN_CATALOGUE_URL);
return client.getGroupList();
}catch(Exception e){
logger.error("Failed to retrieve the list groups", e);
return null;
}
}
@Override
public CkanResource uploadResourceFile(File file, String packageId,
String token, String name, String description) {
// checks
checkNotNull(file);
checkNotNull(packageId);
checkNotNull(token);
checkNotNull(name);
String returnedId = null;
try (CloseableHttpClient httpClient = HttpClientBuilder.create().build()) {
String apiRequestUrl = CKAN_CATALOGUE_URL + "/api/3/action/resource_create";
HttpPost httpPostRequest = new HttpPost(apiRequestUrl);
httpPostRequest.setHeader("Authorization", token);
HttpEntity mpEntity =
MultipartEntityBuilder.create()
.addTextBody("package_id", packageId, ContentType.TEXT_PLAIN)
.addTextBody("url", "upload", ContentType.TEXT_PLAIN)
.addTextBody("description", description == null ? "" : description, ContentType.TEXT_PLAIN)
.addTextBody("name", name, ContentType.TEXT_PLAIN)
.addBinaryBody("upload", file,
ContentType.create(
"application/octet-stream",
Charset.forName("UTF-8")),
name)
.build();
httpPostRequest.setEntity(mpEntity);
HttpResponse response = httpClient.execute(httpPostRequest);
if (response.getStatusLine().getStatusCode() < 200 || response.getStatusLine().getStatusCode() >= 300) {
throw new RuntimeException("failed to add the file to CKAN storage. response status line from "
+ apiRequestUrl + " was: " + response.getStatusLine());
}
logger.info("Returned message is " + response.getStatusLine());
String json = EntityUtils.toString(response.getEntity());
Object obj = JSONValue.parse(json);
JSONObject finalResult=(JSONObject)obj;
JSONObject result = (JSONObject)finalResult.get("result");
logger.debug("Returned json is " + result.get("id"));
returnedId = (String) result.get("id");
return new CheckedCkanClient(CKAN_CATALOGUE_URL, token).getResource(returnedId);
} catch (Exception e) {
logger.error("Error while uploading file");
return null;
}
}
@SuppressWarnings("unchecked")
@Override
public boolean patchResource(String resourceId, String url,
String name, String description, String urlType, String apiKey) {
// checks
checkNotNull(resourceId);
checkNotNull(apiKey);
logger.debug("Going to change resource with id " + resourceId +"."
+ " Request comes from user with key " + apiKey.substring(0, 5) + "****************");
try (CloseableHttpClient httpClient = HttpClientBuilder.create().build()) {
String apiRequestUrl = CKAN_CATALOGUE_URL + "/api/3/action/resource_patch";
HttpPost httpPostRequest = new HttpPost(apiRequestUrl);
httpPostRequest.setHeader("Authorization", apiKey);
// Request parameters to be replaced
JSONObject jsonRequest = new JSONObject();
Map<String, String> requestMap = new HashMap<String, String>();
requestMap.put("id", resourceId);
if(url != null && !url.isEmpty())
requestMap.put("url", url);
if(description != null)
requestMap.put("description", description);
if(name != null && !name.isEmpty())
requestMap.put("name", name);
if(urlType != null)
requestMap.put("url_type", urlType);
jsonRequest.putAll(requestMap);
StringEntity params = new StringEntity(jsonRequest.toJSONString());
httpPostRequest.setEntity(params);
HttpResponse response = httpClient.execute(httpPostRequest);
if (response.getStatusLine().getStatusCode() < 200 || response.getStatusLine().getStatusCode() >= 300) {
throw new RuntimeException("failed to patch the resource. response status line from "
+ apiRequestUrl + " was: " + response.getStatusLine());
}
return true;
}catch(Exception e){
logger.error("Failed to update the resource ", e);
}
return false;
}
@SuppressWarnings("unchecked")
@Override
public boolean patchProductCustomFields(String productId, String apiKey,
Map<String, List<String>> customFieldsToChange) {
// checks
checkNotNull(productId);
checkNotNull(apiKey);
if(customFieldsToChange == null || customFieldsToChange.isEmpty()) // TODO.. remove all custom fields maybe?!
return true;
logger.info("Going to change product with id " + productId +"."
+ " Request comes from user with key " + apiKey.substring(0, 5) + "****************");
logger.info("The new values are " + customFieldsToChange);
// Get already available custom fields
Map<String, List<String>> fromCKANCustomFields = new HashMap<String, List<String>>();
CheckedCkanClient client = new CheckedCkanClient(CKAN_CATALOGUE_URL, apiKey);
List<CkanPair> extras = client.getDataset(productId).getExtras();
if(extras == null)
extras = new ArrayList<CkanPair>();
// fill the above map with these values
for (CkanPair ckanPair : extras) {
List<String> forThisValue = null;
String key = ckanPair.getKey();
if(fromCKANCustomFields.containsKey(key))
forThisValue = fromCKANCustomFields.get(key);
else
forThisValue = new ArrayList<String>();
forThisValue.add(ckanPair.getValue());
fromCKANCustomFields.put(key, forThisValue);
}
logger.info("The generated map from jackan looks like " + fromCKANCustomFields + ". Going to merge them");
// merge them with the new values
Iterator<Entry<String, List<String>>> iteratorUserMap = customFieldsToChange.entrySet().iterator();
while (iteratorUserMap.hasNext()) {
Map.Entry<java.lang.String, java.util.List<java.lang.String>> entry = (Map.Entry<java.lang.String, java.util.List<java.lang.String>>) iteratorUserMap
.next();
String key = entry.getKey();
List<String> newValues = entry.getValue();
// get the unique set of values
Set<String> uniqueValues = new HashSet<String>();
if(fromCKANCustomFields.containsKey(key))
uniqueValues.addAll(fromCKANCustomFields.get(key));
uniqueValues.addAll(newValues);
fromCKANCustomFields.put(key, new ArrayList<String>(uniqueValues));
}
logger.info("After merging it is " + fromCKANCustomFields);
try (CloseableHttpClient httpClient = HttpClientBuilder.create().build()) {
String apiRequestUrl = CKAN_CATALOGUE_URL + "/api/3/action/package_patch";
HttpPost httpPostRequest = new HttpPost(apiRequestUrl);
httpPostRequest.setHeader("Authorization", apiKey);
// Request parameters to be replaced
JSONObject jsonRequest = new JSONObject();
// build the json array for the "extras" field.. each object looks like {"key": ..., "value": ...}
JSONArray extrasObject = new JSONArray();
Iterator<Entry<String, List<String>>> iteratorNewFields = fromCKANCustomFields.entrySet().iterator();
while (iteratorNewFields.hasNext()) {
Map.Entry<java.lang.String, java.util.List<java.lang.String>> entry = (Map.Entry<java.lang.String, java.util.List<java.lang.String>>) iteratorNewFields
.next();
String key = entry.getKey();
List<String> values = entry.getValue();
for (String value : values) {
JSONObject obj = new JSONObject();
obj.put("value", value);
obj.put("key", key);
extrasObject.add(obj);
}
}
// perform the request
jsonRequest.put("id", productId);
jsonRequest.put("extras", extrasObject);
logger.debug("Request param is going to be " + jsonRequest);
StringEntity params = new StringEntity(jsonRequest.toJSONString(), ContentType.APPLICATION_JSON);
httpPostRequest.setEntity(params);
HttpResponse response = httpClient.execute(httpPostRequest);
if (response.getStatusLine().getStatusCode() < 200 || response.getStatusLine().getStatusCode() >= 300) {
throw new RuntimeException("failed to patch the product. response status line from "
+ apiRequestUrl + " was: " + response.getStatusLine());
}
return true;
}catch(Exception e){
logger.error("Failed to patch the product ", e);
}
return false;
}
@SuppressWarnings("unchecked")
@Override
public boolean removeCustomField(String productId, String key,
String value, String apiKey) {
// checks
checkNotNull(productId);
checkNotNull(apiKey);
checkNotNull(value);
checkNotNull(key);
logger.info("Going to change product with id " + productId +"."
+ " Request comes from user with key " + apiKey.substring(0, 5) + "****************");
logger.info("The couple key/value to remove from custom fields is [" + key + "," + value +"]");
CheckedCkanClient client = new CheckedCkanClient(CKAN_CATALOGUE_URL, apiKey);
List<CkanPair> extras = client.getDataset(productId).getExtras();
Iterator<CkanPair> iterator = extras.iterator();
while (iterator.hasNext()) {
CkanPair ckanPair = (CkanPair) iterator.next();
if(ckanPair.getKey().equals(key) && ckanPair.getValue().equals(value)){
logger.info("Removed from the ckan pairs list");
iterator.remove();
break;
}
}
try (CloseableHttpClient httpClient = HttpClientBuilder.create().build()) {
String apiRequestUrl = CKAN_CATALOGUE_URL + "/api/3/action/package_patch";
HttpPost httpPostRequest = new HttpPost(apiRequestUrl);
httpPostRequest.setHeader("Authorization", apiKey);
// Request parameters to be replaced
JSONObject jsonRequest = new JSONObject();
// build the json array for the "extras" field.. each object looks like {"key": ..., "value": ...}
JSONArray extrasObject = new JSONArray();
for(CkanPair extra: extras){
JSONObject obj = new JSONObject();
obj.put("value", extra.getValue());
obj.put("key", extra.getKey());
extrasObject.add(obj);
}
// perform the request
jsonRequest.put("id", productId);
jsonRequest.put("extras", extrasObject);
logger.debug("Request param is going to be " + jsonRequest);
StringEntity params = new StringEntity(jsonRequest.toJSONString(), ContentType.APPLICATION_JSON);
httpPostRequest.setEntity(params);
HttpResponse response = httpClient.execute(httpPostRequest);
if (response.getStatusLine().getStatusCode() < 200 || response.getStatusLine().getStatusCode() >= 300) {
throw new RuntimeException("failed to patch the product. response status line from "
+ apiRequestUrl + " was: " + response.getStatusLine());
}
return true;
}catch(Exception e){
logger.error("Failed to remove the custom field for this product ", e);
}
return false;
}
@SuppressWarnings("unchecked")
@Override
public boolean removeTag(String productId, String apiKey, String tagToRemove) {
// checks
checkNotNull(productId);
checkNotNull(apiKey);
checkNotNull(tagToRemove);
try (CloseableHttpClient httpClient = HttpClientBuilder.create().build()) {
String apiRequestUrl = CKAN_CATALOGUE_URL + "/api/3/action/package_patch";
HttpPost httpPostRequest = new HttpPost(apiRequestUrl);
httpPostRequest.setHeader("Authorization", apiKey);
// Request parameters to be replaced
JSONObject jsonRequest = new JSONObject();
JSONArray tagsAsJson = new JSONArray();
CheckedCkanClient client = new CheckedCkanClient(CKAN_CATALOGUE_URL, apiKey);
CkanDataset dataset = client.getDataset(productId);
List<CkanTag> currentTags = dataset.getTags();
// build the json array for the "tags" field.. each object looks like
// {
//
// "vocabulary_id": null,
// "state": "active",
// "display_name": "....",
// "id": "....",
// "name": "..."
//
// }
for(CkanTag ckanTag : currentTags){
if(!ckanTag.getName().equals(tagToRemove)){
JSONObject obj = new JSONObject();
obj.put("vocabulary_id", ckanTag.getVocabularyId());
obj.put("state", ckanTag.getState().toString());
obj.put("display_name", ckanTag.getDisplayName());
obj.put("id", ckanTag.getId());
obj.put("name", ckanTag.getName());
tagsAsJson.add(obj);
}
}
// perform the request
jsonRequest.put("id", productId);
jsonRequest.put("tags", tagsAsJson);
logger.debug("Request param is going to be " + jsonRequest);
StringEntity params = new StringEntity(jsonRequest.toJSONString(), ContentType.APPLICATION_JSON);
httpPostRequest.setEntity(params);
HttpResponse response = httpClient.execute(httpPostRequest);
if (response.getStatusLine().getStatusCode() < 200 || response.getStatusLine().getStatusCode() >= 300) {
throw new RuntimeException("failed to patch the product. response status line from "
+ apiRequestUrl + " was: " + response.getStatusLine());
}
return true;
}catch(Exception e){
logger.error("Failed to remove the tag " + tagToRemove, e);
}
return false;
}
@Override
public boolean addTag(String productId, String apiKey, String tagToAdd) {
// checks
checkNotNull(productId);
checkNotNull(apiKey);
checkNotNull(tagToAdd);
try{
CheckedCkanClient client = new CheckedCkanClient(CKAN_CATALOGUE_URL, apiKey);
CkanDataset dataset = client.getDataset(productId);
List<CkanTag> currentTags = dataset.getTags();
Iterator<CkanTag> tagsIterator = currentTags.iterator();
boolean added = true;
// check if it is already there ...
while (tagsIterator.hasNext()) {
CkanTag ckanTag = (CkanTag) tagsIterator.next();
if(ckanTag.getName().equals(tagToAdd)){
added = false;
break;
}
}
if(added){
currentTags.add(new CkanTag(tagToAdd));
dataset.setTags(currentTags);
client.patchUpdateDataset(dataset);
}
return true;
}catch(Exception e){
logger.error("Failed to add the tag " + tagToAdd, e);
}
return false;
}
@Override
public List<CkanGroup> getParentGroups(String groupName, String apiKey) {
// checks
checkNotNull(groupName);
checkNotNull(apiKey);
try{
CheckedCkanClient client = new CheckedCkanClient(CKAN_CATALOGUE_URL, apiKey);
return client.getGroup(groupName).getGroups();
}catch(Exception e){
logger.error("Something went wrong, returning null", e);
}
return null;
}
@SuppressWarnings("unchecked")
@Override
public boolean setGroupParent(String parentName, String groupName) {
// checks
checkNotNull(parentName);
checkNotNull(groupName);
try (CloseableHttpClient httpClient = HttpClientBuilder.create().build()) {
String apiRequestUrl = CKAN_CATALOGUE_URL + "/api/3/action/group_patch";
HttpPost httpPostRequest = new HttpPost(apiRequestUrl);
httpPostRequest.setHeader("Authorization", CKAN_TOKEN_SYS);
CheckedCkanClient client = new CheckedCkanClient(CKAN_CATALOGUE_URL, CKAN_TOKEN_SYS);
List<CkanGroup> alreadyAvailableParents = client.getGroup(groupName).getGroups();
Set<String> parentsNames = new HashSet<String>();
parentsNames.add(parentName);
for (CkanGroup alreadyAvailableParent : alreadyAvailableParents) {
parentsNames.add(alreadyAvailableParent.getName());
}
logger.info("Setting as parents of group " + groupName + " :" + parentsNames);
// Request parameters to be replaced
JSONObject jsonRequest = new JSONObject();
JSONArray parentsAsJson = new JSONArray();
for(String parent : parentsNames){
JSONObject obj = new JSONObject();
obj.put("name", parent);
parentsAsJson.add(obj);
}
// perform the request
jsonRequest.put("id", groupName);
jsonRequest.put("groups", parentsAsJson);
logger.debug("Request param is going to be " + jsonRequest);
StringEntity params = new StringEntity(jsonRequest.toJSONString(), ContentType.APPLICATION_JSON);
httpPostRequest.setEntity(params);
HttpResponse response = httpClient.execute(httpPostRequest);
if (response.getStatusLine().getStatusCode() < 200 || response.getStatusLine().getStatusCode() >= 300) {
throw new RuntimeException("failed to patch the group. response status line from "
+ apiRequestUrl + " was: " + response.getStatusLine());
}
return true;
}catch(Exception e){
logger.error("Failed to set parents groups", e);
}
return false;
}
@Override
public boolean isDatasetInGroup(String groupName, String datasetId) {
// checks
checkNotNull(datasetId);
checkNotNull(groupName);
CheckedCkanClient client = new CheckedCkanClient(CKAN_CATALOGUE_URL, CKAN_TOKEN_SYS);
List<CkanGroup> groups = client.getDataset(datasetId).getGroups();
for (CkanGroup ckanGroup : groups) {
if(ckanGroup.getName().equals(groupName))
return true;
}
return false;
}
@Override
public List<CkanDataset> getProductsInGroup(String groupName) {
checkNotNull(groupName);
List<CkanDataset> toReturn = null;
try (CloseableHttpClient httpClient = HttpClientBuilder.create().build()) {
CheckedCkanClient client = new CheckedCkanClient(CKAN_CATALOGUE_URL, CKAN_TOKEN_SYS);
String apiRequestUrl = CKAN_CATALOGUE_URL + "/api/3/action/group_show" + "?id=" + groupName + "&include_datasets=true";
HttpGet httpGetRequest = new HttpGet(apiRequestUrl);
httpGetRequest.setHeader("Authorization", CKAN_TOKEN_SYS);
HttpResponse response = httpClient.execute(httpGetRequest);
String jsonString = EntityUtils.toString(response.getEntity());
JSONParser parser = new JSONParser();
JSONObject parsedJson = (JSONObject)parser.parse(jsonString);
logger.debug("JSONObject looks like " + parsedJson);
// get "packages" array
toReturn = new ArrayList<CkanDataset>();
JSONObject result = (JSONObject)parsedJson.get("result");
JSONArray packages = (JSONArray)result.get("packages");
logger.debug("Packages looks like " + packages);
for (int i = 0, size = packages.size(); i < size; i++){
JSONObject objectInArray = (JSONObject)packages.get(i);
String packageId = (String)objectInArray.get("id");
toReturn.add(client.getDataset(packageId));
}
}catch(Exception e){
logger.error("Failed to get groups information", e);
}
return toReturn;
}
@Override
public String patchProductWithJSON(String productId, JSONObject jsonRequest,
String apiKey) {
checkNotNull(productId);
checkNotNull(jsonRequest);
checkNotNull(apiKey);
logger.info("Request of patching product " + productId + " with json " + jsonRequest);
try(CloseableHttpClient httpClient = HttpClientBuilder.create().build();){
String pathUpdatePatch = getCatalogueUrl() + "/api/3/action/package_patch";
HttpPost httpPostRequest = new HttpPost(pathUpdatePatch);
httpPostRequest.setHeader("Authorization", CKAN_TOKEN_SYS);
StringEntity params = new StringEntity(jsonRequest.toJSONString(), ContentType.APPLICATION_JSON);
httpPostRequest.setEntity(params);
HttpResponse response = httpClient.execute(httpPostRequest);
if (response.getStatusLine().getStatusCode() < 200 || response.getStatusLine().getStatusCode() >= 300) {
throw new RuntimeException("failed to patch the product. response status line from "
+ pathUpdatePatch + " was: " + response.getStatusLine());
}
return null;
}catch(Exception e){
logger.error("Error while trying to patch grsf record " + e.getMessage());
return e.getMessage();
}
}
@Override
public List<String> getProductsIdsInGroupOrOrg(String orgOrGroupName, boolean isOrganization, int start, int rows) throws ClassNotFoundException, SQLException {
List<String> toReturn = new ArrayList<String>();
checkNotNull(orgOrGroupName);
checkArgument(start >= 0);
checkArgument(rows >= 0);
Connection connection = getConnection();
try{
ResultSet rs;
if(isOrganization){
String joinQuery = "SELECT \"package\".\"id\" AS \"dataset_id\" FROM \"package\" INNER JOIN \"group\" ON"
+ " \"package\".\"owner_org\"=\"group\".\"id\" WHERE \"group\".\"name\"=? "
+ "AND \"group\".\"is_organization\"=? AND \"package\".\"type\"=? AND \"package\".\"state\"=? LIMIT ? OFFSET ?; ";
PreparedStatement preparedStatement = connection.prepareStatement(joinQuery);
preparedStatement.setString(1, orgOrGroupName);
preparedStatement.setBoolean(2, isOrganization);
preparedStatement.setString(3, "dataset");
preparedStatement.setString(4, "active");
preparedStatement.setBigDecimal(5, new BigDecimal(rows));
preparedStatement.setBigDecimal(6, new BigDecimal(start));
rs = preparedStatement.executeQuery();
}else{
/**
* Inner join between the member table and the package table.
* Basically every time a dataset is added to a group, a new row is added to the table
* where table_id is the package_id, and group_id is the owner group identifier (not the name)
*/
String groupId = client.getGroup(orgOrGroupName).getId();
String joinQuery = "SELECT \"table_id\" AS \"dataset_id\" FROM \"package\" INNER JOIN \"member\" ON"
+ " \"member\".\"table_id\"=\"package\".\"id\" WHERE \"group_id\"=? "
+ "AND \"member\".\"state\"=? LIMIT ? OFFSET ?;";
PreparedStatement preparedStatement = connection.prepareStatement(joinQuery);
preparedStatement.setString(1, groupId);
preparedStatement.setString(2, "active");
preparedStatement.setBigDecimal(3, new BigDecimal(rows));
preparedStatement.setBigDecimal(4, new BigDecimal(start));
rs = preparedStatement.executeQuery();
}
while (rs.next()) {
toReturn.add(rs.getString("dataset_id"));
}
}catch(Exception e){
logger.error("Failed to retrieve the ids of products in group/org. Error is " + e.getMessage());
return null;
}finally{
closeConnection(connection);
}
return toReturn;
}
@Override
public boolean deleteGroup(String groupName, boolean purge) {
checkNotNull(groupName);
logger.info("Request of deleting group " + groupName + ". Purge is " + Boolean.toString(purge));
try(CloseableHttpClient httpClient = HttpClientBuilder.create().build();){
String deletePath = getCatalogueUrl() + "/api/3/action/group_delete";
String purgePath = getCatalogueUrl() + "/api/3/action/group_purge";
String requestToPerform = purge ? purgePath : deletePath;
HttpPost httpPostRequest = new HttpPost(requestToPerform);
httpPostRequest.setHeader("Authorization", CKAN_TOKEN_SYS);
JSONObject obj = new JSONObject();
obj.put("id", groupName);
StringEntity params = new StringEntity(obj.toJSONString(), ContentType.APPLICATION_JSON);
httpPostRequest.setEntity(params);
HttpResponse response = httpClient.execute(httpPostRequest);
if (response.getStatusLine().getStatusCode() < 200 || response.getStatusLine().getStatusCode() >= 300) {
throw new RuntimeException("failed to delete/purge the group. response status line from "
+ requestToPerform + " was: " + response.getStatusLine());
}
return true;
}catch(Exception e){
logger.error("Error while trying to delete/purge the group " + e.getMessage());
return false;
}
}
}