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 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.common.scope.api.ScopeProvider; import org.gcube.dataaccess.ckanutillibrary.CKanUtilsFactory; 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.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.CheckedCkanClient; import eu.trentorise.opendata.jackan.model.CkanDataset; import eu.trentorise.opendata.jackan.model.CkanOrganization; import eu.trentorise.opendata.jackan.model.CkanPair; import eu.trentorise.opendata.jackan.model.CkanResource; import eu.trentorise.opendata.jackan.model.CkanTag; /** * 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); /** * Get the current scope (/gcube is returned if in development) * @return */ private String getCurrentScope(){ if(isWithinPortal()) return ScopeProvider.instance.get(); else return "/gcube"; } /** * Return the ckan catalogue url for this scope. * @return */ private String getCatalogueUrl(){ logger.info("Request for catalogue url"); try{ String currentScope = getCurrentScope(); return "https://" + CKanUtilsFactory.getInstance().getCkanUtilsForScope(currentScope).getCatalogueUrl(); }catch(Exception e){ logger.error("Failed to retrieve catalogue url information", e); } return null; } /** * Retrieve the api key for this user * @param owner * @return */ private String getCKANApikeyFromUser(String owner) { logger.info("Request for user api key"); try{ String currentScope = getCurrentScope(); return CKanUtilsFactory.getInstance().getCkanUtilsForScope(currentScope).getApiKeyFromUser(owner); }catch(Exception e){ logger.error("Failed to retrieve api key for user " + owner, e); } return null; } /** * Retrieve the list of organizations in which the user can publish * @param owner * @return */ private List getUserOrganizationsList(String owner) { logger.info("Request for user " + owner + " organizations list"); try{ String currentScope = getCurrentScope(); return CKanUtilsFactory.getInstance().getCkanUtilsForScope(currentScope).getOrganizationsNamesByUser(owner); }catch(Exception e){ logger.error("Failed to retrieve user's organizations", e); } return null; } /** * 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) { String currentScope = getCurrentScope(); try { return CKanUtilsFactory.getInstance().getCkanUtilsForScope(currentScope).findLicenseIdByLicense(chosenLicense); } catch (Exception e) { logger.error("Failed to retrieve license id", e); } return null; } @Override public LicensesBean getLicenses() { logger.info("Request for CKAN licenses"); try { String currentScope = getCurrentScope(); List titlesLicenses; titlesLicenses = CKanUtilsFactory.getInstance().getCkanUtilsForScope(currentScope).getLicenseTitles(); // return the bean return new LicensesBean(titlesLicenses); } catch (Exception e) { logger.error("Failed to retrieve licenses", e); } return null; } @Override public DatasetMetadataBean getDatasetBean(String folderId, String owner){ DatasetMetadataBean bean = null; logger.info("Bean request for " + folderId + " and " + owner); if(isWithinPortal()){ try{ 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.setOwnerFolderInWorkspace(owner); bean.setVersion(1); bean.setAuthor(userOwner.getFullname()); bean.setAuthorEmail(userOwner.getEmail()); bean.setMaintainer(userOwner.getFullname()); bean.setMaintainerEmail(userOwner.getEmail()); bean.setOrganizationList(getUserOrganizationsList(owner)); 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); } }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)); bean.setOwnerFolderInWorkspace(owner); if(folderId != null && !folderId.isEmpty()){ ScopeProvider.instance.set("/gcube"); 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); } }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 boolean createCKanDataset(DatasetMetadataBean toCreate) { // retrieve ckan's catalog url String ckanPortalUrl = getCatalogueUrl(); // retrieve the owner of the original folder into the workspace String owner = toCreate.getOwnerFolderInWorkspace(); // retrieve the api key for this user String apiKey = getCKANApikeyFromUser(owner); logger.info("Trying to create the dataset described by this bean " + toCreate + " into CKAN catalog at url " + ckanPortalUrl); // Checked client CheckedCkanClient client = new CheckedCkanClient(ckanPortalUrl, apiKey); // create the base dataset and fill it CkanDataset dataset = new CkanDataset(); // set dataset info (same id as the folder) dataset.setId(toCreate.getId()); // get the name from the title dataset.setName(nameFromTitle(toCreate.getTitle())); dataset.setTitle(toCreate.getTitle()); CkanOrganization orgTest = client.getOrganization(toCreate.getSelectedOrganization()); dataset.setOwnerOrg(orgTest.getId()); dataset.setAuthor(toCreate.getAuthor()); dataset.setAuthorEmail(toCreate.getAuthorEmail()); dataset.setMaintainer(toCreate.getMaintainer()); dataset.setMaintainerEmail(toCreate.getMaintainerEmail()); dataset.setVersion(String.valueOf(toCreate.getVersion())); dataset.setNotes(toCreate.getDescription()); logger.info("Searchable is " + toCreate.isSearchable() + " and visible is " + toCreate.getVisibility()); dataset.setPriv(false); dataset.setOpen(toCreate.getVisibility()); // iterate over the licenses to find the id of the chosen one String chosenLicense = toCreate.getLicense(); String licenseId = findLicenseIdByLicense(chosenLicense); dataset.setLicenseId(licenseId); // set the tags, if any if(toCreate.getTags() != null && !toCreate.getTags().isEmpty()){ // convert to ckan tags List ckanTags = new ArrayList(toCreate.getTags().size()); for (String stringTag : toCreate.getTags()) { ckanTags.add(new CkanTag(stringTag)); } dataset.setTags(ckanTags); } // set the custom fields, if any if(toCreate.getCustomFields() != null && !toCreate.getCustomFields().isEmpty()){ // iterate and create Iterator> iterator = toCreate.getCustomFields().entrySet().iterator(); List extras = new ArrayList(toCreate.getCustomFields().entrySet().size()); while (iterator.hasNext()) { Map.Entry entry = (Map.Entry) iterator.next(); extras.add(new CkanPair(entry.getKey(), entry.getValue())); } dataset.setExtras(extras); } // check if we need to add the resources if(toCreate.isAddResources()){ logger.debug("We need to add resources to the dataset"); try{ ScopeProvider.instance.set("/gcube"); Workspace ws = HomeLibrary .getHomeManagerFactory() .getHomeManager() .getHome(toCreate.getOwnerFolderInWorkspace()).getWorkspace(); List resources = new ArrayList(); for(String resourceId: toCreate.getResourcesIds()){ FolderItem item = (FolderItem)ws.getItem(resourceId); CkanResource newResource = new CkanResource(); newResource.setDescription(item.getDescription()); newResource.setId(item.getId()); newResource.setUrl(item.getPublicLink(false)); newResource.setName(item.getName()); newResource.setMimetype(item.getMimeType()); resources.add(newResource); } // add to the dataset dataset.setResources(resources); }catch(Exception e){ logger.error("Unable to add those resources to the dataset", e); } } // try to create CkanDataset res = null; try{ res = client.createDataset(dataset); }catch(Exception e){ // try to update logger.error("Error while creating the dataset, probably it already exists. Trying to update it..", e); res = client.updateDataset(dataset); } if(res != null) logger.debug("Dataset created/updated " + res.getId()); else{ logger.error("Dataset described by " + toCreate + " not created!"); return false; } return true; } /** * Generate the catalogue's dataset name from its title * @param title * @return */ private String nameFromTitle(String title) { String convertedName = title.replaceAll(" ", "-"); convertedName = convertedName.toLowerCase(); if(convertedName.endsWith("-")) convertedName = convertedName.substring(0, convertedName.length() - 2); return convertedName; } }