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; /** * 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 = "4620e6d0-2313-4f48-9d54-eb3efd01a810"; // 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 getUserOrganizationsList(String username, String scope) { logger.debug("Request for user " + username + " organizations list"); List orgsName = new ArrayList(); 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)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 rolesToMatch = new ArrayList(); rolesToMatch.add(RolesIntoOrganization.EDITOR); rolesToMatch.add(RolesIntoOrganization.ADMIN); Map> orgsAndRoles = ckanUtils.getGroupsAndRolesByUser(username, rolesToMatch); logger.debug("Result is " + orgsAndRoles); Iterator>> iterator = orgsAndRoles.entrySet().iterator(); // get the names while (iterator.hasNext()) { Map.Entry> entry = (Map.Entry>) 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 getMetadataProfilesList() { List beans = new ArrayList(); 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)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 wrapperList = new ArrayList(); List 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 titlesLicenses = getCkanUtilsObj().getLicenseTitles(); licensesBean = new LicensesBean(titlesLicenses); 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); if(isWithinPortal()){ try{ ASLSession aslSession = getASLSession(); String user = aslSession.getUsername(); // 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.setAuthor(userOwner.getFullname()); 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 bean.setTitle(retrievedItem.getName()); bean.setDescription(retrievedItem.getDescription()); // retrieve gcube items of the folder Map folderItems = getGcubeItemProperties(retrievedItem); bean.setCustomFields(folderItems); // check the resources within the folder (skip subdirectories) List childrenIds = new ArrayList(); for (WorkspaceItem file : retrievedItem.getChildren()) { if(!file.isFolder()) // ok, it's a file childrenIds.add(file.getId()); } bean.setResourcesIds(childrenIds); } // retrieve the metadata List 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); bean.setTitle("dataset-" + Calendar.getInstance().getTimeInMillis()); bean.setAuthor("Costantino 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 folderItems = getGcubeItemProperties(retrievedItem); bean.setCustomFields(folderItems); // check the resources within the folder (skip subdirectories) List childrenIds = new ArrayList(); for (WorkspaceItem file : retrievedItem.getChildren()) { if(!file.isFolder()) // ok, it's a file childrenIds.add(file.getId()); } bean.setResourcesIds(childrenIds); } // retrieve the metadata List 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 getGcubeItemProperties(WorkspaceItem item) { if(item instanceof GCubeItem){ GCubeItem gItem = (GCubeItem) item; try { if(gItem.getProperties()!=null){ Map map = gItem.getProperties().getProperties(); HashMap properties = new HashMap(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; } // get the owner String username = toCreate.getOwnerIdentifier(); // set dataset info (same id as the folder, if the request comes from the workspace) String withId = null; if(isWorkspaceRequest) withId = toCreate.getId(); String title = toCreate.getTitle(); String organizationNameOrId = toCreate.getSelectedOrganization(); String author = toCreate.getAuthor(); 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 listOfTags = toCreate.getTags(); Map customFields = toCreate.getCustomFields(); boolean setPublic = toCreate.getVisibility(); List resources = new ArrayList(); // build the resource (if it is a workspaceRequest type) if(toCreate.isAddResources() && isWorkspaceRequest){ logger.debug("We need to add resources to the dataset"); try{ Workspace ws = HomeLibrary .getHomeManagerFactory() .getHomeManager() .getHome(toCreate.getOwnerIdentifier()).getWorkspace(); for(String resourceId: toCreate.getResourcesIds()){ FolderItem item = (FolderItem)ws.getItem(resourceId); ResourceBean newResource = new ResourceBean(); newResource.setDescription(item.getDescription()); newResource.setId(item.getId()); newResource.setUrl(item.getPublicLink(false)); newResource.setName(item.getName()); newResource.setMimeType(item.getMimeType()); newResource.setOwner(username); resources.add(newResource); } }catch(Exception e){ logger.error("Unable to add those resources to the dataset", e); } } String datasetId = utils.createCKanDataset(getUserCKanTokenFromSession(), withId, 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); } }