ckan-metadata-publisher-widget/src/main/java/org/gcube/portlets/widgets/ckandatapublisherwidget/server/CKANPublisherServicesImpl.java

724 lines
23 KiB
Java

package org.gcube.portlets.widgets.ckandatapublisherwidget.server;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.servlet.http.HttpSession;
import org.gcube.application.framework.core.session.ASLSession;
import org.gcube.application.framework.core.session.SessionManager;
import org.gcube.common.homelibrary.home.HomeLibrary;
import org.gcube.common.homelibrary.home.exceptions.InternalErrorException;
import org.gcube.common.homelibrary.home.workspace.Workspace;
import org.gcube.common.homelibrary.home.workspace.WorkspaceItem;
import org.gcube.common.homelibrary.home.workspace.folder.FolderItem;
import org.gcube.common.homelibrary.home.workspace.folder.items.GCubeItem;
import org.gcube.datacatalogue.ckanutillibrary.CKanUtils;
import org.gcube.datacatalogue.ckanutillibrary.CKanUtilsImpl;
import org.gcube.datacatalogue.ckanutillibrary.models.ResourceBean;
import org.gcube.datacatalogue.ckanutillibrary.models.RolesIntoOrganization;
import org.gcube.datacatalogue.metadatadiscovery.DataCalogueMetadataFormatReader;
import org.gcube.datacatalogue.metadatadiscovery.bean.MetadataType;
import org.gcube.datacatalogue.metadatadiscovery.bean.jaxb.MetadataField;
import org.gcube.datacatalogue.metadatadiscovery.bean.jaxb.MetadataFormat;
import org.gcube.datacatalogue.metadatadiscovery.bean.jaxb.MetadataValidator;
import org.gcube.datacatalogue.metadatadiscovery.bean.jaxb.MetadataVocabulary;
import org.gcube.portal.custom.scopemanager.scopehelper.ScopeHelper;
import org.gcube.portlets.widgets.ckandatapublisherwidget.client.CKanPublisherService;
import org.gcube.portlets.widgets.ckandatapublisherwidget.shared.DatasetMetadataBean;
import org.gcube.portlets.widgets.ckandatapublisherwidget.shared.LicensesBean;
import org.gcube.portlets.widgets.ckandatapublisherwidget.shared.MetaDataProfileBean;
import org.gcube.portlets.widgets.ckandatapublisherwidget.shared.MetaDataTypeWrapper;
import org.gcube.portlets.widgets.ckandatapublisherwidget.shared.MetadataFieldWrapper;
import org.gcube.portlets.widgets.ckandatapublisherwidget.shared.ResourceBeanWrapper;
import org.gcube.vomanagement.usermanagement.UserManager;
import org.gcube.vomanagement.usermanagement.impl.LiferayUserManager;
import org.gcube.vomanagement.usermanagement.model.GCubeUser;
import org.slf4j.LoggerFactory;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import com.liferay.portal.service.UserLocalServiceUtil;
import eu.trentorise.opendata.jackan.model.CkanLicense;
/**
* Server side of the data publisher.
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
*/
@SuppressWarnings("serial")
public class CKANPublisherServicesImpl extends RemoteServiceServlet implements CKanPublisherService{
// Logger
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(CKANPublisherServicesImpl.class);
public static final String TEST_SCOPE = "/gcube/devsec/devVRE";
public static final String TEST_USER = "test.user";
private final static String TEST_SEC_TOKEN = "a1e19695-467f-42b8-966d-bf83dd2382ef";
// ckan keys for ASL
private static final String CKAN_TOKEN_KEY = "ckanToken";
private static final String CKAN_LICENSES_KEY = "ckanLicenses"; // licenses
private static final String CKAN_ORGANIZATIONS_PUBLISH_KEY = "ckanOrganizationsPublish"; // here he can publish
private static final String CKAN_PROFILES_KEY = "ckanProfiles"; // product profiles
/**
* Since it needs the scope, we need to check if it is null or not
* @return
*/
private CKanUtils getCkanUtilsObj(){
CKanUtils instance = null;
try{
String currentScope = getASLSession().getScope();
instance = new CKanUtilsImpl(currentScope);
}catch(Exception e){
logger.error("Unable to retrieve ckan utils", e);
}
return instance;
}
/**
* the current ASLSession
* @return the session
*/
private ASLSession getASLSession() {
String sessionID = this.getThreadLocalRequest().getSession().getId();
String user = (String) this.getThreadLocalRequest().getSession().getAttribute(ScopeHelper.USERNAME_ATTRIBUTE);
if (user == null) {
logger.warn("USER IS NULL setting testing user and Running OUTSIDE PORTAL");
user = getDevelopmentUser();
SessionManager.getInstance().getASLSession(sessionID, user).setScope(TEST_SCOPE);
}
return SessionManager.getInstance().getASLSession(sessionID, user);
}
/**
* when packaging test will fail if the user is not set to test.user
* @return .
*/
public String getDevelopmentUser() {
String user = TEST_USER;
//user = "costantino.perciante";
return user;
}
/**
* Get current user's token
* @return String the ckan user's token
*/
private String getUserCKanTokenFromSession(){
String token = null;
if(!isWithinPortal()){
logger.warn("You are running outside the portal");
token = TEST_SEC_TOKEN;
}else{
ASLSession aslSession = getASLSession();
String username = aslSession.getUsername();
// store info in the http session
HttpSession httpSession = getThreadLocalRequest().getSession();
// get the key per scope
String keyPerScope = concatenateSessionKeyScope(CKAN_TOKEN_KEY, aslSession.getScope());
// check if session expired
if(username.equals(TEST_USER)){
logger.warn("Session expired, returning null token");
token = null;
}else{
try{
logger.debug("User in session is " + username);
if(httpSession.getAttribute(keyPerScope) != null){
token = (String)httpSession.getAttribute(keyPerScope);
logger.debug("Found ckan token into session");
}
else{
token = getCkanUtilsObj().getApiKeyFromUsername(username);
httpSession.setAttribute(keyPerScope, token);
logger.debug("Ckan token has been set for user " + username);
}
logger.debug("Found ckan token " + token.substring(0, 3) + "************************" + " for user " + username);
}catch(Exception e){
logger.error("Error while retrieving the key" , e);
}
}
}
return token;
}
/**
* Retrieve the list of organizations in which the user can publish (roles ADMIN, EDITOR)
* If he is a SYSADMIN, he can publish everywhere
* @param username
* @return the list of organizations
*/
private List<String> getUserOrganizationsList(String username, String scope) {
logger.debug("Request for user " + username + " organizations list");
List<String> orgsName = new ArrayList<String>();
CKanUtils ckanUtils = getCkanUtilsObj();
// get http session
HttpSession httpSession = getThreadLocalRequest().getSession();
// get key
String keyPerScope = concatenateSessionKeyScope(CKAN_ORGANIZATIONS_PUBLISH_KEY, scope);
if(httpSession.getAttribute(keyPerScope) != null){
orgsName = (List<String>)httpSession.getAttribute(keyPerScope);
logger.info("List of organizations was into session");
}
else{
if(getCkanUtilsObj().isSysAdmin(username, getUserCKanTokenFromSession())){
logger.debug("The user " + username + " is a sysadmin. He can publish everywhere");
orgsName = ckanUtils.getOrganizationsNames(); // get all organizations' names
}else{
// We need to retrieve orgs in which the user has the roles ADMIN or EDITOR
List<RolesIntoOrganization> rolesToMatch = new ArrayList<RolesIntoOrganization>();
rolesToMatch.add(RolesIntoOrganization.EDITOR);
rolesToMatch.add(RolesIntoOrganization.ADMIN);
Map<String, List<RolesIntoOrganization>> orgsAndRoles = ckanUtils.getGroupsAndRolesByUser(username, rolesToMatch);
logger.debug("Result is " + orgsAndRoles);
Iterator<Entry<String, List<RolesIntoOrganization>>> iterator = orgsAndRoles.entrySet().iterator();
// get the names
while (iterator.hasNext()) {
Map.Entry<String, List<RolesIntoOrganization>> entry = (Map.Entry<String, List<RolesIntoOrganization>>) iterator
.next();
orgsName.add(entry.getKey());
logger.debug("The user has a role ADMIN/EDITOR into org " + entry.getKey());
}
}
httpSession.setAttribute(keyPerScope, orgsName);
logger.info("Organizations name for user " + username + " has been saved into session");
}
return orgsName;
}
/**
* Online or in development mode?
* @return true if you're running into the portal, false if in development
*/
private boolean isWithinPortal() {
try {
UserLocalServiceUtil.getService();
return true;
}
catch (com.liferay.portal.kernel.bean.BeanLocatorException ex) {
logger.trace("Development Mode ON");
return false;
}
}
/**
* Find a license id given the license text.
* @param chosenLicense
* @return
*/
private String findLicenseIdByLicense(String chosenLicense) {
return getCkanUtilsObj().findLicenseIdByLicense(chosenLicense);
}
/**
* Retrieve the list of metadata beans
* @return
*/
private List<MetaDataProfileBean> getMetadataProfilesList() {
List<MetaDataProfileBean> beans = new ArrayList<MetaDataProfileBean>();
ASLSession session = getASLSession();
String username = session.getUsername();
logger.debug("User in session is " + username);
// get http session
HttpSession httpSession = getThreadLocalRequest().getSession();
// get key per scope
String keyPerScope = concatenateSessionKeyScope(CKAN_PROFILES_KEY, session.getScope());
if(httpSession.getAttribute(keyPerScope) != null){
beans = (List<MetaDataProfileBean>)httpSession.getAttribute(keyPerScope);
logger.info("List of profiles was into session");
}
else{
try {
DataCalogueMetadataFormatReader reader = new DataCalogueMetadataFormatReader();
for (MetadataType mt : reader.getListOfMetadataTypes()) {
MetadataFormat metadata = reader.getMetadataFormatForMetadataType(mt);
// we need to wrap the list of metadata
List<MetadataFieldWrapper> wrapperList = new ArrayList<MetadataFieldWrapper>();
List<MetadataField> toWrap = metadata.getMetadataFields();
for(MetadataField metadataField: toWrap){
MetadataFieldWrapper wrapperObj = new MetadataFieldWrapper();
wrapperObj.setDefaulValue(metadataField.getDefaulValue());
wrapperObj.setFieldName(metadataField.getFieldName());
wrapperObj.setIsBoolean(metadataField.getIsBoolean());
wrapperObj.setMandatory(metadataField.getMandatory());
wrapperObj.setNote(metadataField.getNote());
MetadataValidator validator = metadataField.getValidator();
if(validator != null)
wrapperObj.setValidator(validator.getRegularExpression());
MetadataVocabulary vocabulary = metadataField.getVocabulary();
if(vocabulary != null)
wrapperObj.setVocabulary(vocabulary.getVocabularyFields());
// add to the list
wrapperList.add(wrapperObj);
}
// wrap the mt as well
MetaDataTypeWrapper typeWrapper = new MetaDataTypeWrapper();
typeWrapper.setDescription(mt.getDescription());
typeWrapper.setId(mt.getId());
typeWrapper.setName(mt.getName());
MetaDataProfileBean bean = new MetaDataProfileBean(typeWrapper, wrapperList);
beans.add(bean);
}
logger.debug("List of beans is " + beans);
httpSession.setAttribute(keyPerScope, beans);
logger.debug("List of profiles has been saved into session");
} catch (Exception e) {
logger.error("Error while retrieving metadata beans ", e);
}
}
return beans;
}
@Override
public LicensesBean getLicenses() {
logger.info("Request for CKAN licenses");
ASLSession session = getASLSession();
String username = session.getUsername();
logger.debug("User in session is " + username);
// get http session
HttpSession httpSession = getThreadLocalRequest().getSession();
// get key per scope
String keyPerScope = concatenateSessionKeyScope(CKAN_LICENSES_KEY, session.getScope());
LicensesBean licensesBean = null;
if(httpSession.getAttribute(keyPerScope) != null){
licensesBean = (LicensesBean)httpSession.getAttribute(keyPerScope);
logger.debug("List of licenses was into session");
}
else{
List<CkanLicense> titlesLicenses = getCkanUtilsObj().getLicenses();
List<String> titles = new ArrayList<String>();
List<String> urls = new ArrayList<String>();
for (CkanLicense license : titlesLicenses) {
titles.add(license.getTitle());
String url = (license.getUrl() != null && !license.getUrl().isEmpty()) ? license.getUrl() : "";
urls.add(url);
}
licensesBean = new LicensesBean(titles, urls);
httpSession.setAttribute(keyPerScope, licensesBean);
logger.debug("List of licenses has been saved into session");
}
return licensesBean;
}
@Override
public DatasetMetadataBean getDatasetBean(String folderId, String owner){
DatasetMetadataBean bean = null;
logger.info("DatasetBean request for " + folderId + " and " + owner);
ASLSession aslSession = getASLSession();
String user = aslSession.getUsername();
if(isWithinPortal()){
try{
// check if session expired
if(user.equals(TEST_USER)){
logger.debug("SESSION EXPIRED");
return null;
}
logger.debug("Request dataset metadata bean for folder with id " + folderId
+ " whose owner is " + owner);
// get usermanager (liferay)
UserManager liferUserManager = new LiferayUserManager();
GCubeUser userOwner = liferUserManager.getUserByUsername(owner);
// build bean
logger.debug("Building bean");
bean = new DatasetMetadataBean();
bean.setId(folderId);
bean.setOwnerIdentifier(owner);
bean.setVersion(1);
bean.setAuthorName(userOwner.getFirstName());
bean.setAuthorSurname(userOwner.getLastName());
bean.setAuthorEmail(userOwner.getEmail());
bean.setMaintainer(userOwner.getFullname());
bean.setMaintainerEmail(userOwner.getEmail());
bean.setOrganizationList(getUserOrganizationsList(owner, aslSession.getScope()));
// if the request comes from the workspace
if(folderId != null && !folderId.isEmpty()){
Workspace ws = HomeLibrary
.getHomeManagerFactory()
.getHomeManager()
.getHome(owner).getWorkspace();
WorkspaceItem retrievedItem = ws.getItem(folderId);
// set some info
String onlyAlphanumeric = retrievedItem.getName().replaceAll("[^A-Za-z0-9]", "");
bean.setTitle(onlyAlphanumeric);
bean.setDescription(retrievedItem.getDescription());
// retrieve gcube items of the folder
Map<String, String> folderItems = getGcubeItemProperties(retrievedItem);
bean.setCustomFields(folderItems);
// check the resources within the folder (skip subdirectories)
List<String> childrenIds = new ArrayList<String>();
for (WorkspaceItem file : retrievedItem.getChildren()) {
if(!file.isFolder()) // ok, it's a file
childrenIds.add(file.getId());
}
List<ResourceBeanWrapper> listOfResources = getWorkspaceResourcesInformation(childrenIds, ws, user);
bean.setResources(listOfResources);
}
// retrieve the metadata
List<MetaDataProfileBean> metadataBeans = getMetadataProfilesList();
bean.setMetadataList(metadataBeans);
}catch(Exception e){
logger.error("Error while retrieving folder information", e);
}
}else{
try{
bean = new DatasetMetadataBean();
bean.setId(folderId);
bean.setDescription("This is a fantastic description");
bean.setVersion(1);
String onlyAlphanumeric = "test-creation-blablabla".replaceAll("[^A-Za-z0-9]", "");
bean.setTitle(onlyAlphanumeric + Calendar.getInstance().getTimeInMillis());
bean.setAuthorName("Costantino");
bean.setAuthorSurname("Perciante");
bean.setAuthorEmail("costantino.perciante@isti.cnr.it");
bean.setMaintainer("Costantino Perciante");
bean.setMaintainerEmail("costantino.perciante@isti.cnr.it");
bean.setOrganizationList(getUserOrganizationsList(owner, TEST_SCOPE));
bean.setOwnerIdentifier(owner);
if(folderId != null && !folderId.isEmpty()){
Workspace ws = HomeLibrary
.getHomeManagerFactory()
.getHomeManager()
.getHome(owner).getWorkspace();
WorkspaceItem retrievedItem = ws.getItem(folderId);
// retrieve gcube items of the folder
Map<String, String> folderItems = getGcubeItemProperties(retrievedItem);
bean.setCustomFields(folderItems);
// check the resources within the folder (skip subdirectories)
List<String> childrenIds = new ArrayList<String>();
for (WorkspaceItem file : retrievedItem.getChildren()) {
if(!file.isFolder()) // ok, it's a file
childrenIds.add(file.getId());
}
List<ResourceBeanWrapper> listOfResources = getWorkspaceResourcesInformation(childrenIds, ws, user);
bean.setResources(listOfResources);
}
// retrieve the metadata
List<MetaDataProfileBean> metadataBeans = getMetadataProfilesList();
bean.setMetadataList(metadataBeans);
}catch(Exception e){
logger.error("Error while building bean into dev mode", e);
}
}
return bean;
}
/** Gets the gcube item properties.
*
* @param item the item
* @return the gcube item properties
*/
private Map<String, String> getGcubeItemProperties(WorkspaceItem item) {
if(item instanceof GCubeItem){
GCubeItem gItem = (GCubeItem) item;
try {
if(gItem.getProperties()!=null){
Map<String, String> map = gItem.getProperties().getProperties();
HashMap<String, String> properties = new HashMap<String, String>(map.size()); //TO PREVENT GWT SERIALIZATION ERROR
for (String key : map.keySet())
properties.put(key, map.get(key));
return properties;
}
} catch (InternalErrorException e) {
logger.error("Error in server getItemProperties: ", e);
return null;
}
}
return null;
}
@Override
public DatasetMetadataBean createCKanDataset(DatasetMetadataBean toCreate, boolean isWorkspaceRequest) {
logger.debug("Request for creating a dataset with these information " + toCreate);
ASLSession aslSession = getASLSession();
String user = aslSession.getUsername();
CKanUtils utils = getCkanUtilsObj();
try{
// check if session expired
if(user.equals(TEST_USER)){
logger.debug("SESSION EXPIRED");
return null;
}
String title = toCreate.getTitle();
String organizationNameOrId = toCreate.getSelectedOrganization();
String author = toCreate.getAuthorFullName();
String authorMail = toCreate.getAuthorEmail();
String maintainer = toCreate.getMaintainer();
String maintainerMail = toCreate.getMaintainerEmail();
long version = toCreate.getVersion();
String description = toCreate.getDescription();
String chosenLicense = toCreate.getLicense();
String licenseId = findLicenseIdByLicense(chosenLicense);
List<String> listOfTags = toCreate.getTags();
Map<String, String> customFields = toCreate.getCustomFields();
boolean setPublic = toCreate.getVisibility();
// get the list of resources and convert to ResourceBean
List<ResourceBean> resources = new ArrayList<ResourceBean>();
List<ResourceBeanWrapper> resourcesToAdd = toCreate.getResources();
if(resourcesToAdd != null && !resourcesToAdd.isEmpty())
for (ResourceBeanWrapper resourceBeanWrapper : resourcesToAdd) {
if(resourceBeanWrapper.isToBeAdded()){
resources.add(new ResourceBean(
resourceBeanWrapper.getUrl(),
resourceBeanWrapper.getName(),
resourceBeanWrapper.getDescription(),
resourceBeanWrapper.getId(),
resourceBeanWrapper.getOwner(),
null,
resourceBeanWrapper.getMimeType()));
}
}
String datasetId = utils.createCKanDataset(getUserCKanTokenFromSession(), title, organizationNameOrId, author,
authorMail, maintainer, maintainerMail, version, description, licenseId,
listOfTags, customFields, resources, setPublic);
if(datasetId != null){
logger.debug("Dataset created!");
toCreate.setId(datasetId);
// retrieve the url
String datasetUrl = utils.getPortletUrl() + "?path=" + utils.getUrlFromDatasetIdOrName(getUserCKanTokenFromSession(), datasetId, true);
toCreate.setSource(datasetUrl);
return toCreate;
}else{
logger.error("Failed to create the dataset");
}
}catch(Exception e){
logger.error("Unable to create the dataset", e);
}
return null;
}
@Override
public ResourceBeanWrapper addResourceToDataset(ResourceBeanWrapper resource, String datasetId, String owner) {
logger.debug("Incoming request for creating new resource for dataset with id " + datasetId);
logger.debug("Owner is " + owner + " and resource is " + resource);
if(!isWithinPortal()){
logger.warn("Running outside the portal");
return resource;
}else{
ASLSession session = getASLSession();
String username = session.getUsername();
if(username.equals(TEST_USER)){
logger.warn("SESSION EXPIRED! ");
return null;
}else{
try{
ResourceBean resourceBean = new ResourceBean(
resource.getUrl(),
resource.getName(),
resource.getDescription(),
null,
owner,
datasetId,
null);
String resourceId = getCkanUtilsObj().addResourceToDataset(resourceBean, getUserCKanTokenFromSession());
if(resourceId != null){
logger.debug("Resource " + resource.getName() + " is now available");
// set its id and turn it to the client
resource.setId(resourceId);
return resource;
}
}catch(Exception e){
logger.error("Unable to create new resource", e);
}
}
logger.debug("No resource created");
return null;
}
}
@Override
public boolean deleteResourceFromDataset(ResourceBeanWrapper resource,
String owner) {
logger.debug("Request for deleting resource " + resource);
boolean deleted = false;
if(!isWithinPortal()){
logger.warn("Running outside the portal");
return deleted;
}else{
ASLSession session = getASLSession();
String username = session.getUsername();
if(username.equals(TEST_USER)){
logger.warn("SESSION EXPIRED! ");
return deleted;
}else{
try{
deleted = getCkanUtilsObj().
deleteResourceFromDataset(resource.getId(), getUserCKanTokenFromSession());
if(deleted){
logger.debug("Resource described by " + resource + " deleted");
}else
logger.error("Resource described by " + resource + " NOT deleted");
}catch(Exception e){
logger.error("Error while trying to delete resource described by " + resource, e);
}
return deleted;
}
}
}
/**
* Builds a string made of key + scope
* @param key
* @param scope
* @return
*/
private String concatenateSessionKeyScope(String key, String scope){
return key.concat(scope);
}
/**
* Build up the resource beans.
* @param resourceIds
* @param ws
* @param username
* @return
*/
private List<ResourceBeanWrapper> getWorkspaceResourcesInformation(
List<String> resourceIds, Workspace ws, String username) {
List<ResourceBeanWrapper> toReturn = null;
try{
toReturn = new ArrayList<>();
for (String resourceId : resourceIds) {
logger.debug("RESOURCE ID IS " + resourceId);
ResourceBeanWrapper newResource = new ResourceBeanWrapper();
WorkspaceItem item = ws.getItem(resourceId);
newResource.setDescription(item.getDescription());
newResource.setId(item.getId());
newResource.setUrl(item.getPublicLink(true));
newResource.setName(item.getName());
newResource.setToBeAdded(true); // default is true
newResource.setMimeType(((FolderItem)item).getMimeType());
newResource.setOwner(username);
toReturn.add(newResource);
}
}catch(Exception e){
logger.error("Unable to retrieve resources' info", e);
}
return toReturn;
}
}