catalogue-util-library/src/main/java/org/gcube/datacatalogue/utillibrary/server/DataCatalogueImpl.java

1814 lines
58 KiB
Java

package org.gcube.datacatalogue.utillibrary.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.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.gcube.common.scope.impl.ScopeBean;
import org.gcube.common.scope.impl.ScopeBean.Type;
import org.gcube.datacatalogue.utillibrary.ckan.ExtendCkanClient;
import org.gcube.datacatalogue.utillibrary.ckan.MarshUnmarshCkanObject;
import org.gcube.datacatalogue.utillibrary.ckan.MarshUnmarshCkanObject.METHOD;
import org.gcube.datacatalogue.utillibrary.db.DBCaller;
import org.gcube.datacatalogue.utillibrary.gcat.GCatCaller;
import org.gcube.datacatalogue.utillibrary.server.DataCatalogueRunningCluster.ACCESS_LEVEL_TO_CATALOGUE_PORTLET;
import org.gcube.datacatalogue.utillibrary.server.cms.CatalogueContentModeratorSystem;
import org.gcube.datacatalogue.utillibrary.server.cms.DataCatalogueCMSImpl;
import org.gcube.datacatalogue.utillibrary.server.utils.CKANConveter;
import org.gcube.datacatalogue.utillibrary.server.utils.CatalogueUtilMethods;
import org.gcube.datacatalogue.utillibrary.server.utils.GCubeUtils;
import org.gcube.datacatalogue.utillibrary.server.utils.GcubeContext;
import org.gcube.datacatalogue.utillibrary.server.utils.url.EntityContext;
import org.gcube.datacatalogue.utillibrary.shared.LandingPages;
import org.gcube.datacatalogue.utillibrary.shared.ResourceBean;
import org.gcube.datacatalogue.utillibrary.shared.RolesCkanGroupOrOrg;
import org.gcube.datacatalogue.utillibrary.shared.State;
import org.gcube.datacatalogue.utillibrary.shared.jackan.model.CkanDataset;
import org.gcube.datacatalogue.utillibrary.shared.jackan.model.CkanGroup;
import org.gcube.datacatalogue.utillibrary.shared.jackan.model.CkanLicense;
import org.gcube.datacatalogue.utillibrary.shared.jackan.model.CkanOrganization;
import org.gcube.datacatalogue.utillibrary.shared.jackan.model.CkanPair;
import org.gcube.datacatalogue.utillibrary.shared.jackan.model.CkanResource;
import org.gcube.datacatalogue.utillibrary.shared.jackan.model.CkanUser;
import org.gcube.datacatalogue.utillibrary.shared.jackan.model.exceptions.JackanException;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This is the Ckan Utils implementation class.
*
* revisited by
* @author Francesco Mangiacrapa at ISTI-CNR (francesco.mangiacrapa@isti.cnr.it)
*
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
*/
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 ExtendCkanClient ckanCaller;
// hashmap for ckan api keys
private ConcurrentHashMap<String, CKANTokenBean> apiKeysMap;
// http ckan caller
// private DirectCkanCaller directCkanCaller; //is not needed anymore?
// apikey bean expires after X minutes in the above map
private static final int EXPIRE_KEY_TIME = 60 * 60 * 1000;
private DataCatalogueCMSImpl dataCatalogueCMSImpl = null;
/**
* The ckan catalogue url and database will be discovered in this scope.
*
* @param scope the 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 ExtendCkanClient(CKAN_CATALOGUE_URL);
//directCkanCaller = new DirectCkanCaller(CKAN_CATALOGUE_URL); //is not needed anymore?
// init map
apiKeysMap = new ConcurrentHashMap<String, CKANTokenBean>();
// save the context
CONTEXT = scope;
// extended roles
extendRoleInOrganization = runningInstance.getExtendRoleInOrganization();
}
/**
* The ckan catalogue url and database will be discovered in this scope.
*
* @param scope the scope
* @param sysAuthentication if true perform the sys authentication
* @throws Exception if unable to find datacatalogue info
*/
public DataCatalogueImpl(String scope, boolean sysAuthentication) throws Exception{
this(scope);
if(sysAuthentication)
ckanCaller = new ExtendCkanClient(CKAN_CATALOGUE_URL, CKAN_TOKEN_SYS);
}
/**
* Gets the catalogue url.
*
* @return the catalogue url
*/
/* (non-Javadoc)
* @see org.gcube.datacatalogue.utillibrary.server.DataCatalogue#getCatalogueUrl()
*/
@Override
public String getCatalogueUrl() {
return CKAN_CATALOGUE_URL;
}
/**
* Gets the portlet url.
*
* @return the portlet url
*/
/* (non-Javadoc)
* @see org.gcube.datacatalogue.utillibrary.server.DataCatalogue#getPortletUrl()
*/
@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;
}
}
/**
* Find license id by license title.
*
* @param chosenLicense the chosen license
* @return the string
*/
/* (non-Javadoc)
* @see org.gcube.datacatalogue.utillibrary.server.DataCatalogue#findLicenseIdByLicenseTitle(java.lang.String)
*/
@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;
}
/**
* Gets the license titles.
*
* @return the license titles
*/
/* (non-Javadoc)
* @see org.gcube.datacatalogue.utillibrary.server.DataCatalogue#getLicenseTitles()
*/
@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;
}
/**
* Gets the licenses.
*
* @return the licenses
*/
/* (non-Javadoc)
* @see org.gcube.datacatalogue.utillibrary.server.DataCatalogue#getLicenses()
*/
@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();
}
/**
* Gets the dataset.
*
* @param datasetIdOrName the dataset id or name
* @param username the username
* @return the dataset
*/
/* (non-Javadoc)
* @see org.gcube.datacatalogue.utillibrary.server.DataCatalogue#getDataset(java.lang.String, java.lang.String)
*/
@Override
public CkanDataset getDataset(String datasetIdOrName, String username) {
LOG.info("Called getDataset with id or name" + datasetIdOrName+ " and username: "+username);
// checks
checkNotNull(datasetIdOrName);
checkArgument(!datasetIdOrName.isEmpty());
try {
if (username != null && !username.isEmpty()) {
LOG.info("username found. Calling the " + ExtendCkanClient.class.getSimpleName());
String apiKey = getApiKeyFromUsername(username);
ExtendCkanClient client = new ExtendCkanClient(CKAN_CATALOGUE_URL, apiKey);
return client.getDataset(datasetIdOrName);
}
LOG.info("No username found. Calling Ckan Client without API-KEY");
return ckanCaller.getDataset(datasetIdOrName);
} catch (Exception e) {
LOG.error("Unable to retrieve such dataset, returning null ...", e);
}
return null;
}
/**
* Gets the catalogue content moderator system
*
* @return the catalogue content moderator
*/
public CatalogueContentModeratorSystem getCatalogueContentModerator() {
if (dataCatalogueCMSImpl == null) {
dataCatalogueCMSImpl = new DataCatalogueCMSImpl(CONTEXT, MANAGE_PRODUCT_BUTTON, gCatCaller);
}
return dataCatalogueCMSImpl;
}
/**
* Gets the unencrypted url from dataset id or name.
*
* @param datasetIdOrName the dataset id or name
* @return the unencrypted url from dataset id or name
*/
/* (non-Javadoc)
* @see org.gcube.datacatalogue.utillibrary.server.DataCatalogue#getUnencryptedUrlFromDatasetIdOrName(java.lang.String)
*/
@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;
}
/**
* Gets the user role by group.
*
* @param username the username
* @return the user role by group
*/
/* (non-Javadoc)
* @see org.gcube.datacatalogue.utillibrary.server.DataCatalogue#getUserRoleByGroup(java.lang.String)
*/
@Override
public Map<String, Map<CkanGroup, RolesCkanGroupOrOrg>> getUserRoleByGroup(String username) {
LOG.info("Get user role by group called. The username is: " + username);
checkNotNull(username);
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);
LOG.info("Found " + toReturn.size() + " group/s with the user " + username);
} catch (Exception e) {
LOG.error("Failed to retrieve roles of user in his/her own groups", e);
}
return toReturn;
}
/**
* Gets the user role by organization.
*
* @param username the username
* @return the user role by organization
*/
/* (non-Javadoc)
* @see org.gcube.datacatalogue.utillibrary.server.DataCatalogue#getUserRoleByOrganization(java.lang.String)
*/
@Override
public Map<String, Map<CkanOrganization, RolesCkanGroupOrOrg>> getUserRoleByOrganization(String username) {
LOG.info("Get user role by organization called. The username is: " + username);
checkNotNull(username);
Map<String, Map<CkanOrganization, RolesCkanGroupOrOrg>> toReturn = new HashMap<String, Map<CkanOrganization, RolesCkanGroupOrOrg>>();
try {
String ckanUsername = CatalogueUtilMethods.fromUsernameToCKanUsername(username);
Map<String, RolesCkanGroupOrOrg> partialResult = dbCaller.getOrganizationsByUserFromDB(ckanUsername);
for (String orgID : partialResult.keySet()) {
CkanOrganization org = ckanCaller.getOrganization(orgID);
HashMap<CkanOrganization, RolesCkanGroupOrOrg> subMap = new HashMap<CkanOrganization, RolesCkanGroupOrOrg>();
subMap.put(org, partialResult.get(orgID));
toReturn.put(orgID, subMap);
LOG.debug("For organisation: " + org.getName() + ", the user " + username + " has role: " + subMap);
}
LOG.debug("Returning map " + toReturn);
LOG.info("Found " + toReturn.size() + " organization/s with the user " + username);
} 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 the context
* @param entityContext the entity context
* @param entityName the entity name
* @return the url for product
*/
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;
}
/**
* Gets the landing pages.
*
* @return the landing pages
* @throws Exception the exception
*/
/* (non-Javadoc)
* @see org.gcube.datacatalogue.utillibrary.server.DataCatalogue#getLandingPages()
*/
@Override
public LandingPages getLandingPages() throws Exception {
LandingPages landingPages = new LandingPages();
landingPages.setUrlGroups(PORTLET_URL_FOR_SCOPE + "?path=/group/");
landingPages.setUrlItems(PORTLET_URL_FOR_SCOPE + "?path=/dataset/");
landingPages.setUrlOrganizations(PORTLET_URL_FOR_SCOPE + "?path=/organization/");
landingPages.setUrlTypes(PORTLET_URL_FOR_SCOPE + "?path=/type/");
return landingPages;
}
/**
* Gets the uri resolver url.
*
* @return the uri resolver url
*/
/* (non-Javadoc)
* @see org.gcube.datacatalogue.utillibrary.server.DataCatalogue#getUriResolverUrl()
*/
@Override
public String getUriResolverUrl() {
return URI_RESOLVER_URL;
}
/**
* Check if the manage product is enabled.
*
* @return true, if is manage product enabled
*/
@Override
public boolean isManageProductEnabled() {
return MANAGE_PRODUCT_BUTTON;
}
/**
* Gets the group by name.
*
* @param name the name
* @return the group by name
*/
/* (non-Javadoc)
* @see org.gcube.datacatalogue.utillibrary.server.DataCatalogue#getGroupByName(java.lang.String)
*/
@Override
public CkanGroup getGroupByName(String name) {
String ckanName = CatalogueUtilMethods.fromGroupTitleToName(name);
try{
return ckanCaller.getGroup(ckanName);
}catch(Exception e){
LOG.error("Failed to retrieve the group with name" + name, e);
}
return null;
}
/**
* Checks if is notification to users enabled.
*
* @return true, if is notification to users enabled
*/
/* (non-Javadoc)
* @see org.gcube.datacatalogue.utillibrary.server.DataCatalogue#isNotificationToUsersEnabled()
*/
@Override
public boolean isNotificationToUsersEnabled() {
return ALERT_USERS_ON_POST_CREATION;
}
/**
* Gets the organizations by user.
*
* @param username the username
* @return the organizations by user
*/
/* (non-Javadoc)
* @see org.gcube.datacatalogue.utillibrary.server.DataCatalogue#getOrganizationsByUser(java.lang.String)
*/
@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 {
Map<String, RolesCkanGroupOrOrg> partialResult = dbCaller.getOrganizationsByUserFromDB(ckanUsername);
for (String orgID : partialResult.keySet()) {
CkanOrganization org = ckanCaller.getOrganization(orgID, false);
LOG.debug("User " + ckanUsername + " is into " + org.getName());
toReturn.add(org);
}
} catch (Exception e) {
LOG.error("Unable to get user's organizations", e);
}
return toReturn;
}
/**
* Gets the groups by user.
*
* @param username the username
* @return the groups by user
*/
/* (non-Javadoc)
* @see org.gcube.datacatalogue.utillibrary.server.DataCatalogue#getGroupsByUser(java.lang.String)
*/
@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 {
Map<String, RolesCkanGroupOrOrg> partialResult = dbCaller.getGroupsByUserFromDB(ckanUsername);
for (String groupID : partialResult.keySet()) {
CkanGroup group = ckanCaller.getGroup(groupID, false);
LOG.debug("User " + ckanUsername + " is into " + group.getName());
toReturn.add(group);
}
} catch (Exception e) {
LOG.error("Unable to get user's groups", e);
}
return toReturn;
}
/**
* Gets the organizations ids.
*
* @return the organizations ids
*/
/* (non-Javadoc)
* @see org.gcube.datacatalogue.utillibrary.server.DataCatalogue#getOrganizationsIds()
*/
@Override
public List<String> getOrganizationsIds() {
List<String> toReturn = new ArrayList<String>();
List<CkanOrganization> orgs = ckanCaller.getOrganizationList();
for (CkanOrganization ckanOrganization : orgs) {
LOG.debug("Retrieved org " + ckanOrganization.getName());
toReturn.add(ckanOrganization.getId());
}
return toReturn;
}
/**
* Gets the organizations names.
*
* @return the organizations names
*/
/* (non-Javadoc)
* @see org.gcube.datacatalogue.utillibrary.server.DataCatalogue#getOrganizationsNames()
*/
@Override
public List<String> getOrganizationsNames() {
List<String> toReturn = new ArrayList<String>();
List<CkanOrganization> orgs = ckanCaller.getOrganizationList();
for (CkanOrganization ckanOrganization : orgs) {
LOG.debug("Retrieved org " + ckanOrganization.getName());
toReturn.add(ckanOrganization.getName());
}
return toReturn;
}
/**
* Gets the organizations names by user.
*
* @param username the username
* @return the organizations names by user
*/
/* (non-Javadoc)
* @see org.gcube.datacatalogue.utillibrary.server.DataCatalogue#getOrganizationsNamesByUser(java.lang.String)
*/
@Override
public List<String> getOrganizationsNamesByUser(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<CkanOrganization> orgs = getOrganizationsByUser(ckanUsername);
List<String> orgsName = new ArrayList<String>();
for (CkanOrganization ckanOrganization : orgs) {
orgsName.add(ckanOrganization.getName());
LOG.debug("Organization name is " + ckanOrganization.getName());
}
return orgsName;
}
/**
* Gets the role of user in organization.
*
* @param username the username
* @param orgName the org name
* @return the role of user in organization
*/
/* (non-Javadoc)
* @see org.gcube.datacatalogue.utillibrary.server.DataCatalogue#getRoleOfUserInOrganization(java.lang.String, java.lang.String)
*/
@Override
public String getRoleOfUserInOrganization(String username, String orgName) {
String toReturn = null;
String apiKey = getApiKeyFromUsername(username);
String usernameCkan = CatalogueUtilMethods.fromUsernameToCKanUsername(username);
try {
ExtendCkanClient client = new ExtendCkanClient(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) {
LOG.error("Unable to retrieve the role the user has into organization: " + orgName, e);
}
return toReturn;
}
/**
* Check if the user is valid by checking if its API_KEY is present into DB.
*
* @param username the username
* @return true, if successful
*/
@Override
public boolean checkValidUser(String username) {
String apiKey = getApiKeyFromUsername(username);
return apiKey != null;
}
/**
* Gets the api key from username.
*
* @param username the username
* @return the api key from username
*/
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);
LOG.debug("username: "+username + " converted to ckanUsername: "+ckanUsername);
// 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(ckanUsername, 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;
}
/**
* Exist product with name or id.
*
* @param nameOrId the name or id
* @return true, if successful
*/
/* (non-Javadoc)
* @see org.gcube.datacatalogue.utillibrary.server.DataCatalogue#existProductWithNameOrId(java.lang.String)
*/
@Override
public boolean existProductWithNameOrId(String nameOrId) {
checkNotNull(nameOrId);
checkArgument(!nameOrId.isEmpty());
try {
ExtendCkanClient client = new ExtendCkanClient(CKAN_CATALOGUE_URL, CKAN_TOKEN_SYS);
CkanDataset product = client.getDataset(nameOrId);
return product != null;
} catch (Exception e) {
LOG.debug("A dataset with name " + nameOrId + " doesn't exist");
return false;
}
}
/**
* Gets the organization by id or name.
*
* @param idOrName the id or name
* @return the organization by id or name
*/
/* (non-Javadoc)
* @see org.gcube.datacatalogue.utillibrary.server.DataCatalogue#getOrganizationByIdOrName(java.lang.String)
*/
@Override
public CkanOrganization getOrganizationByIdOrName(String idOrName) {
checkNotNull(idOrName);
String ckanName = idOrName.toLowerCase();
try {
return ckanCaller.getOrganization(ckanName);
} catch (Exception e) {
LOG.warn("Failed to retrieve the organization with name " + idOrName + " on the ckan: "
+ ckanCaller.getCatalogUrl(), e);
}
return null;
}
/**
* Check if the user has this role into the organization/group with
* groupOrOrganization name.
*
* @param ckanUsername the ckan username
* @param groupOrOrganization the group or organization
* @param correspondentRoleToCheck the correspondent role to check
* @param group the group
* @return true if he has the role, false otherwise
* @throws Exception the exception
*/
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 = ckanCaller.getGroup(groupOrOrganization).getUsers();
else
users = ckanCaller.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;
}
/**
* Just check if the group exists.
*
* @param nameOrId the name or id
* @return the ckan group
*/
private CkanGroup groupExists(String nameOrId) {
CkanGroup toReturn = null;
try {
ExtendCkanClient client = new ExtendCkanClient(CKAN_CATALOGUE_URL, CKAN_TOKEN_SYS);
toReturn = client.getGroup(nameOrId);
} catch (JackanException je) {
LOG.error("The group " + nameOrId + " doesn't exist");
}
return toReturn;
}
/**
* Gets the parent groups.
*
* @param groupName the group name
* @param apiKey the api key
* @return the parent groups
*/
/* (non-Javadoc)
* @see org.gcube.datacatalogue.utillibrary.server.DataCatalogue#getParentGroups(java.lang.String, java.lang.String)
*/
@Override
public List<CkanGroup> getParentGroups(String groupName, String apiKey) {
// checks
checkNotNull(groupName);
checkNotNull(apiKey);
try{
ExtendCkanClient client = new ExtendCkanClient(CKAN_CATALOGUE_URL, apiKey);
return client.getGroup(groupName).getGroups();
}catch(Exception e){
LOG.error("Something went wrong, returning null", e);
}
return null;
}
/**
* Gets the organization by name.
*
* @param name the name
* @return the organization by name
*/
/* (non-Javadoc)
* @see org.gcube.datacatalogue.utillibrary.server.DataCatalogue#getOrganizationByName(java.lang.String)
*/
@Override
public CkanOrganization getOrganizationByName(String name) {
checkNotNull(name);
String ckanName = name.toLowerCase();
try{
return ckanCaller.getOrganization(ckanName);
}catch(Exception e){
LOG.warn("Failed to retrieve the organization with name " +name+ " on the ckan: "+ckanCaller.getCatalogUrl(), e);
}
return null;
}
/**
* *****************************************************************************
*
*
* WRITE OPERATIONS
*
*
* *****************************************************************************.
*
* @param username the username
* @param organizationName the organization name
* @param correspondentRoleToCheck the correspondent role to check
* @return true, if successful
*/
@Override
public boolean checkRoleIntoOrganization(String username, String organizationName,
RolesCkanGroupOrOrg correspondentRoleToCheck) {
LOG.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 = CatalogueUtilMethods.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{
//TODO PASS by GCAT?
// we need to use the APIs to make it
String path = "/api/3/action/organization_member_create";
JSONObject obj = new JSONObject();
obj.put("id", organizationNameToCheck);
obj.put("username", ckanUsername);
obj.put("role", RolesCkanGroupOrOrg.convertToCkanCapacity(correspondentRoleToCheck));
LOG.debug("API request for organization membership is going to be " + obj.toJSONString());
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(obj.toJSONString());
request.setEntity(params);
HttpResponse response = httpClient.execute(request);
LOG.debug("Response code is " + response.getStatusLine().getStatusCode() + " and response message is " + response.getStatusLine().getReasonPhrase());
return response.getStatusLine().getStatusCode() == HttpStatus.SC_OK;
}catch (Exception ex) {
LOG.error("Error while trying to change the role for this user ", ex);
}
}
}catch (Exception ex) {
LOG.error("Unable to check if this role was already set, please check your parameters! ", ex);
}
return false;
}
/**
* Check role into group.
*
* @param username the username
* @param groupName the group name
* @param correspondentRoleToCheck the correspondent role to check
* @return true, if successful
*/
/* (non-Javadoc)
* @see org.gcube.datacatalogue.utillibrary.server.DataCatalogue#checkRoleIntoGroup(java.lang.String, java.lang.String, org.gcube.datacatalogue.utillibrary.shared.RolesCkanGroupOrOrg)
*/
@Override
public boolean checkRoleIntoGroup(String username, String groupName, RolesCkanGroupOrOrg correspondentRoleToCheck) {
LOG.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 = CatalogueUtilMethods.fromUsernameToCKanUsername(username);
// check if this role is already present in ckan for this user within the group
String groupNameToCheck = CatalogueUtilMethods.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";
JSONObject obj = new JSONObject();
obj.put("id", groupNameToCheck);
obj.put("username", ckanUsername);
obj.put("role", RolesCkanGroupOrOrg.convertToCkanCapacity(correspondentRoleToCheck));
LOG.debug("API request for organization membership is going to be " + obj.toJSONString());
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(obj.toJSONString());
request.setEntity(params);
HttpResponse response = httpClient.execute(request);
LOG.debug("Response code is " + response.getStatusLine().getStatusCode() + " and response message is " + response.getStatusLine().getReasonPhrase());
return response.getStatusLine().getStatusCode() == HttpStatus.SC_OK;
}catch (Exception ex) {
LOG.error("Error while trying to change the role for this user ", ex);
}
}
}catch (Exception ex) {
LOG.error("Unable to check if this role was already set, please check your parameters! ", ex);
}
return false;
}
/**
* Creates the ckan dataset multiple custom fields.
*
* @param username the username
* @param title the title
* @param name the name
* @param organizationName the organization name
* @param author the author
* @param authorMail the author mail
* @param maintainer the maintainer
* @param maintainerMail the maintainer mail
* @param version the version
* @param description the description
* @param licenseId the license id
* @param tags the tags
* @param customFieldsMultiple the custom fields multiple
* @param resources the resources
* @param setPublic the set public
* @param setSearchable the set searchable
* @param socialPost the social post
* @return the string
* @throws Exception the exception
*/
/* (non-Javadoc)
* @see org.gcube.datacatalogue.utillibrary.server.DataCatalogue#createCkanDatasetMultipleCustomFields(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, long, java.lang.String, java.lang.String, java.util.List, java.util.Map, java.util.List, boolean, boolean, boolean)
*/
@Override
public String createCkanDatasetMultipleCustomFields(String username, String title, String name, String organizationName,
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, boolean setSearchable, boolean socialPost) throws Exception {
LOG.info("Called createCkanDatasetMultipleCustomFields");
// checks (minimum)
checkNotNull(username);
//checkNotNull(organizationNameOrId);
//checkArgument(!organizationNameOrId.isEmpty());
checkArgument(!(title == null && name == null || title.isEmpty() && name.isEmpty()), "Name and Title cannot be empty/null at the same time!");
GcubeContext gcubeContext = null;
try {
gcubeContext = GCubeUtils.detectTheOrgNameContexts(organizationName, username, true);
String toPassOrganizationToGcat = null; //Not needed to pass this information to gCat, never.
// String ckanUsername = getUserFromApiKey(apiKey).getName();
LOG.debug("The visibility parameter passed is (isPublic): "+setPublic);
CkanDataset dataset = CKANConveter.toCkanDataset(ckanCaller, username, title, name, toPassOrganizationToGcat, author, authorMail,
maintainer, maintainerMail, version, description, licenseId, tags, null, customFieldsMultiple,
resources, setPublic, setSearchable);
LOG.debug("The isPriv property into dataset is: "+dataset.isPriv());
// trying to create by gCat
String jsonValueDataset = MarshUnmarshCkanObject.toJsonValueDataset(dataset,METHOD.TO_CREATE);
LOG.info("Serialized dataset is: " + jsonValueDataset);
jsonValueDataset = gCatCaller.createDataset(jsonValueDataset,socialPost);
LOG.debug("Created dataset is: " + jsonValueDataset);
if(jsonValueDataset != null){
CkanDataset toCkanDataset = MarshUnmarshCkanObject.toCkanDataset(jsonValueDataset,METHOD.TO_READ);
LOG.info("Dataset with name " + toCkanDataset.getName() + " has been created correctly");
return toCkanDataset.getId();
}
}catch (Exception e) {
LOG.error("Error on creating the dataset: ", e);
throw e;
}finally {
if(gcubeContext!=null)
GCubeUtils.revertToSourceContext(gcubeContext);
}
return null;
}
/**
* Patch fields for dataset.
*
* @param datasetIdOrName the dataset id or name
* @param mapFields the map fields
* @return true, if successful
* @throws Exception the exception
*/
/* (non-Javadoc)
* @see org.gcube.datacatalogue.utillibrary.server.DataCatalogue#patchFieldsForDataset(java.lang.String, java.util.Map)
*/
@Override
public boolean patchFieldsForDataset(String datasetIdOrName, Map<String, String> mapFields) throws Exception {
LOG.info("Called patchFieldsForDataset " + mapFields + " for dataset id/name: " + datasetIdOrName);
checkNotNull(datasetIdOrName);
checkNotNull(mapFields);
try {
CkanDataset dataset = ckanCaller.getDataset(datasetIdOrName);
String datasetId = dataset.getId();
JSONObject jsonObj = new JSONObject();
for (String key : mapFields.keySet()) {
jsonObj.put(key, mapFields.get(key));
}
jsonObj.put("id", datasetId);
LOG.debug("Json Dataset is: " + jsonObj);
gCatCaller.patchDataset(dataset.getName(), jsonObj);
LOG.info("Patch operation for dataset " + datasetId + " terminates without errors");
return true;
} catch (Exception e) {
LOG.error("Error occurred trying to patch the dataset with id: " + datasetIdOrName, e);
throw new Exception("Unable to patch the dataset. Error: " + e.getMessage());
}
}
/**
* Sets the searchable field for dataset.
*
* @param datasetId the dataset id
* @param searchable the searchable
* @return true, if successful
* @throws Exception the exception
*/
/* (non-Javadoc)
* @see org.gcube.datacatalogue.utillibrary.server.DataCatalogue#setSearchableFieldForDataset(java.lang.String, boolean)
*/
@Override
public boolean setSearchableFieldForDataset(String datasetId, boolean searchable) throws Exception {
LOG.info("Set searchalbe field as " + searchable + " for dataset id: " + datasetId);
checkNotNull(datasetId);
try {
String searchableAsString = searchable ? "True" : "False";
JSONObject jsonObj = new JSONObject();
jsonObj.put("id", datasetId); // just to be sure
jsonObj.put("searchable", searchableAsString);
LOG.debug("Json Dataset is: " + jsonObj);
gCatCaller.patchDataset(datasetId, jsonObj);
LOG.info("Set 'searchable' field for dataset " + datasetId + " terminates without errors");
return true;
} catch (Exception e) {
LOG.error("Error occured trying to set the 'searchable' field for the dataset with id: " + datasetId,
e.getMessage());
throw new Exception("Unable to set the 'searchable' field for this dataset. Error: " + e.getMessage());
}
}
/**
* Adds the resource to dataset.
*
* @param resourceBean the resource bean
* @param organizationName the organization name
* @param username the username
* @return the string
* @throws Exception the exception
*/
/* (non-Javadoc)
* @see org.gcube.datacatalogue.utillibrary.server.DataCatalogue#addResourceToDataset(org.gcube.datacatalogue.utillibrary.shared.ResourceBean)
*/
@Override
public String addResourceToDataset(ResourceBean resourceBean, String organizationName, String username) throws Exception {
LOG.info("Called addResourceToDataset by this bean " + resourceBean);
// checks
checkNotNull(resourceBean);
checkNotNull(resourceBean.getUrl());
//Commented since #21259
/*boolean isAccessibleURL = false;
try {
isAccessibleURL = CatalogueUtilMethods.resourceExists(resourceBean.getUrl());
} catch (Exception e) {
throw new Exception("It seems the resource at this url " + resourceBean.getUrl()+" is not reachable. Error: "+e.getMessage());
}
if(!isAccessibleURL){
throw new Exception("It seems there is no resource at this url " + resourceBean.getUrl());
}*/
GcubeContext gcubeContext = null;
try {
//Switch the context if needed
gcubeContext = GCubeUtils.detectTheOrgNameContexts(organizationName, username, true);
CkanResource resource = CKANConveter.toCkanResource(CKAN_CATALOGUE_URL, resourceBean);
String jsonValueResource = MarshUnmarshCkanObject.toJsonValueResource(resource, METHOD.TO_CREATE);
LOG.debug("Serialized resource is: " + jsonValueResource);
jsonValueResource = gCatCaller.addResourceToDataset(resourceBean.getDatasetId(), jsonValueResource);
LOG.debug("Added resource to dataset is: " + jsonValueResource);
CkanResource createdRes = MarshUnmarshCkanObject.toCkanResource(jsonValueResource);
if (createdRes != null) {
LOG.info("Resource with id: " + createdRes.getId() + ", name: "+createdRes.getName()+" added correclty");
return createdRes.getId();
}
}catch (Exception e) {
LOG.error("Unable to add the resource "+resourceBean, e);
}finally {
//revert the context if needed
if(gcubeContext!=null)
GCubeUtils.revertToSourceContext(gcubeContext);
}
return null;
}
/**
* Delete resource from dataset.
*
* @param resourceId the resource id
* @param username the username
* @return true, if successful
* @throws Exception the exception
*/
/* (non-Javadoc)
* @see org.gcube.datacatalogue.utillibrary.server.DataCatalogue#deleteResourceFromDataset(java.lang.String)
*/
@Override
public boolean deleteResourceFromDataset(String resourceId, String username) throws Exception {
LOG.info("Called deleteResourceFromDataset - resource with id " + resourceId);
// checks
checkNotNull(resourceId);
checkArgument(!resourceId.isEmpty());
GcubeContext gcubeContext = null;
try{
CkanResource theResource = ckanCaller.getResource(resourceId);
CkanDataset theDataset = getDataset(theResource.getPackageId(), username);
//Switch the context if needed
gcubeContext = GCubeUtils.detectTheOrgNameContexts(theDataset.getOrganization().getName(), username, true);
gCatCaller.deleteResource(theResource.getPackageId(), resourceId);
LOG.info("Resource with id: " + resourceId + " deleted correclty");
return true;
}catch(Exception e){
LOG.error("Unable to delete resource whose id is " + resourceId, e);
}finally {
//revert the context if needed
if(gcubeContext!=null)
GCubeUtils.revertToSourceContext(gcubeContext);
}
return false;
}
/**
* Creates the group.
*
* @param name the name
* @param title the title
* @param description the description
* @return the ckan group
* @throws Exception the exception
*/
/* (non-Javadoc)
* @see org.gcube.datacatalogue.utillibrary.server.DataCatalogue#createGroup(java.lang.String, java.lang.String, java.lang.String)
*/
@Override
public CkanGroup createGroup(String name, String title, String description) throws Exception {
// checks
checkNotNull(name);
checkArgument(!name.trim().isEmpty());
// check if it exists
CkanGroup toCreate = null;
LOG.debug("Request for creating group with name " + name + " title " + title + " and description " + description);
String normalizedName = CatalogueUtilMethods.fromGroupTitleToName(name);
if((toCreate = groupExists(name))!= null)
return toCreate;
else{
try{
CkanGroup group = new CkanGroup(normalizedName);
group.setTitle(title);
group.setDisplayName(title);
group.setDescription(description);
String jsonValueGroup = MarshUnmarshCkanObject.toJsonValueGroup(group);
LOG.trace("Serialized group is: " + jsonValueGroup);
String theGroup = gCatCaller.createGroup(jsonValueGroup);
toCreate = MarshUnmarshCkanObject.toCkanGroup(theGroup);
LOG.info("Created the group with id: " + toCreate.getId() + ", name: "+toCreate.getName());
}catch(JackanException je){
LOG.error("Unable to create such group", je);
}
}
return toCreate;
}
/**
* Gets the roles and users group.
*
* @param groupName the group name
* @return the roles and users group
*/
/* (non-Javadoc)
* @see org.gcube.datacatalogue.utillibrary.server.DataCatalogue#getRolesAndUsersGroup(java.lang.String)
*/
@Override
public Map<RolesCkanGroupOrOrg, List<String>> getRolesAndUsersGroup(String groupName) {
// checks
checkNotNull(groupName);
checkArgument(!groupName.isEmpty());
Map<RolesCkanGroupOrOrg, List<String>> capacityAndUsers = null;
String groupNameToCheck = CatalogueUtilMethods.fromGroupTitleToName(groupName);
CkanGroup group = ckanCaller.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);
}
LOG.info("Returning " + capacityAndUsers);
}
return capacityAndUsers;
}
/* (non-Javadoc)
* @see org.gcube.datacatalogue.utillibrary.server.DataCatalogue#assignDatasetToGroup(java.lang.String, java.lang.String)
*/
/**
* Assign dataset to group.
*
* @param groupNameOrId the group name or id
* @param datasetNameOrId the dataset name or id
* @return true, if successful
*/
//TODO HAS TO BE REVISITED by gCAT
@Override
public boolean assignDatasetToGroup(String groupNameOrId, String datasetNameOrId) {
return assignDatasetToGroupBody(groupNameOrId, datasetNameOrId, false);
}
/* (non-Javadoc)
* @see org.gcube.datacatalogue.utillibrary.server.DataCatalogue#patchProductCustomFields(java.lang.String, java.lang.String, java.util.Map, boolean)
*/
/**
* Patch product custom fields.
*
* @param productId the product id
* @param username the username
* @param customFieldsToChange the custom fields to change
* @param removeOld the remove old
* @return true, if successful
*/
//TODO HAS TO BE REVISITED by gCAT
@Override
public boolean patchProductCustomFields(String productId, String username,
Map<String, List<String>> customFieldsToChange, boolean removeOld) {
// checks
checkNotNull(productId);
checkNotNull(username);
if(customFieldsToChange == null || customFieldsToChange.isEmpty()) // TODO.. remove all custom fields maybe?!
return true;
String apiKey = getApiKeyFromUsername(username);
LOG.info("Going to change product with id " + productId +"."
+ " Request comes from user with key " + apiKey.substring(0, 5) + "****************");
LOG.info("The new values are " + customFieldsToChange);
// Get already available custom fields
Map<String, List<String>> fromCKANCustomFields = new HashMap<String, List<String>>();
ExtendCkanClient client = new ExtendCkanClient(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);
}
LOG.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 = 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))
if(!removeOld)
uniqueValues.addAll(fromCKANCustomFields.get(key));
uniqueValues.addAll(newValues);
fromCKANCustomFields.put(key, new ArrayList<String>(uniqueValues));
}
LOG.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 = 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);
LOG.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){
LOG.error("Failed to patch the product ", e);
}
return false;
}
/**
* The real body of the assignDatasetToGroup.
*
* @param groupNameOrId the group name or id
* @param datasetNameOrId the dataset name or id
* @param addOnParents the add on parents
* @return true, if successful
*/
private boolean assignDatasetToGroupBody(String groupNameOrId, String datasetNameOrId, boolean addOnParents) {
// checks
checkNotNull(groupNameOrId);
checkArgument(!groupNameOrId.isEmpty());
checkNotNull(datasetNameOrId);
checkArgument(!datasetNameOrId.isEmpty());
String groupNameToCheck = CatalogueUtilMethods.fromGroupTitleToName(groupNameOrId);
try(CloseableHttpClient httpClient = HttpClientBuilder.create().build();){
ExtendCkanClient client = new ExtendCkanClient(CKAN_CATALOGUE_URL, CKAN_TOKEN_SYS);
// check the group exists
CkanGroup group = client.getGroup(groupNameToCheck);
// move to a list
List<String> groupNames = new ArrayList<String>();
groupNames.add(group.getName());
if(group != null && addOnParents){
findHierarchyGroups(groupNames, CKAN_TOKEN_SYS);
}
// 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);
LOG.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 = it.next();
try{
if(object.containsKey("name"))
groupNames.add((String)object.get("name"));
}catch(Exception e){
LOG.error("Error", e);
}
}
// remove duplicates
Set<String> groupNamesSet = new HashSet<String>(groupNames);
LOG.debug("Groups to be added are " + groupNamesSet);
// now we patch the dataset with the new group
String pathUpdatePatch = CKAN_CATALOGUE_URL + "/api/3/action/package_patch";
JSONObject req = new JSONObject();
req.put("id", datasetNameOrId);
JSONArray groups = new JSONArray();
Iterator<String> iteratorNameSet = groupNamesSet.iterator();
while (iteratorNameSet.hasNext()) {
String groupName = iteratorNameSet.next();
JSONObject groupJSON = new JSONObject();
groupJSON.put("name", groupName);
groups.add(groupJSON);
}
req.put("groups", groups);
LOG.debug("Request for patch is going to be " + req.toJSONString());
HttpPost request = new HttpPost(pathUpdatePatch);
request.addHeader("Authorization", CKAN_TOKEN_SYS);
StringEntity params = new StringEntity(req.toJSONString());
request.setEntity(params);
HttpResponse responsePatch = httpClient.execute(request);
LOG.debug("Response code is " + responsePatch.getStatusLine().getStatusCode() + " and response message is " + responsePatch.getStatusLine().getReasonPhrase());
if(responsePatch.getStatusLine().getStatusCode() == HttpStatus.SC_OK){
LOG.info("Dataset Added to the group!!");
return true;
}
}
}catch(Exception e){
LOG.error("Unable to make this association", e);
}
return false;
}
/**
* Find the hierarchy of trees.
*
* @param groupsTitles the groups titles
* @param apiKey the api key
*/
private void findHierarchyGroups(
List<String> groupsTitles,
String apiKey) {
ListIterator<String> iterator = groupsTitles.listIterator();
while (iterator.hasNext()) {
String group = iterator.next();
List<CkanGroup> parents = getParentGroups(group, apiKey);
if(parents == null || parents.isEmpty())
return;
for (CkanGroup ckanGroup : parents) {
List<String> parentsList = new ArrayList<String>(Arrays.asList(ckanGroup.getName()));
findHierarchyGroups(parentsList, apiKey);
for (String parent : parentsList) {
iterator.add(parent);
}
}
}
}
/**
* *****************************************************************************
*
*
* MANAGEMENT OPERATIONS
*
*
* *****************************************************************************.
*
* @param username the username
* @param sourceOrganization the source organization
* @param currentRole the current role
*/
@Override
public void assignRolesOtherOrganization(String username,
String sourceOrganization, RolesCkanGroupOrOrg currentRole) {
checkNotNull(username);
checkNotNull(sourceOrganization);
checkNotNull(currentRole);
LOG.info("Request for assigning other roles for user " + username + ", whose current role is " + currentRole + " and organization " + sourceOrganization);
Iterator<Entry<String, String>> iterator = extendRoleInOrganization.entrySet().iterator();
LOG.debug("List of entries to check is " + extendRoleInOrganization);
while (iterator.hasNext()) {
Map.Entry<java.lang.String, java.lang.String> entry = iterator
.next();
String sourceOrg = entry.getKey();
LOG.debug("Found organization source " + sourceOrg);
if(sourceOrg.equals(sourceOrganization)){
String[] values = entry.getValue().split(DataCatalogueRunningCluster.TUPLES_SEPARATOR);
for(int i = 0; i < values.length; i++){
String destOrg = values[i].split("\\"+DataCatalogueRunningCluster.ROLE_ORGANIZATION_SEPARATOR)[0];
String role = values[i].split("\\"+DataCatalogueRunningCluster.ROLE_ORGANIZATION_SEPARATOR)[1];
LOG.debug("Role is " + role + " and organization is " + destOrg);
RolesCkanGroupOrOrg ckanRole;
if(role.equals(DataCatalogueRunningCluster.CKAN_GENERIC_ROLE))
ckanRole = currentRole;
else
ckanRole = RolesCkanGroupOrOrg.convertFromCapacity(role);
LOG.info("Checking for extra role: role is " + ckanRole + " and organization is " + destOrg);
checkRoleIntoOrganization(username, destOrg, ckanRole);
}
}
}
}
}