package org.gcube.portlets.widgets.ckandatapublisherwidget.server.utils; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; 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.HttpServletRequest; import org.gcube.common.portal.PortalContext; import org.gcube.common.storagehubwrapper.server.StorageHubWrapper; import org.gcube.common.storagehubwrapper.server.tohl.Workspace; import org.gcube.common.storagehubwrapper.shared.tohl.WorkspaceItem; import org.gcube.common.storagehubwrapper.shared.tohl.impl.URLFile; import org.gcube.common.storagehubwrapper.shared.tohl.items.FileItem; import org.gcube.common.storagehubwrapper.shared.tohl.items.GCubeItem; import org.gcube.common.storagehubwrapper.shared.tohl.items.PropertyMap; import org.gcube.datacatalogue.utillibrary.shared.ResourceBean; import org.gcube.portlets.widgets.ckandatapublisherwidget.shared.DatasetBean; import org.gcube.portlets.widgets.ckandatapublisherwidget.shared.ResourceElementBean; import org.gcube.vomanagement.usermanagement.model.GCubeUser; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.liferay.portal.service.UserLocalServiceUtil; /** * The Class WorkspaceUtils. * * @author Francesco Mangiacrapa at ISTI-CNR (francesco.mangiacrapa@isti.cnr.it) * * Feb 18, 2021 */ public class WorkspaceUtils { //private static final org.slf4j.Logger logger = LoggerFactory.getLogger(WorkspaceUtils.class); private static final Logger logger = LoggerFactory.getLogger(WorkspaceUtils.class); private static final String RESOURCES_NAME_SEPARATOR = "_"; private static final String STRIP_NOT_ALPHANUMERIC = "[^A-Za-z0-9.-_]"; /** * Checks if is within portal. * * @return true if you're running into the portal, false if in development */ public static boolean isWithinPortal() { try { UserLocalServiceUtil.getService(); return true; } catch (Exception ex) { logger.trace("Development Mode ON"); return false; } } /** * Gets the storage hub wrapper. * * @param request * the request * @param scopeGroupId * the scope group id. If scopeGroupId is null the scope is read * by using the request else by using the scopeGroupId * @param user * the user * @return the storage hub wrapper * @throws Exception * the exception */ public static StorageHubWrapper getStorageHubWrapper(final HttpServletRequest request, String scopeGroupId, GCubeUser user) throws Exception { if (user == null || user.getUsername().isEmpty()) throw new Exception("Session expired"); try { String scope; PortalContext pContext = PortalContext.getConfiguration(); if (isWithinPortal() && scopeGroupId != null) { scope = pContext.getCurrentScope(scopeGroupId); logger.debug(scope + " has retrieved by using the scopeGroupId=" + scopeGroupId); } else scope = pContext.getCurrentScope(request); logger.debug("Getting " + StorageHubWrapper.class.getSimpleName() + " for user: " + user.getUsername() + " by using the scope: " + scope); String token = pContext.getCurrentUserToken(scope, user.getUsername()); return new StorageHubWrapper(scope, token, false, false, true); } catch (Exception e) { logger.error("Error during getting storageHub wrapper", e); throw new Exception("Error on gettig the StorageHub wrapper for userId: " + user); } } /** * This method receives an item-id within the user's workspace and setit in the dataset bean to be returned. * revisited by Francesco * * @param wsItemId the ws item id * @param userName the user name * @param bean the bean * @param workspace the workspace * @throws Exception the exception */ public static void toWorkspaceResource(String wsItemId, String userName, DatasetBean bean, Workspace workspace) throws Exception { WorkspaceItem originalFolderOrFile = workspace.getItem(wsItemId); logger.debug("Item retrieved is " + originalFolderOrFile); String title = originalFolderOrFile.getTitle() != null && !originalFolderOrFile.getTitle().isEmpty() ? originalFolderOrFile.getTitle() : originalFolderOrFile.getName(); title = title.replaceAll(STRIP_NOT_ALPHANUMERIC, " "); bean.setTitle(title); ResourceElementBean resourceEB = new ResourceElementBean(); resourceEB.setOriginalIdInWorkspace(wsItemId); resourceEB.setName(originalFolderOrFile.getName()); resourceEB.setDescription(originalFolderOrFile.getDescription()); resourceEB.setFolder(originalFolderOrFile.isFolder()); resourceEB.setEditableName(originalFolderOrFile.getName()); resourceEB.setRootIdInWorkspace(workspace.getRoot().getId()); //in case of folder if(originalFolderOrFile.isFolder()) { // loading gcube properties Map folderItems = getGcubeItemProperties(originalFolderOrFile); if(folderItems != null && folderItems.size()>0){ // transform this properties Map> tempItems = new HashMap>(folderItems.size()); Iterator> iterator = folderItems.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry entry = (Map.Entry) iterator.next(); tempItems.put(entry.getKey(), Arrays.asList(entry.getValue())); } //setting properties as custom fields bean.setCustomFields(tempItems); } resourceEB.setChildrenSize(workspace.getChildren(originalFolderOrFile.getId()).size()); }else { //it is a file, removing extension int indexOfDot = title.lastIndexOf("."); if(indexOfDot>0) { String suffix = title.substring(indexOfDot, title.length()); if(suffix.length()>=1 && suffix.length()<=4) { //I'm considering last .suffix as an file extension so removing it. title = title.substring(0,indexOfDot); bean.setTitle(title); } } } //Replacing /Home/user.name with "" String fullPathBase = originalFolderOrFile.getPath(); logger.debug("Path is: "+fullPathBase); String prefixNodeWorkspace = String.format("/%s/%s", "Home",userName); logger.debug("Searching: "+prefixNodeWorkspace); if(fullPathBase.startsWith(prefixNodeWorkspace)){ logger.info("Removing from path the prefix: "+prefixNodeWorkspace); fullPathBase = fullPathBase.replaceFirst(prefixNodeWorkspace, ""); } resourceEB.setFullPath(fullPathBase); //setting parent id ResourceElementBean theParent = new ResourceElementBean(); if(originalFolderOrFile.getParentId()!=null) { try { WorkspaceItem parentItem = workspace.getItem(originalFolderOrFile.getParentId()); theParent.setOriginalIdInWorkspace(parentItem.getId()); theParent.setName(parentItem.getName()); }catch (Exception e) { logger.warn("Error on loading the parent item with id: "+originalFolderOrFile.getParentId()+" skipping it"); } } resourceEB.setParent(theParent); bean.setResourceRoot(resourceEB); } /** Gets the gcube item properties. * * @param item the item * @return the gcube item properties */ public static Map getGcubeItemProperties(WorkspaceItem item) { if(item instanceof GCubeItem){ GCubeItem gItem = (GCubeItem) item; try { Map properties = null; if(gItem.getPropertyMap()!=null){ Map map = toSimpleMap(gItem.getPropertyMap()); if(map!=null) { properties = new HashMap(map.size()); //TO PREVENT GWT SERIALIZATION ERROR for (String key : map.keySet()) properties.put(key, map.get(key)); } return properties; } } catch (Exception e) { logger.error("Error in server getItemProperties: ", e); } } return null; } /** * To simple map. * * @param propertyMap the property map * @return the map */ public static Map toSimpleMap(PropertyMap propertyMap) { if (propertyMap == null) return null; try { Map properties = null; Map map = propertyMap.getValues(); if (map != null) { properties = new HashMap(map.size()); for (String key : map.keySet()) { Object theValue = map.get(key); properties.put(key, (String) theValue); } } if(properties!=null) logger.error("Converted: "+properties.size()+" property/properties"); return properties; } catch (Exception e) { logger.error("Error on converting a PropertyMap to simple Map: ", e); return null; } } // /** // * Returns ResourceElementBean corresponding to workspaceFolderId // * // * @param workspaceFolderId the workspace folder id // * @param workspace the workspace // * @return ResourceElementBean a tree object // * @throws Exception the exception // */ // public static ResourceElementBean toResourceEBFromFolder(String workspaceFolderId, Workspace workspace) throws Exception{ // // ResourceElementBean rootElem = new ResourceElementBean(); // String pathSeparator = "/"; // // //String pathSeparator = ws.getPathSeparator(); // // WorkspaceItem initialItem = workspace.getItem(workspaceFolderId); // String fullPathBase = initialItem.getPath(); // fullPathBase = fullPathBase.endsWith(pathSeparator) ? fullPathBase : fullPathBase + pathSeparator; // rootElem.setFolder(initialItem.isFolder()); // rootElem.setFullPath(initialItem.getPath().replace(fullPathBase, "")); // rootElem.setName(initialItem.getName()); // rootElem.setOriginalIdInWorkspace(initialItem.getId()); // rootElem.setDescription(initialItem.getDescription()); // extractEditableNameFromPath(rootElem, pathSeparator); // // // recursive visiting //// if(initialItem.isFolder()) //// visit(rootElem, initialItem, workspace, fullPathBase, pathSeparator); // // logger.debug("Tree that is going to be returned is " + rootElem); // return rootElem; // } // /** // * Recursive visit of a workspace item. // * // * @param parent the parent // * @param initialItemWS the initial item WS // * @param workspace the ws // * @param fullPathBase the full path base // * @param pathSeparator the path separator // * @throws Exception the exception // */ // private static void visit(ResourceElementBean parent, WorkspaceItem initialItemWS, Workspace workspace, String fullPathBase, String pathSeparator) throws Exception { // //List children = initialItemWS.getChildren(); // // List children = workspace.getChildren(initialItemWS.getId()); // // ArrayList childrenInTree = new ArrayList(children.size()); // for (WorkspaceItem item : children) { // // logger.debug("Path BEFORE REPLACE is " + item.getPath()); // // logger.debug("Path AFTER REPLACE is " + item.getPath().replace(fullPathBase, "")); // // logger.debug("Name is " + item.getName()); // // logger.debug("id is " + item.getId()); // ResourceElementBean elem = new ResourceElementBean(); // elem.setFolder(item.isFolder()); // elem.setOriginalIdInWorkspace(item.getId()); // elem.setFullPath(item.getPath().replace(fullPathBase, "")); // elem.setParent(parent); // elem.setName(item.getName()); // elem.setDescription(item.getDescription()); // extractEditableNameFromPath(elem, pathSeparator); // childrenInTree.add(elem); // logger.trace("Elem is " + elem); // if(item.isFolder()) // visit(elem, item, workspace, fullPathBase, pathSeparator); // } // // add these list as child of the rootElem // parent.setChildren(childrenInTree); // } // /** // * Replaces the "/" char with a custom one and return an editable name for the user. // * // * @param rootElem the root elem // * @param pathSeparatorInWs the path separator in ws // */ // public static void extractEditableNameFromPath(ResourceElementBean rootElem, String pathSeparatorInWs) { // // if(rootElem == null) // return; // // String elemName = rootElem.getName(); // String fullPath = rootElem.getFullPath(); // logger.info("Element original is " + rootElem); // // int lastIndex = rootElem.getFullPath().lastIndexOf(elemName); // fullPath = rootElem.getFullPath().substring(0, lastIndex); // fullPath = fullPath.replaceAll(pathSeparatorInWs, RESOURCES_NAME_SEPARATOR) + elemName; // rootElem.setEditableName(fullPath); // logger.info("Editable name for resource name: "+rootElem.getName()+", is: " + rootElem.getEditableName()); // } /** * Copy into the .catalogue area folder the checked resources. * There is no difference among a single-file-publish and a folder-publish. * * @param bean the bean * @param workspace the workspace * @param username the username * @return the list * @throws Exception the exception */ public static List toResources(DatasetBean bean, Workspace workspace, String username) throws Exception{ logger.debug("Called to Resources...: "); List resources = new ArrayList(); ResourceElementBean rootResource = bean.getResourceRoot(); if(rootResource==null) { logger.info("No resource root, returning empty list of resources"); return resources; } // retrieve the children List resourcesToAdd = rootResource.getToPublish(); if(resourcesToAdd==null) { logger.info("No resource to add, returning empty list of resources"); return resources; } // copy only the selected ones for(ResourceElementBean resource : resourcesToAdd){ if (resource.isToBeAdded()) { logger.debug("Resource to add is " + resource); // ok it is a file, so copy it into the copiedFolder WorkspaceItem wsItem = workspace.getItem(resource.getOriginalIdInWorkspace()); String mimeType = null; if(wsItem instanceof FileItem) { mimeType = ((FileItem)wsItem).getMimeType(); } // check if it is an URLFile String externalUrl = null; try{ if(wsItem instanceof URLFile) { URLFile urlFile = (URLFile) wsItem; externalUrl = urlFile.getValue()!=null?urlFile.getValue().toString():null; } }catch(Exception e){ logger.warn("Unable to check if it is an external url file ", e); } String resourceURL = externalUrl; //it is not a URLFile if(resourceURL==null) { //getting public link of file URL publicLink = workspace.getPublicLinkForFile(resource.getOriginalIdInWorkspace()); if(publicLink!=null) resourceURL = publicLink.toString(); } resources.add(new ResourceBean(resourceURL, resource.getEditableName(), resource.getDescription(), wsItem.getId(), username, null, // dataset id, to be set mimeType)); } } return resources; } // //MOVED TO GCAT // /** // * Copy into the .catalogue area folder the checked resources. // * There is no difference among a single-file-publish and a folder-publish. // * @param folderId // * @param userName // * @param bean // * @return // */ // public static List copyResourcesToUserCatalogueArea(String folderOrFileId, String userName, DatasetBean bean) throws Exception{ // // logger.debug("Request to copy onto catalogue area...."); // List resources = new ArrayList(); // WorkspaceItem copiedFolder = null; // WorkspaceCatalogue userCatalogue = null; // ResourceElementBean rootResource = bean.getResourceRoot(); // // // into the .catalogue area of the user's workspace // Workspace ws = HomeLibrary // .getHomeManagerFactory() // .getHomeManager() // .getHome() // .getWorkspace(); // // // Retrieve the catalogue of the user // userCatalogue = ws.getCatalogue(); // // // get workspace item (it could be a file or a folder) // WorkspaceItem originalItem = ws.getItem(folderOrFileId); // // // copy the folder in the catalogue if it is a folder, or create a new folder // long referenceTime = System.currentTimeMillis(); // if(originalItem.isFolder()){ // copiedFolder = userCatalogue.addWorkspaceItem(folderOrFileId, userCatalogue.getId()); // add to .catalogue root area // copiedFolder.setDescription(bean.getDescription()); // ((WorkspaceFolder)copiedFolder).rename(CatalogueUtilMethods.fromProductTitleToName(bean.getTitle()) + "_" + referenceTime); // } // else{ // copiedFolder = userCatalogue.createFolder(CatalogueUtilMethods.fromProductTitleToName(bean.getTitle()) + "_" + referenceTime, bean.getDescription()); // } // // // retrieve the children // List resourcesToAdd = rootResource.getChildren(); // // // copy only the selected ones // for(ResourceElementBean resource : resourcesToAdd){ // // if (resource.isToBeAdded()) { // // logger.debug("Resource to add is " + resource); // // // ok it is a file, so copy it into the copiedFolder // WorkspaceItem copiedFile = userCatalogue.addWorkspaceItem(resource.getOriginalIdInWorkspace(), copiedFolder.getId()); // // // name and description could have been edited // copiedFile.setDescription(resource.getDescription()); // // // check if it is an external url // String externalUrl = null; // try{ // boolean isExternalUrl = ((FolderItem)copiedFile).getFolderItemType().equals(FolderItemType.EXTERNAL_URL); // externalUrl = isExternalUrl ? ((ExternalUrl)copiedFile).getUrl() : null; // }catch(Exception e){ // logger.warn("Unable to check if it is an external url file ", e); // } // // resources.add(new ResourceBean( // externalUrl != null ? externalUrl : copiedFile.getPublicLink(true), // resource.getEditableName(), // copiedFile.getDescription(), // copiedFile.getId(), // userName, // null, // dataset id, to be set // ((FolderItem)copiedFile).getMimeType())); // // // postpone rename operation // copiedFile.rename(resource.getEditableName()); // } // // } // return resources; // } }