From 2aadb9cce77c25e76b6c9e22806b4365187bef3f Mon Sep 17 00:00:00 2001 From: "lucio.lelii" Date: Tue, 4 May 2021 11:42:02 +0200 Subject: [PATCH] - External Folder imporvements - Inbox and Outbox creation --- .classpath | 1 + .settings/org.eclipse.wst.common.component | 47 +- pom.xml | 7 - .../data/access/storagehub/Constants.java | 6 + .../data/access/storagehub/PathUtil.java | 8 + .../data/access/storagehub/StorageHub.java | 2 + .../gcube/data/access/storagehub/Utils.java | 119 +---- .../storagehub/handlers/ClassHandler.java | 19 +- .../storagehub/handlers/CompressHandler.java | 101 +++++ .../handlers/StorageBackendHandler.java | 59 --- .../storagehub/handlers/TrashHandler.java | 53 ++- .../storagehub/handlers/VersionHandler.java | 11 +- .../handlers/items/Item2NodeConverter.java | 3 +- .../handlers/items/ItemHandler.java | 69 +-- .../handlers/items/Node2ItemConverter.java | 108 +++-- .../plugins/ExternalFolderPluginHandler.java | 29 -- .../handlers/plugins/FolderPluginHandler.java | 80 ++++ .../handlers/plugins/OperationMediator.java | 28 ++ .../storagehub/services/ItemSharing.java | 1 + .../storagehub/services/ItemsManager.java | 75 +++- .../storagehub/services/MessageManager.java | 413 ++++++++++++++++++ .../storagehub/services/UserManager.java | 10 +- .../storagehub/services/WorkspaceManager.java | 14 +- .../impl/GCubeFolderManagerConnector.java | 22 + .../backend/impl/GCubeStorageBackend.java | 39 +- .../backend/impl/GcubeFolderManager.java | 48 ++ .../storagehub/types/MessageSharable.java | 16 + src/main/webapp/WEB-INF/README | 2 +- 28 files changed, 1035 insertions(+), 355 deletions(-) create mode 100644 src/main/java/org/gcube/data/access/storagehub/handlers/CompressHandler.java delete mode 100644 src/main/java/org/gcube/data/access/storagehub/handlers/StorageBackendHandler.java delete mode 100644 src/main/java/org/gcube/data/access/storagehub/handlers/plugins/ExternalFolderPluginHandler.java create mode 100644 src/main/java/org/gcube/data/access/storagehub/handlers/plugins/FolderPluginHandler.java create mode 100644 src/main/java/org/gcube/data/access/storagehub/handlers/plugins/OperationMediator.java create mode 100644 src/main/java/org/gcube/data/access/storagehub/services/MessageManager.java create mode 100644 src/main/java/org/gcube/data/access/storagehub/storage/backend/impl/GCubeFolderManagerConnector.java create mode 100644 src/main/java/org/gcube/data/access/storagehub/storage/backend/impl/GcubeFolderManager.java create mode 100644 src/main/java/org/gcube/data/access/storagehub/types/MessageSharable.java diff --git a/.classpath b/.classpath index 298646d..0a99827 100644 --- a/.classpath +++ b/.classpath @@ -35,5 +35,6 @@ + diff --git a/.settings/org.eclipse.wst.common.component b/.settings/org.eclipse.wst.common.component index f70b3ad..8a1486b 100644 --- a/.settings/org.eclipse.wst.common.component +++ b/.settings/org.eclipse.wst.common.component @@ -1,5 +1,8 @@ - + + + + @@ -19,7 +22,10 @@ - + + + + @@ -39,7 +45,10 @@ - + + + + @@ -59,7 +68,10 @@ - + + + + @@ -79,7 +91,10 @@ - + + + + @@ -99,13 +114,16 @@ - + uses uses - + + + + @@ -125,7 +143,10 @@ - + + + + @@ -145,7 +166,10 @@ - + + + + @@ -165,7 +189,10 @@ - + + + + diff --git a/pom.xml b/pom.xml index 2f12a76..cccba25 100644 --- a/pom.xml +++ b/pom.xml @@ -273,13 +273,6 @@ 3.0.1 - - com.fasterxml.jackson.jaxrs - jackson-jaxrs-json-provider - 2.3.0 - - - org.glassfish.jersey.core diff --git a/src/main/java/org/gcube/data/access/storagehub/Constants.java b/src/main/java/org/gcube/data/access/storagehub/Constants.java index 99200e7..1b7515e 100644 --- a/src/main/java/org/gcube/data/access/storagehub/Constants.java +++ b/src/main/java/org/gcube/data/access/storagehub/Constants.java @@ -9,6 +9,12 @@ public class Constants { public static final String PERSONAL_VRES_FOLDER_PARENT_NAME = "VREs"; + public static final String INBOX_FOLDER_NAME = "InBox"; + + public static final String OUTBOX_FOLDER_NAME = "OutBox"; + + public static final String ATTACHMENTNODE_NAME = "hl:attachments"; + public static final String SHARED_WITH_ME_PARENT_NAME = "SharedWithMe"; public static final String SHARED_FOLDER_PATH = "/Share"; diff --git a/src/main/java/org/gcube/data/access/storagehub/PathUtil.java b/src/main/java/org/gcube/data/access/storagehub/PathUtil.java index c6bd6c7..2310273 100644 --- a/src/main/java/org/gcube/data/access/storagehub/PathUtil.java +++ b/src/main/java/org/gcube/data/access/storagehub/PathUtil.java @@ -19,6 +19,14 @@ public class PathUtil { return Paths.getPath(String.format("/Home/%s",login)); } + public Path getInboxPath(String login) { + return Paths.append(getHome(login),Constants.INBOX_FOLDER_NAME); + } + + public Path getOutboxPath(String login) { + return Paths.append(getHome(login),Constants.OUTBOX_FOLDER_NAME); + } + @Deprecated private Path getOldTrashPath(String login){ return Paths.append(getWorkspacePath(login),Constants.TRASH_ROOT_FOLDER_NAME); diff --git a/src/main/java/org/gcube/data/access/storagehub/StorageHub.java b/src/main/java/org/gcube/data/access/storagehub/StorageHub.java index 9dbeeb3..fcda7e9 100644 --- a/src/main/java/org/gcube/data/access/storagehub/StorageHub.java +++ b/src/main/java/org/gcube/data/access/storagehub/StorageHub.java @@ -13,6 +13,7 @@ import org.gcube.data.access.storagehub.services.Impersonable; import org.gcube.data.access.storagehub.services.ItemSharing; import org.gcube.data.access.storagehub.services.ItemsCreator; import org.gcube.data.access.storagehub.services.ItemsManager; +import org.gcube.data.access.storagehub.services.MessageManager; import org.gcube.data.access.storagehub.services.UserManager; import org.gcube.data.access.storagehub.services.WorkspaceManager; import org.gcube.data.access.storagehub.services.admin.ScriptManager; @@ -34,6 +35,7 @@ public class StorageHub extends Application { classes.add(UserManager.class); classes.add(GroupManager.class); classes.add(ScriptManager.class); + classes.add(MessageManager.class); classes.add(MultiPartFeature.class); classes.add(SerializableErrorEntityTextWriter.class); classes.add(MyApplicationListener.class); diff --git a/src/main/java/org/gcube/data/access/storagehub/Utils.java b/src/main/java/org/gcube/data/access/storagehub/Utils.java index c137ec4..546bfb3 100644 --- a/src/main/java/org/gcube/data/access/storagehub/Utils.java +++ b/src/main/java/org/gcube/data/access/storagehub/Utils.java @@ -1,6 +1,5 @@ package org.gcube.data.access.storagehub; -import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -8,14 +7,11 @@ import java.net.URL; import java.security.MessageDigest; import java.util.ArrayList; import java.util.Calendar; -import java.util.Deque; import java.util.HashSet; -import java.util.LinkedList; import java.util.List; import java.util.Set; import java.util.function.Predicate; -import java.util.zip.ZipEntry; -import java.util.zip.ZipOutputStream; + import javax.jcr.Node; import javax.jcr.NodeIterator; import javax.jcr.PathNotFoundException; @@ -24,28 +20,25 @@ import javax.jcr.Session; import javax.jcr.lock.Lock; import javax.jcr.lock.LockException; import javax.jcr.query.Query; -import javax.jcr.version.Version; + import org.apache.commons.io.FilenameUtils; import org.apache.jackrabbit.util.ISO9075; import org.apache.jackrabbit.util.Text; import org.gcube.common.storagehub.model.Excludes; -import org.gcube.common.storagehub.model.Paths; import org.gcube.common.storagehub.model.exceptions.BackendGenericError; import org.gcube.common.storagehub.model.exceptions.IdNotFoundException; import org.gcube.common.storagehub.model.exceptions.ItemLockedException; import org.gcube.common.storagehub.model.exceptions.StorageHubException; import org.gcube.common.storagehub.model.exceptions.UserNotAuthorizedException; -import org.gcube.common.storagehub.model.items.AbstractFileItem; import org.gcube.common.storagehub.model.items.ExternalLink; import org.gcube.common.storagehub.model.items.FolderItem; import org.gcube.common.storagehub.model.items.GCubeItem; import org.gcube.common.storagehub.model.items.Item; +import org.gcube.common.storagehub.model.items.RootItem; import org.gcube.common.storagehub.model.items.SharedFolder; import org.gcube.common.storagehub.model.types.ItemAction; import org.gcube.common.storagehub.model.types.NodeProperty; import org.gcube.data.access.storagehub.accounting.AccountingHandler; -import org.gcube.data.access.storagehub.handlers.StorageBackendHandler; -import org.gcube.data.access.storagehub.handlers.VersionHandler; import org.gcube.data.access.storagehub.handlers.items.Item2NodeConverter; import org.gcube.data.access.storagehub.handlers.items.Node2ItemConverter; import org.gcube.data.access.storagehub.handlers.items.builders.FolderCreationParameters; @@ -79,7 +72,7 @@ public class Utils { return digest; } - public static long getItemCount(Node parent, boolean showHidden, Class nodeType) throws RepositoryException, BackendGenericError{ + public static long getItemCount(Node parent, boolean showHidden, Class nodeType) throws RepositoryException, BackendGenericError{ return getItemList(parent, Excludes.ALL, null, showHidden, nodeType).size(); } @@ -108,12 +101,13 @@ public class Utils { } - public static List serachByNameOnFolder(Session ses, String user, AuthorizationChecker authChecker, Node parent, List excludes, Range range, boolean showHidden, boolean excludeTrashed, Class nodeTypeToInclude, String nameParam) throws RepositoryException, BackendGenericError{ + public static List serachByNameOnFolder(Session ses, String user, AuthorizationChecker authChecker, Node parent, List excludes, Range range, boolean showHidden, boolean excludeTrashed, Class nodeTypeToInclude, String nameParam) throws RepositoryException, BackendGenericError{ String xpath = String.format("/jcr:root%s//element(*,nthl:workspaceItem)[jcr:like(fn:lower-case(@jcr:title), '%s')]",ISO9075.encodePath(parent.getPath()), nameParam.toLowerCase()); //String query = String.format("SELECT * FROM [nthl:workspaceLeafItem] AS node WHERE ISDESCENDANTNODE('%s') ORDER BY node.[jcr:lastModified] DESC ",vreFolder.getPath()); logger.debug("query for search is {}",xpath); long start = System.currentTimeMillis(); + @SuppressWarnings("deprecation") Query jcrQuery = ses.getWorkspace().getQueryManager().createQuery(xpath, Query.XPATH); NodeChildrenFilterIterator iterator = new NodeChildrenFilterIterator(jcrQuery.execute().getNodes()); logger.debug("[SEARCH] real search took {} millis",(System.currentTimeMillis()-start)); @@ -135,11 +129,11 @@ public class Utils { } - public static List getItemList(Node parent, List excludes, Range range, boolean showHidden, Class nodeTypeToInclude) throws RepositoryException, BackendGenericError{ + public static List getItemList(Node parent, List excludes, Range range, boolean showHidden, Class nodeTypeToInclude) throws RepositoryException, BackendGenericError{ return getItemList(null, parent, excludes, range, showHidden, nodeTypeToInclude); } - public static List getItemList(Predicate checker, Node parent, List excludes, Range range, boolean showHidden, Class nodeTypeToInclude) throws RepositoryException, BackendGenericError{ + public static List getItemList(Predicate checker, Node parent, List excludes, Range range, boolean showHidden, Class nodeTypeToInclude) throws RepositoryException, BackendGenericError{ logger.trace("getting children of node {}", parent.getIdentifier()); long start = System.currentTimeMillis(); NodeChildrenFilterIterator iterator = new NodeChildrenFilterIterator(parent); @@ -147,7 +141,7 @@ public class Utils { return getItemListFromNodeIterator(checker, iterator, excludes, range, showHidden, false, nodeTypeToInclude); } - private static List getItemListFromNodeIterator(Predicate checker, NodeChildrenFilterIterator iterator, List excludes, Range range, boolean showHidden, boolean excludeTrashed, Class nodeTypeToInclude) throws RepositoryException, BackendGenericError{ + private static List getItemListFromNodeIterator(Predicate checker, NodeChildrenFilterIterator iterator, List excludes, Range range, boolean showHidden, boolean excludeTrashed, Class nodeTypeToInclude) throws RepositoryException, BackendGenericError{ List returnList = new ArrayList(); logger.trace("nodeType is {}",nodeTypeToInclude); @@ -194,71 +188,9 @@ public class Utils { } - public static Deque getAllNodesForZip(FolderItem directory, Session session, String login, AccountingHandler accountingHandler, List excludes) throws RepositoryException, BackendGenericError{ - Deque queue = new LinkedList(); - Node currentNode = session.getNodeByIdentifier(directory.getId()); - queue.push(directory); - Deque tempQueue = new LinkedList(); - logger.trace("adding directory {}",currentNode.getPath()); - for (Item item : Utils.getItemList(currentNode,Excludes.GET_ONLY_CONTENT, null, false, null)){ - if (excludes.contains(item.getId())) continue; - if (item instanceof FolderItem) - tempQueue.addAll(getAllNodesForZip((FolderItem) item, session, login, accountingHandler, excludes)); - else if (item instanceof AbstractFileItem){ - logger.trace("adding file {}",item.getPath()); - AbstractFileItem fileItem = (AbstractFileItem) item; - accountingHandler.createReadObj(fileItem.getTitle(), session, session.getNodeByIdentifier(item.getId()), login, false); - queue.addLast(item); - } - } - queue.addAll(tempQueue); - return queue; - } - - - public static void zipNode(ZipOutputStream zos, Deque queue, String login, org.gcube.common.storagehub.model.Path originalPath, StorageBackendHandler storageHandler) throws Exception{ - logger.trace("originalPath is {}",originalPath.toPath()); - org.gcube.common.storagehub.model.Path actualPath = Paths.getPath(""); - while (!queue.isEmpty()) { - Item item = queue.pop(); - if (item instanceof FolderItem) { - actualPath = Paths.getPath(item.getPath()); - logger.trace("actualPath is {}",actualPath.toPath()); - String name = Paths.remove(actualPath, originalPath).toPath().replaceFirst("/", ""); - logger.trace("writing dir {}",name); - if (name.isEmpty()) continue; - try { - zos.putNextEntry(new ZipEntry(name)); - }finally { - zos.closeEntry(); - } - } else if (item instanceof AbstractFileItem){ - try { - InputStream streamToWrite = storageHandler.download(((AbstractFileItem)item).getContent().getStorageId()); - if (streamToWrite == null){ - logger.warn("discarding item {} ",item.getName()); - continue; - } - try(BufferedInputStream is = new BufferedInputStream(streamToWrite)){ - String name = (Paths.remove(actualPath, originalPath).toPath()+item.getName()).replaceFirst("/", ""); - logger.trace("writing file {}",name); - zos.putNextEntry(new ZipEntry(name)); - copyStream(is, zos); - }catch (Exception e) { - logger.warn("error writing item {}", item.getName(),e); - } finally{ - zos.closeEntry(); - } - zos.flush(); - }catch (Throwable e) { - logger.warn("error reading content for item {}", item.getPath(),e); - } - } - } - zos.close(); - } + - private static void copyStream(InputStream in, OutputStream out) throws IOException { + public static void copyStream(InputStream in, OutputStream out) throws IOException { byte[] buffer = new byte[2048]; int readcount = 0; while ((readcount=in.read(buffer))!=-1) { @@ -279,34 +211,7 @@ public class Utils { return false; } - public static void getAllContentIds(Session ses, Set idsToDelete, Item itemToDelete, VersionHandler versionHandler) throws Exception{ - if (itemToDelete instanceof AbstractFileItem) { - Node currentNode = ses.getNodeByIdentifier(itemToDelete.getId()); - List versions = versionHandler.getContentVersionHistory(currentNode, ses); - - versions.forEach(v -> { - try { - String storageId =v.getFrozenNode().getProperty(NodeProperty.STORAGE_ID.toString()).getString(); - idsToDelete.add(storageId); - logger.info("retrieved StorageId {} for version {}", storageId, v.getName()); - } catch (Exception e) { - logger.warn("error retreiving sotrageId version for item with id {}",itemToDelete.getId(),e); - } - }); - - - idsToDelete.add(((AbstractFileItem) itemToDelete).getContent().getStorageId()); - }else if (itemToDelete instanceof FolderItem) { - //only to be sure to not delete shared content - if (itemToDelete.isShared()) return; - List items = Utils.getItemList(ses.getNodeByIdentifier(itemToDelete.getId()), Excludes.GET_ONLY_CONTENT , null, true, null); - for (Item item: items) - getAllContentIds(ses, idsToDelete, item, versionHandler); - - } - - } - + public static String checkExistanceAndGetUniqueName(Session ses, Node destination, String name) throws BackendGenericError{ try { destination.getNode(name); diff --git a/src/main/java/org/gcube/data/access/storagehub/handlers/ClassHandler.java b/src/main/java/org/gcube/data/access/storagehub/handlers/ClassHandler.java index 31a9f08..21e83d2 100644 --- a/src/main/java/org/gcube/data/access/storagehub/handlers/ClassHandler.java +++ b/src/main/java/org/gcube/data/access/storagehub/handlers/ClassHandler.java @@ -7,7 +7,7 @@ import java.util.Map; import java.util.Set; import org.gcube.common.storagehub.model.annotations.RootNode; -import org.gcube.common.storagehub.model.items.Item; +import org.gcube.common.storagehub.model.items.RootItem; import org.reflections.Reflections; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -30,32 +30,33 @@ public class ClassHandler { "nthl:workflowTemplate", "nthl:gCubeMetadata", "nthl:gCubeDocument", "nthl:gCubeDocumentLink", "nthl:gCubeImageDocumentLink", "nthl:gCubePDFDocumentLink", "nthl:gCubeImageDocument", "nthl:gCubePDFDocument", "nthl:gCubeURLDocument", "nthl:gCubeAnnotation", "nthl:externalResourceLink", "nthl:tabularDataLink"); - private Map> classMap = new HashMap>(); - private Map, String> typeMap = new HashMap, String>(); + private Map> classMap = new HashMap>(); + private Map, String> typeMap = new HashMap, String>(); + @SuppressWarnings("unchecked") private ClassHandler() { Set> classesAnnotated = reflection.getTypesAnnotatedWith(RootNode.class); for (Class clazz: classesAnnotated ){ - if (Item.class.isAssignableFrom(clazz)) { + if (RootItem.class.isAssignableFrom(clazz)) { String value = clazz.getAnnotation(RootNode.class).value(); log.debug("loading class {} with value {} ", clazz, value ); - classMap.put(value, (Class) clazz); - typeMap.put((Class) clazz, value); + classMap.put(value, (Class) clazz); + typeMap.put((Class) clazz, value); } } } - public Class get(String nodeType){ + public Class get(String nodeType){ if (classMap.containsKey(nodeType)) return classMap.get(nodeType); - if (deprecatedNode.contains(nodeType)) return Item.class; + if (deprecatedNode.contains(nodeType)) return RootItem.class; return null; //throw new RuntimeException("mapping not found for nodetype "+ nodeType); } - public String getNodeType(Class clazz){ + public String getNodeType(Class clazz){ if (typeMap.containsKey(clazz)) return typeMap.get(clazz); throw new RuntimeException("mapping not found for nodetype "+ clazz.getSimpleName()); } diff --git a/src/main/java/org/gcube/data/access/storagehub/handlers/CompressHandler.java b/src/main/java/org/gcube/data/access/storagehub/handlers/CompressHandler.java new file mode 100644 index 0000000..ed22043 --- /dev/null +++ b/src/main/java/org/gcube/data/access/storagehub/handlers/CompressHandler.java @@ -0,0 +1,101 @@ +package org.gcube.data.access.storagehub.handlers; + +import java.io.BufferedInputStream; +import java.io.InputStream; +import java.util.Deque; +import java.util.LinkedList; +import java.util.List; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +import javax.inject.Inject; +import javax.jcr.Node; +import javax.jcr.RepositoryException; +import javax.jcr.Session; + +import org.gcube.common.storagehub.model.Excludes; +import org.gcube.common.storagehub.model.Paths; +import org.gcube.common.storagehub.model.exceptions.BackendGenericError; +import org.gcube.common.storagehub.model.items.AbstractFileItem; +import org.gcube.common.storagehub.model.items.FolderItem; +import org.gcube.common.storagehub.model.items.Item; +import org.gcube.common.storagehub.model.plugins.FolderManager; +import org.gcube.data.access.storagehub.Utils; +import org.gcube.data.access.storagehub.accounting.AccountingHandler; +import org.gcube.data.access.storagehub.handlers.plugins.FolderPluginHandler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class CompressHandler { + + private Logger logger = LoggerFactory.getLogger(CompressHandler.class); + + @Inject + FolderPluginHandler pluginHandler; + + public Deque getAllNodesForZip(FolderItem directory, Session session, String login, AccountingHandler accountingHandler, List excludes) throws RepositoryException, BackendGenericError{ + Deque queue = new LinkedList(); + Node currentNode = session.getNodeByIdentifier(directory.getId()); + queue.push(directory); + Deque tempQueue = new LinkedList(); + logger.trace("adding directory {}",currentNode.getPath()); + for (Item item : Utils.getItemList(currentNode,Excludes.GET_ONLY_CONTENT, null, false, null)){ + if (excludes.contains(item.getId())) continue; + if (item instanceof FolderItem) + tempQueue.addAll(getAllNodesForZip((FolderItem) item, session, login, accountingHandler, excludes)); + else if (item instanceof AbstractFileItem){ + logger.trace("adding file {}",item.getPath()); + AbstractFileItem fileItem = (AbstractFileItem) item; + accountingHandler.createReadObj(fileItem.getTitle(), session, session.getNodeByIdentifier(item.getId()), login, false); + queue.addLast(item); + } + } + queue.addAll(tempQueue); + return queue; + } + + + public void zipNode(ZipOutputStream zos, Deque queue, String login, org.gcube.common.storagehub.model.Path originalPath) throws Exception{ + logger.trace("originalPath is {}",originalPath.toPath()); + org.gcube.common.storagehub.model.Path actualPath = Paths.getPath(""); + while (!queue.isEmpty()) { + Item item = queue.pop(); + if (item instanceof FolderItem) { + actualPath = Paths.getPath(item.getPath()); + logger.trace("actualPath is {}",actualPath.toPath()); + String name = Paths.remove(actualPath, originalPath).toPath().replaceFirst("/", ""); + logger.trace("writing dir {}",name); + if (name.isEmpty()) continue; + try { + zos.putNextEntry(new ZipEntry(name)); + }finally { + zos.closeEntry(); + } + } else if (item instanceof AbstractFileItem){ + try { + AbstractFileItem fileItem = (AbstractFileItem)item; + FolderManager manager = pluginHandler.getFolderManager(fileItem); + InputStream streamToWrite = manager.getStorageBackend().download(fileItem.getContent()); + if (streamToWrite == null){ + logger.warn("discarding item {} ",item.getName()); + continue; + } + try(BufferedInputStream is = new BufferedInputStream(streamToWrite)){ + String name = (Paths.remove(actualPath, originalPath).toPath()+item.getName()).replaceFirst("/", ""); + logger.trace("writing file {}",name); + zos.putNextEntry(new ZipEntry(name)); + Utils.copyStream(is, zos); + }catch (Exception e) { + logger.warn("error writing item {}", item.getName(),e); + } finally{ + zos.closeEntry(); + } + zos.flush(); + }catch (Throwable e) { + logger.warn("error reading content for item {}", item.getPath(),e); + } + } + } + zos.close(); + } +} diff --git a/src/main/java/org/gcube/data/access/storagehub/handlers/StorageBackendHandler.java b/src/main/java/org/gcube/data/access/storagehub/handlers/StorageBackendHandler.java deleted file mode 100644 index cf7e34d..0000000 --- a/src/main/java/org/gcube/data/access/storagehub/handlers/StorageBackendHandler.java +++ /dev/null @@ -1,59 +0,0 @@ -package org.gcube.data.access.storagehub.handlers; - -import java.io.InputStream; - -import javax.enterprise.inject.Any; -import javax.enterprise.inject.Instance; -import javax.inject.Inject; -import javax.inject.Singleton; - -import org.gcube.common.storagehub.model.items.AbstractFileItem; -import org.gcube.common.storagehub.model.items.FolderItem; -import org.gcube.common.storagehub.model.items.Item; -import org.gcube.common.storagehub.model.storages.MetaInfo; -import org.gcube.common.storagehub.model.storages.StorageBackend; -import org.gcube.common.storagehub.model.storages.StorageBackendFactory; -import org.gcube.data.access.storagehub.storage.backend.impl.GCubeStorageBackend; - - -@Singleton -public class StorageBackendHandler { - - @Inject - @Any - private Instance> backends; - - @Inject - private GCubeStorageBackend defaultBackend; - - - public String move(Item item, FolderItem destination) { - //if item is a folder we have to move everything - return defaultBackend.move(((AbstractFileItem) item).getContent().getStorageId()); - } - - public String copy(AbstractFileItem item) { - return defaultBackend.copy(item.getContent().getStorageId(), item.getContent().getRemotePath()); - } - - public MetaInfo upload(InputStream stream, String itemPath) { - return defaultBackend.upload(stream, itemPath); - } - - public InputStream download(String id) { - return defaultBackend.getContent(id); - } - - public void delete(String id) { - defaultBackend.delete(id); - } - - public String getTotalVolume() { - return defaultBackend.getTotalSizeStored(); - } - - public String getTotalItemsCount() { - return defaultBackend.getTotalItemsCount(); - } - -} diff --git a/src/main/java/org/gcube/data/access/storagehub/handlers/TrashHandler.java b/src/main/java/org/gcube/data/access/storagehub/handlers/TrashHandler.java index fbea1ed..09de47b 100644 --- a/src/main/java/org/gcube/data/access/storagehub/handlers/TrashHandler.java +++ b/src/main/java/org/gcube/data/access/storagehub/handlers/TrashHandler.java @@ -6,6 +6,7 @@ import java.util.List; import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.stream.Collectors; import javax.inject.Inject; import javax.inject.Singleton; @@ -14,6 +15,7 @@ import javax.jcr.Node; import javax.jcr.RepositoryException; import javax.jcr.Session; import javax.jcr.lock.LockException; +import javax.jcr.version.Version; import org.gcube.common.authorization.library.AuthorizedTasks; import org.gcube.common.storagehub.model.Excludes; @@ -26,6 +28,8 @@ import org.gcube.common.storagehub.model.items.AbstractFileItem; import org.gcube.common.storagehub.model.items.FolderItem; import org.gcube.common.storagehub.model.items.Item; import org.gcube.common.storagehub.model.items.TrashItem; +import org.gcube.common.storagehub.model.items.nodes.Content; +import org.gcube.common.storagehub.model.plugins.FolderManager; import org.gcube.common.storagehub.model.types.ItemAction; import org.gcube.data.access.storagehub.AuthorizationChecker; import org.gcube.data.access.storagehub.PathUtil; @@ -33,6 +37,7 @@ import org.gcube.data.access.storagehub.Utils; import org.gcube.data.access.storagehub.accounting.AccountingHandler; import org.gcube.data.access.storagehub.handlers.items.Item2NodeConverter; import org.gcube.data.access.storagehub.handlers.items.Node2ItemConverter; +import org.gcube.data.access.storagehub.handlers.plugins.FolderPluginHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -61,8 +66,10 @@ public class TrashHandler { @Inject PathUtil pathUtil; + @Inject FolderPluginHandler managerHandler; + @Inject - StorageBackendHandler storageHandler; + FolderPluginHandler folderHandler; public void removeNodes(Session ses, List itemsToDelete) throws RepositoryException, StorageHubException{ log.debug("defnitively removing nodes with ids {}",itemsToDelete); @@ -78,34 +85,55 @@ public class TrashHandler { } } + private void retrieveContentsToDelete(Set itemsToDelete, Item itemToDelete) throws Exception{ + if (itemToDelete instanceof AbstractFileItem) { + itemsToDelete.add(((AbstractFileItem) itemToDelete)); + }else if (itemToDelete instanceof FolderItem) { + //only to be sure to not delete shared content + if (itemToDelete.isShared()) return; + + List items = Utils.getItemList((Node) itemToDelete, Excludes.GET_ONLY_CONTENT , null, true, null); + for (Item item: items) + retrieveContentsToDelete(itemsToDelete, item); + } + } + + private void removeNodesInternally(Session ses, Item itemToDelete, boolean onlyContent) throws RepositoryException, StorageHubException { try { - Set contentIdsToDelete = new HashSet<>(); - + Set itemsToDelete = new HashSet<>(); Node nodeToDelete = ses.getNodeByIdentifier(itemToDelete.getId()); if (itemToDelete instanceof TrashItem) { List trashChildren = Utils.getItemList(nodeToDelete, Excludes.GET_ONLY_CONTENT, null, true, null); for (Item itemContentToRetrieve: trashChildren) - Utils.getAllContentIds(ses, contentIdsToDelete, itemContentToRetrieve, versionHandler); - } else { - Utils.getAllContentIds(ses, contentIdsToDelete, itemToDelete, versionHandler); - } + retrieveContentsToDelete(itemsToDelete, itemContentToRetrieve); + } else + retrieveContentsToDelete(itemsToDelete, itemToDelete); + if (!onlyContent) nodeToDelete.remove(); - log.debug("content ids to remove are {}",contentIdsToDelete); + String ids = itemsToDelete.stream().map((i) -> i.getId()).collect(Collectors.joining(",")); + log.debug("content ids to remove are {}",ids); Runnable deleteFromStorageRunnable = AuthorizedTasks.bind(new Runnable() { @Override public void run() { - for (String id: contentIdsToDelete) { + for (AbstractFileItem item: itemsToDelete ) { try { - storageHandler.delete(id); - log.debug("file with id {} correctly removed on storage",id); + FolderManager manager = folderHandler.getFolderManager(item); + manager.getStorageBackend().onDelete(item.getContent()); + List versions = versionHandler.getContentVersionHistory((Node)item.getRelatedNode()); + + for (Version version: versions) { + Content content = node2Item.getContent(version); + manager.getStorageBackend().onDelete(content); + } + log.debug("file with id {} correctly removed from storage {}",item.getId(), manager.getClass().getSimpleName()); }catch(Throwable t) { - log.warn("error removing file on storage with id {}",id, t); + log.warn("error removing file with id {} from storage",item.getId(), t); } } } @@ -120,6 +148,7 @@ public class TrashHandler { } } + public void moveToTrash(Session ses, Node nodeToDelete, Item item, String login) throws RepositoryException, BackendGenericError{ log.debug("moving node {} to trash ",item.getId()); diff --git a/src/main/java/org/gcube/data/access/storagehub/handlers/VersionHandler.java b/src/main/java/org/gcube/data/access/storagehub/handlers/VersionHandler.java index d4e0353..5eba029 100644 --- a/src/main/java/org/gcube/data/access/storagehub/handlers/VersionHandler.java +++ b/src/main/java/org/gcube/data/access/storagehub/handlers/VersionHandler.java @@ -22,7 +22,7 @@ public class VersionHandler { private static final Logger logger = LoggerFactory.getLogger(VersionHandler.class); - public void makeVersionableContent(Node node, Session session){ + public void makeVersionableContent(Node node){ try { Node contentNode = node.getNode(NodeConstants.CONTENT_NAME); contentNode.addMixin(JcrConstants.MIX_VERSIONABLE); @@ -31,8 +31,9 @@ public class VersionHandler { } } - public void checkinContentNode(Node node, Session session){ + public void checkinContentNode(Node node){ try { + Session session = node.getSession(); Node contentNode = node.getNode(NodeConstants.CONTENT_NAME); VersionManager versionManager = session.getWorkspace().getVersionManager(); versionManager.checkin(contentNode.getPath()); @@ -41,8 +42,9 @@ public class VersionHandler { } } - public void checkoutContentNode(Node node, Session session){ + public void checkoutContentNode(Node node){ try { + Session session = node.getSession(); Node contentNode = node.getNode(NodeConstants.CONTENT_NAME); VersionManager versionManager = session.getWorkspace().getVersionManager(); versionManager.checkout(contentNode.getPath()); @@ -51,8 +53,9 @@ public class VersionHandler { } } - public List getContentVersionHistory(Node node, Session session) { + public List getContentVersionHistory(Node node) { try { + Session session = node.getSession(); Node contentNode = node.getNode(NodeConstants.CONTENT_NAME); VersionManager versionManager = session.getWorkspace().getVersionManager(); VersionHistory history = versionManager.getVersionHistory(contentNode.getPath()); diff --git a/src/main/java/org/gcube/data/access/storagehub/handlers/items/Item2NodeConverter.java b/src/main/java/org/gcube/data/access/storagehub/handlers/items/Item2NodeConverter.java index a6d6a0b..35bd301 100644 --- a/src/main/java/org/gcube/data/access/storagehub/handlers/items/Item2NodeConverter.java +++ b/src/main/java/org/gcube/data/access/storagehub/handlers/items/Item2NodeConverter.java @@ -35,6 +35,7 @@ import org.gcube.common.storagehub.model.exceptions.BackendGenericError; import org.gcube.common.storagehub.model.items.AbstractFileItem; import org.gcube.common.storagehub.model.items.FolderItem; import org.gcube.common.storagehub.model.items.Item; +import org.gcube.common.storagehub.model.items.RootItem; import org.gcube.common.storagehub.model.types.ItemAction; import org.gcube.common.storagehub.model.types.NodeProperty; import org.gcube.data.access.storagehub.NodeChildrenFilterIterator; @@ -48,7 +49,7 @@ public class Item2NodeConverter { private static final Logger logger = LoggerFactory.getLogger(Item2NodeConverter.class); - public Node getNode(Node parentNode, T item){ + public Node getNode(Node parentNode, T item){ try { String primaryType= ClassHandler.instance().getNodeType(item.getClass()); Node newNode = parentNode.addNode(Text.escapeIllegalJcrChars(item.getName()), primaryType); diff --git a/src/main/java/org/gcube/data/access/storagehub/handlers/items/ItemHandler.java b/src/main/java/org/gcube/data/access/storagehub/handlers/items/ItemHandler.java index e3c9655..07474fd 100644 --- a/src/main/java/org/gcube/data/access/storagehub/handlers/items/ItemHandler.java +++ b/src/main/java/org/gcube/data/access/storagehub/handlers/items/ItemHandler.java @@ -7,20 +7,16 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; -import java.util.UUID; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; - import javax.inject.Inject; import javax.inject.Singleton; import javax.jcr.Node; -import javax.jcr.PathNotFoundException; import javax.jcr.RepositoryException; import javax.jcr.Session; import javax.jcr.lock.LockException; - import org.apache.commons.compress.archivers.ArchiveEntry; import org.apache.commons.compress.archivers.ArchiveInputStream; import org.apache.commons.compress.archivers.ArchiveStreamFactory; @@ -29,24 +25,26 @@ import org.apache.tika.detect.Detector; import org.apache.tika.io.TikaInputStream; import org.apache.tika.metadata.Metadata; import org.gcube.common.authorization.library.AuthorizedTasks; +import org.gcube.common.storagehub.model.Excludes; import org.gcube.common.storagehub.model.NodeConstants; +import org.gcube.common.storagehub.model.Paths; import org.gcube.common.storagehub.model.exceptions.BackendGenericError; import org.gcube.common.storagehub.model.exceptions.IdNotFoundException; import org.gcube.common.storagehub.model.exceptions.InvalidCallParameters; import org.gcube.common.storagehub.model.exceptions.InvalidItemException; import org.gcube.common.storagehub.model.exceptions.ItemLockedException; import org.gcube.common.storagehub.model.exceptions.StorageHubException; -import org.gcube.common.storagehub.model.exceptions.UserNotAuthorizedException; import org.gcube.common.storagehub.model.items.AbstractFileItem; import org.gcube.common.storagehub.model.items.FolderItem; +import org.gcube.common.storagehub.model.plugins.FolderManager; import org.gcube.common.storagehub.model.storages.MetaInfo; +import org.gcube.common.storagehub.model.storages.StorageBackend; import org.gcube.common.storagehub.model.types.ItemAction; import org.gcube.common.storagehub.model.types.NodeProperty; import org.gcube.data.access.storagehub.AuthorizationChecker; import org.gcube.data.access.storagehub.MultipleOutputStream; import org.gcube.data.access.storagehub.Utils; import org.gcube.data.access.storagehub.accounting.AccountingHandler; -import org.gcube.data.access.storagehub.handlers.StorageBackendHandler; import org.gcube.data.access.storagehub.handlers.VersionHandler; import org.gcube.data.access.storagehub.handlers.content.ContentHandler; import org.gcube.data.access.storagehub.handlers.content.ContentHandlerFactory; @@ -56,13 +54,14 @@ import org.gcube.data.access.storagehub.handlers.items.builders.FileCreationPara import org.gcube.data.access.storagehub.handlers.items.builders.FolderCreationParameters; import org.gcube.data.access.storagehub.handlers.items.builders.GCubeItemCreationParameters; import org.gcube.data.access.storagehub.handlers.items.builders.URLCreationParameters; +import org.gcube.data.access.storagehub.handlers.plugins.FolderPluginHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Singleton public class ItemHandler { - + @Inject AccountingHandler accountingHandler; @@ -71,11 +70,12 @@ public class ItemHandler { @Inject AuthorizationChecker authChecker; - + @Inject VersionHandler versionHandler; - @Inject StorageBackendHandler storageBackend; + @Inject + FolderPluginHandler pluginHandler; private static ExecutorService executor = Executors.newFixedThreadPool(100); @@ -142,8 +142,7 @@ public class ItemHandler { private Node create(FileCreationParameters params, Node destination) throws Exception{ Node newNode = createFileItemInternally(params.getSession(), destination, params.getStream(), params.getName(), params.getDescription(), params.getUser(), true); params.getSession().save(); - - versionHandler.checkinContentNode(newNode, params.getSession()); + versionHandler.checkinContentNode(newNode); log.info("file with id {} correctly created",newNode.getIdentifier()); return newNode; } @@ -195,7 +194,7 @@ public class ItemHandler { Node parentNode = directoryNodeMap.get(parentPath); if (parentNode ==null) parentNode = createPath(parentPath, directoryNodeMap, parentDirectoryNode, params.getSession(), params.getUser()); - + fileNode = createFileItemInternally(params.getSession(), parentNode, input, name, "", params.getUser(), false); } fileNodes.add(fileNode); @@ -209,7 +208,7 @@ public class ItemHandler { params.getSession().save(); for (Node node : fileNodes) - versionHandler.checkinContentNode(node, params.getSession()); + versionHandler.checkinContentNode(node); return parentDirectoryNode; } @@ -246,13 +245,28 @@ public class ItemHandler { return newNode; } - private Node createFileItemInternally(Session ses, Node destinationNode, InputStream stream, String name, String description, String login, boolean withLock) throws RepositoryException, UserNotAuthorizedException, ItemLockedException, BackendGenericError{ + private Node createFileItemInternally(Session ses, Node destinationNode, InputStream stream, String name, String description, String login, boolean withLock) throws RepositoryException, StorageHubException{ Node newNode; - try { - newNode = ses.getNode(org.gcube.common.storagehub.model.Paths.append(org.gcube.common.storagehub.model.Paths.getPath(destinationNode.getPath()), name).toPath()); + FolderItem destinationItem = node2Item.getItem(destinationNode, Excludes.ALL); + FolderManager folderManager = pluginHandler.getFolderManager(destinationItem); + StorageBackend storageBackend = folderManager.getStorageBackend(); + String relativePath = destinationNode.getPath(); + + if (destinationItem.isExternalManaged()) + relativePath = relativePath.replace(folderManager.getRootFolder().getPath(), ""); + + + String newNodePath = Paths.append(Paths.getPath(destinationNode.getPath()), name).toPath(); + + if (ses.nodeExists(newNodePath)) { + + if (!folderManager.manageVersion()) + throw new InvalidCallParameters("storage for plugin "+folderManager.getClass().getName()+" doesn't support versioning"); + newNode = ses.getNode(newNodePath); authChecker.checkWriteAuthorizationControl(ses, login, newNode.getIdentifier(), false); - AbstractFileItem item = fillItemWithContent(stream, name, description, destinationNode.getPath(), login); + + AbstractFileItem item = fillItemWithContent(stream, storageBackend, name, description, relativePath,login); item.setHidden(destinationNode.getProperty(NodeProperty.HIDDEN.toString()).getBoolean()); if (withLock) { try { @@ -262,7 +276,7 @@ public class ItemHandler { } } try { - versionHandler.checkoutContentNode(newNode, ses); + versionHandler.checkoutContentNode(newNode); log.trace("replacing content of class {}",item.getContent().getClass()); item2Node.replaceContent(newNode,item, ItemAction.UPDATED); accountingHandler.createFileUpdated(item.getTitle(), ses, newNode, login, false); @@ -270,9 +284,10 @@ public class ItemHandler { }finally { if (withLock) ses.getWorkspace().getLockManager().unlock(newNode.getPath()); } - }catch(PathNotFoundException pnf) { + } + else { authChecker.checkWriteAuthorizationControl(ses, login, destinationNode.getIdentifier(), true); - AbstractFileItem item = fillItemWithContent(stream, name, description, destinationNode.getPath(), login); + AbstractFileItem item = fillItemWithContent(stream, storageBackend, name, description, relativePath, login); if (withLock) { try { log.debug("trying to acquire lock"); @@ -288,20 +303,22 @@ public class ItemHandler { }finally { if (withLock) ses.getWorkspace().getLockManager().unlock(destinationNode.getPath()); } - versionHandler.makeVersionableContent(newNode, ses); + versionHandler.makeVersionableContent(newNode); accountingHandler.createFolderAddObj(name, item.getClass().getSimpleName(), item.getContent().getMimeType(), ses, login, destinationNode, false); } return newNode; } - private AbstractFileItem fillItemWithContent(InputStream stream, String name, String description, String path, String login) throws BackendGenericError{ - ContentHandler handler = getContentHandler(stream , name, path, login); + + + private AbstractFileItem fillItemWithContent(InputStream stream, StorageBackend storageBackend, String name, String description, String relPath, String login) throws BackendGenericError{ + ContentHandler handler = getContentHandler(stream, storageBackend, name, relPath, login); AbstractFileItem item =handler.buildItem(name, description, login); return item ; } - private ContentHandler getContentHandler(InputStream stream , String name, String path, String login) throws BackendGenericError { + private ContentHandler getContentHandler(InputStream stream, StorageBackend storageBackend, String name, String relPath, String login) throws BackendGenericError { final MultipleOutputStream mos; @@ -348,9 +365,7 @@ public class ItemHandler { @Override public MetaInfo call() throws Exception { try(InputStream is1 = mos.get()){ - String uid = UUID.randomUUID().toString(); - String remotePath= String.format("%s/%s-%s",path,uid,name); - MetaInfo info = storageBackend.upload(is1, remotePath); + MetaInfo info = storageBackend.upload(is1, relPath, name); return info; }catch (Throwable e) { log.error("error writing content",e ); diff --git a/src/main/java/org/gcube/data/access/storagehub/handlers/items/Node2ItemConverter.java b/src/main/java/org/gcube/data/access/storagehub/handlers/items/Node2ItemConverter.java index 48981d6..5a9e41c 100644 --- a/src/main/java/org/gcube/data/access/storagehub/handlers/items/Node2ItemConverter.java +++ b/src/main/java/org/gcube/data/access/storagehub/handlers/items/Node2ItemConverter.java @@ -12,8 +12,6 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.function.Consumer; -import java.util.function.Function; import javax.inject.Singleton; import javax.jcr.Node; @@ -28,16 +26,20 @@ import javax.jcr.Value; import org.apache.commons.io.IOUtils; import org.apache.jackrabbit.util.Text; -import org.gcube.common.storagehub.model.Excludes; import org.gcube.common.storagehub.model.annotations.Attribute; import org.gcube.common.storagehub.model.annotations.AttributeRootNode; import org.gcube.common.storagehub.model.annotations.ListNodes; import org.gcube.common.storagehub.model.annotations.MapAttribute; import org.gcube.common.storagehub.model.annotations.NodeAttribute; import org.gcube.common.storagehub.model.exceptions.BackendGenericError; +import org.gcube.common.storagehub.model.items.ExternalFolder; import org.gcube.common.storagehub.model.items.Item; +import org.gcube.common.storagehub.model.items.RootItem; import org.gcube.common.storagehub.model.items.SharedFolder; import org.gcube.common.storagehub.model.items.TrashItem; +import org.gcube.common.storagehub.model.items.nodes.Content; +import org.gcube.common.storagehub.model.messages.Message; +import org.gcube.data.access.storagehub.Constants; import org.gcube.data.access.storagehub.handlers.ClassHandler; import org.reflections.Configuration; import org.reflections.Reflections; @@ -54,7 +56,7 @@ public class Node2ItemConverter { private static HashMap, Map> typeToSubtypeMap = new HashMap<>(); - public T getFilteredItem(Node node, List excludes, Class nodeTypeToInclude) throws RepositoryException, BackendGenericError{ + public T getFilteredItem(Node node, List excludes, Class nodeTypeToInclude) throws RepositoryException, BackendGenericError{ @SuppressWarnings("unchecked") Class classToHandle = (Class)ClassHandler.instance().get(node.getPrimaryNodeType().getName()); if (classToHandle==null) return null; @@ -71,22 +73,29 @@ public class Node2ItemConverter { @SuppressWarnings("unchecked") Class classToHandle = (Class)ClassHandler.instance().get(node.getPrimaryNodeType().getName()); if (classToHandle==null) return null; - /*Node nodeToRetrieve= node; - if (SharedFolder.class.isAssignableFrom(classToHandle)) { - NodeIterator it= node.getSharedSet(); - while (it.hasNext()) { - Node sharedNode = it.nextNode(); - if (sharedNode.getPath().startsWith(Utils.getWorkspacePath().toPath())) { - nodeToRetrieve = sharedNode; - } - - } - }*/ T item = retrieveItem(node, excludes, classToHandle); - item.setRelatedNode(node); return item; } + public Content getContent(Node node) throws RepositoryException, BackendGenericError{ + Content content = new Content(); + setGenericFields(node, Content.class, content); + return content; + } + + public Message getMessageItem(Node node) throws RepositoryException{ + Message msg = new Message(); + try { + Node attachmentNode = node.getNode(Constants.ATTACHMENTNODE_NAME); + msg.setWithAttachments(attachmentNode.hasNodes()); + }catch (Throwable e) { + msg.setWithAttachments(false); + } + + setRooItemCommonFields(node, Collections.emptyList(), Message.class, msg); + return msg; + } + private T retrieveItem(Node node, List excludes, Class classToHandle) throws RepositoryException, BackendGenericError{ T item; @@ -95,13 +104,6 @@ public class Node2ItemConverter { }catch (Exception e) { throw new BackendGenericError(e); } - item.setId(node.getIdentifier()); - item.setName(Text.unescapeIllegalJcrChars(node.getName())); - - item.setPath(Text.unescapeIllegalJcrChars(node.getPath())); - - item.setLocked(node.isLocked()); - item.setPrimaryType(node.getPrimaryNodeType().getName()); try { item.setShared(SharedFolder.class.isInstance(item) || @@ -117,20 +119,58 @@ public class Node2ItemConverter { item.setTrashed(false); } + try { + item.setExternalManaged(hasTypedParent(node, ExternalFolder.class)); + }catch (Exception e) { + item.setExternalManaged(false); + } + + + item.setLocked(node.isLocked()); + + setRooItemCommonFields(node, excludes, classToHandle, item); + + return item; + } + + + + private boolean hasTypedParent(Node node, Class parentType) throws BackendGenericError, RepositoryException{ + if(node==null) return false; + return checkNodeType(node, parentType) || hasTypedParent(node.getParent(), parentType); + } + + + private void setRooItemCommonFields(Node node, List excludes, Class classToHandle, T instance) throws RepositoryException{ + try{ - item.setParentId(node.getParent().getIdentifier()); - item.setParentPath(node.getParent().getPath()); + instance.setParentId(node.getParent().getIdentifier()); + instance.setParentPath(node.getParent().getPath()); }catch (Throwable e) { logger.trace("Root node doesn't have a parent"); } + + instance.setRelatedNode(node); + + instance.setId(node.getIdentifier()); + instance.setName(Text.unescapeIllegalJcrChars(node.getName())); + + instance.setPath(Text.unescapeIllegalJcrChars(node.getPath())); + + instance.setPrimaryType(node.getPrimaryNodeType().getName()); + setGenericFields(node, classToHandle, instance); + + } + + private void setGenericFields(Node node, Class classToHandle, T instance){ for (Field field : retrieveAllFields(classToHandle)){ if (field.isAnnotationPresent(Attribute.class)){ Attribute attribute = field.getAnnotation(Attribute.class); field.setAccessible(true); try{ Class returnType = field.getType(); - field.set(item, getPropertyValue(returnType, node.getProperty(attribute.value()))); + field.set(instance, getPropertyValue(returnType, node.getProperty(attribute.value()))); logger.trace("retrieve item - added field {}",field.getName()); }catch(PathNotFoundException e){ logger.trace("the current node dosn't contain {} property",attribute.value()); @@ -140,13 +180,12 @@ public class Node2ItemConverter { } else if (field.isAnnotationPresent(NodeAttribute.class)){ String fieldNodeName = field.getAnnotation(NodeAttribute.class).value(); //for now it excludes only first level node - if (excludes!=null && excludes.contains(fieldNodeName)) continue; logger.trace("retrieving field node "+field.getName()); field.setAccessible(true); try{ Node fieldNode = node.getNode(fieldNodeName); logger.trace("looking in node {} searched with {}",fieldNode.getName(),fieldNodeName); - field.set(item, iterateNodeAttributeFields(field.getType(), fieldNode)); + field.set(instance, iterateNodeAttributeFields(field.getType(), fieldNode)); }catch(PathNotFoundException e){ logger.trace("the current node dosn't contain {} node",fieldNodeName); } catch (Exception e ) { @@ -156,19 +195,8 @@ public class Node2ItemConverter { } } - - return item; } - - private boolean hasTypedParent(Node node, Class parentType) throws BackendGenericError, RepositoryException{ - if(node==null) return false; - return checkNodeType(node, parentType) || hasTypedParent(node.getParent(), parentType); - - } - - - private T iterateNodeAttributeFields(Class clazz, Node node) throws Exception{ T obj = clazz.newInstance(); for (Field field : retrieveAllFields(clazz)){ @@ -264,7 +292,7 @@ public class Node2ItemConverter { return obj; } - @SuppressWarnings({ "rawtypes", "unchecked" }) + @SuppressWarnings({ "unchecked" }) private Object getPropertyValue(Class returnType, Property prop) throws Exception{ if (returnType.equals(String.class)) return prop.getString(); if (returnType.isEnum()) return Enum.valueOf(returnType, prop.getString()); diff --git a/src/main/java/org/gcube/data/access/storagehub/handlers/plugins/ExternalFolderPluginHandler.java b/src/main/java/org/gcube/data/access/storagehub/handlers/plugins/ExternalFolderPluginHandler.java deleted file mode 100644 index 4e24748..0000000 --- a/src/main/java/org/gcube/data/access/storagehub/handlers/plugins/ExternalFolderPluginHandler.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.gcube.data.access.storagehub.handlers.plugins; - -import java.util.Map; -import java.util.stream.Collectors; - -import javax.enterprise.inject.Instance; -import javax.inject.Inject; -import javax.inject.Singleton; - -import org.gcube.common.storagehub.model.exceptions.PluginNotFoundException; -import org.gcube.common.storagehub.model.plugins.ExternalFolderManagerConnector; - -@Singleton -public class ExternalFolderPluginHandler { - - @Inject - private Instance connectors; - - private Map connectorsMap; - - ExternalFolderPluginHandler(){ - connectorsMap = connectors.stream().collect(Collectors.toMap(ExternalFolderManagerConnector::getName, e -> e )); - } - - public ExternalFolderManagerConnector getConnector(String name) throws PluginNotFoundException { - if (!connectorsMap.containsKey(name)) throw new PluginNotFoundException("plugin "+name+" not found"); - return connectorsMap.get(name); - } -} diff --git a/src/main/java/org/gcube/data/access/storagehub/handlers/plugins/FolderPluginHandler.java b/src/main/java/org/gcube/data/access/storagehub/handlers/plugins/FolderPluginHandler.java new file mode 100644 index 0000000..fc517f0 --- /dev/null +++ b/src/main/java/org/gcube/data/access/storagehub/handlers/plugins/FolderPluginHandler.java @@ -0,0 +1,80 @@ +package org.gcube.data.access.storagehub.handlers.plugins; + +import java.util.Collections; +import java.util.Map; +import java.util.stream.Collectors; + +import javax.enterprise.inject.Default; +import javax.enterprise.inject.Instance; +import javax.inject.Inject; +import javax.inject.Singleton; +import javax.jcr.Node; +import javax.jcr.RepositoryException; +import javax.jcr.Session; + +import org.gcube.common.storagehub.model.Excludes; +import org.gcube.common.storagehub.model.exceptions.BackendGenericError; +import org.gcube.common.storagehub.model.exceptions.PluginInitializationException; +import org.gcube.common.storagehub.model.exceptions.PluginNotFoundException; +import org.gcube.common.storagehub.model.items.ExternalFolder; +import org.gcube.common.storagehub.model.items.Item; +import org.gcube.common.storagehub.model.plugins.FolderManager; +import org.gcube.common.storagehub.model.plugins.FolderManagerConnector; +import org.gcube.data.access.storagehub.handlers.items.Node2ItemConverter; +import org.gcube.data.access.storagehub.storage.backend.impl.GcubeFolderManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@Singleton +public class FolderPluginHandler { + + private static Logger log = LoggerFactory.getLogger(FolderPluginHandler.class); + + @Inject + Node2ItemConverter node2Item; + + private GcubeFolderManager defaultManager = new GcubeFolderManager(); + + public FolderManager getDefault() { + return defaultManager; + } + + @Inject + Instance connectors; + + private Map connectorsMap; + + FolderPluginHandler(){ + if (connectors !=null) + connectorsMap = connectors.stream().collect(Collectors.toMap(FolderManagerConnector::getName, e -> e )); + else { + log.info("connectors are null"); + connectorsMap = Collections.emptyMap(); + } + } + + public FolderManagerConnector getConnector(String name) throws PluginNotFoundException { + if (!connectorsMap.containsKey(name)) throw new PluginNotFoundException("plugin "+name+" not found"); + return connectorsMap.get(name); + } + + public FolderManager getFolderManager(Item item) throws PluginInitializationException, PluginNotFoundException, RepositoryException, BackendGenericError{ + if (!item.isExternalManaged()) + return defaultManager; + Session session = ((Node)item.getRelatedNode()).getSession(); + Item parent = null; + do { + String parentId = item.getParentId(); + Node node = session.getNodeByIdentifier(parentId); + parent = node2Item.getItem(node, Excludes.ALL); + + if (parent !=null && parent instanceof ExternalFolder) { + ExternalFolder extParent = (ExternalFolder) parent; + String plugin = extParent.getManagedBy(); + Map parameters = extParent.getConnectionParameters().getMap(); + return getConnector(plugin).connect(extParent, parameters); + } + } while (parent!=null); + throw new BackendGenericError("selected external managed item doesn't have a parent external folder"); + } +} diff --git a/src/main/java/org/gcube/data/access/storagehub/handlers/plugins/OperationMediator.java b/src/main/java/org/gcube/data/access/storagehub/handlers/plugins/OperationMediator.java new file mode 100644 index 0000000..211a91f --- /dev/null +++ b/src/main/java/org/gcube/data/access/storagehub/handlers/plugins/OperationMediator.java @@ -0,0 +1,28 @@ +package org.gcube.data.access.storagehub.handlers.plugins; + +import javax.inject.Inject; +import javax.inject.Singleton; + +@Singleton +public class OperationMediator { + + @Inject + FolderPluginHandler folderHandler; + + /* + boolean onMove(Item source, Item destination, Session session) throws PluginInitializationException, PluginNotFoundException, BackendGenericError, RepositoryException{ + FolderManager sourceFolderManager = folderHandler.getFolderManager(source); + FolderManager destinationFolderManager = folderHandler.getFolderManager(destination); + + if (source instanceof FolderItem) { + destinationFolderManager.onCreatedFolder((FolderItem) source); + + + session.move(source.getPath(), destination.getPath()); + sourceFolderManager.onDeletingFolder((FolderItem) source); + } else if (source instanceof AbstractFileItem){ + + } + } + */ +} diff --git a/src/main/java/org/gcube/data/access/storagehub/services/ItemSharing.java b/src/main/java/org/gcube/data/access/storagehub/services/ItemSharing.java index 8050dae..7dadea4 100644 --- a/src/main/java/org/gcube/data/access/storagehub/services/ItemSharing.java +++ b/src/main/java/org/gcube/data/access/storagehub/services/ItemSharing.java @@ -35,6 +35,7 @@ import org.gcube.common.storagehub.model.exceptions.InvalidCallParameters; import org.gcube.common.storagehub.model.exceptions.InvalidItemException; import org.gcube.common.storagehub.model.exceptions.ItemLockedException; import org.gcube.common.storagehub.model.exceptions.StorageHubException; +import org.gcube.common.storagehub.model.items.ExternalFolder; import org.gcube.common.storagehub.model.items.FolderItem; import org.gcube.common.storagehub.model.items.Item; import org.gcube.common.storagehub.model.items.SharedFolder; diff --git a/src/main/java/org/gcube/data/access/storagehub/services/ItemsManager.java b/src/main/java/org/gcube/data/access/storagehub/services/ItemsManager.java index 981d461..52c05e4 100644 --- a/src/main/java/org/gcube/data/access/storagehub/services/ItemsManager.java +++ b/src/main/java/org/gcube/data/access/storagehub/services/ItemsManager.java @@ -57,12 +57,16 @@ import org.gcube.common.storagehub.model.exceptions.IdNotFoundException; import org.gcube.common.storagehub.model.exceptions.InvalidCallParameters; import org.gcube.common.storagehub.model.exceptions.InvalidItemException; import org.gcube.common.storagehub.model.exceptions.ItemLockedException; +import org.gcube.common.storagehub.model.exceptions.PluginInitializationException; +import org.gcube.common.storagehub.model.exceptions.PluginNotFoundException; import org.gcube.common.storagehub.model.exceptions.StorageHubException; import org.gcube.common.storagehub.model.items.AbstractFileItem; import org.gcube.common.storagehub.model.items.FolderItem; import org.gcube.common.storagehub.model.items.Item; import org.gcube.common.storagehub.model.items.SharedFolder; import org.gcube.common.storagehub.model.items.VreFolder; +import org.gcube.common.storagehub.model.items.nodes.Content; +import org.gcube.common.storagehub.model.plugins.FolderManager; import org.gcube.common.storagehub.model.service.ItemList; import org.gcube.common.storagehub.model.service.ItemWrapper; import org.gcube.common.storagehub.model.service.VersionList; @@ -78,12 +82,13 @@ import org.gcube.data.access.storagehub.Utils; import org.gcube.data.access.storagehub.accounting.AccountingHandler; import org.gcube.data.access.storagehub.exception.MyAuthException; import org.gcube.data.access.storagehub.handlers.ClassHandler; +import org.gcube.data.access.storagehub.handlers.CompressHandler; import org.gcube.data.access.storagehub.handlers.CredentialHandler; -import org.gcube.data.access.storagehub.handlers.StorageBackendHandler; import org.gcube.data.access.storagehub.handlers.TrashHandler; import org.gcube.data.access.storagehub.handlers.VersionHandler; import org.gcube.data.access.storagehub.handlers.items.Item2NodeConverter; import org.gcube.data.access.storagehub.handlers.items.Node2ItemConverter; +import org.gcube.data.access.storagehub.handlers.plugins.FolderPluginHandler; import org.gcube.smartgears.annotations.ManagedBy; import org.gcube.smartgears.utils.InnerMethodName; import org.slf4j.Logger; @@ -122,9 +127,14 @@ public class ItemsManager extends Impersonable{ @Inject Node2ItemConverter node2Item; @Inject Item2NodeConverter item2Node; - @Inject StorageBackendHandler storageBackend; - + @Inject + FolderPluginHandler folderPluginHandler; + + @Inject + CompressHandler compressHandler; + + @GET @Path("{id}") @Produces(MediaType.APPLICATION_JSON) @@ -215,11 +225,24 @@ public class ItemsManager extends Impersonable{ return null; } + @Deprecated @GET @Path("{id}/items/{name}") @Produces(MediaType.APPLICATION_JSON) - public ItemList findChildrenByNamePattern(@QueryParam("exclude") List excludes, @PathParam("name") String name){ + public ItemList findChildrenByNamePatternInPath(@QueryParam("exclude") List excludes, @PathParam("name") String name){ InnerMethodName.instance.set("findChildrenByNamePattern"); + return _findChildrenByNamePattern(excludes, name); + } + + @GET + @Path("{id}/items") + @Produces(MediaType.APPLICATION_JSON) + public ItemList findChildrenByNamePattern(@QueryParam("exclude") List excludes, @QueryParam("name") String name){ + InnerMethodName.instance.set("findChildrenByNamePattern"); + return _findChildrenByNamePattern(excludes, name); + } + + public ItemList _findChildrenByNamePattern(List excludes, String name){ Session ses = null; List toReturn = new ArrayList<>(); try{ @@ -255,11 +278,11 @@ public class ItemsManager extends Impersonable{ if (ses!=null) ses.logout(); } - + return new ItemList(toReturn); + } - @GET @Path("{id}/children/count") @Produces(MediaType.APPLICATION_JSON) @@ -624,7 +647,7 @@ public class ItemsManager extends Impersonable{ if (!(currentItem instanceof AbstractFileItem)) throw new InvalidItemException("this item is not versioned"); - List jcrVersions = versionHandler.getContentVersionHistory(node, ses); + List jcrVersions = versionHandler.getContentVersionHistory(node); for (Version version: jcrVersions) { boolean currentVersion = ((AbstractFileItem)currentItem).getContent().getStorageId().equals(version.getFrozenNode().getProperty(NodeProperty.STORAGE_ID.toString()).getString()); @@ -674,16 +697,15 @@ public class ItemsManager extends Impersonable{ if (!(currentItem instanceof AbstractFileItem)) throw new InvalidItemException("this item is not a file"); - List jcrVersions = versionHandler.getContentVersionHistory(ses.getNodeByIdentifier(id), ses); + List jcrVersions = versionHandler.getContentVersionHistory(node); for (Version version: jcrVersions) { log.debug("retrieved version id {}, name {}", version.getIdentifier(), version.getName()); if (version.getName().equals(versionName)) { - long size = version.getFrozenNode().getProperty(NodeProperty.SIZE.toString()).getLong(); - String mimeType = version.getFrozenNode().getProperty(NodeProperty.MIME_TYPE.toString()).getString(); - String storageId = version.getFrozenNode().getProperty(NodeProperty.STORAGE_ID.toString()).getString(); + Content content = node2Item.getContent(version); - final InputStream streamToWrite = storageBackend.download(storageId); + FolderManager folderManager = folderPluginHandler.getFolderManager((AbstractFileItem) currentItem); + final InputStream streamToWrite = folderManager.getStorageBackend().download(content); String oldfilename = FilenameUtils.getBaseName(currentItem.getTitle()); String ext = FilenameUtils.getExtension(currentItem.getTitle()); @@ -698,8 +720,8 @@ public class ItemsManager extends Impersonable{ return Response .ok(so) .header("content-disposition","attachment; filename = "+fileName) - .header("Content-Length", size) - .header("Content-Type", mimeType) + .header("Content-Length", content.getSize()) + .header("Content-Type", content.getMimeType()) .build(); } } @@ -779,7 +801,7 @@ public class ItemsManager extends Impersonable{ } else if (item instanceof FolderItem){ try { - final Deque allNodes = Utils.getAllNodesForZip((FolderItem)item, ses, currentUser, accountingHandler, excludes); + final Deque allNodes = compressHandler.getAllNodesForZip((FolderItem)item, ses, currentUser, accountingHandler, excludes); final org.gcube.common.storagehub.model.Path originalPath = Paths.getPath(item.getParentPath()); StreamingOutput so = new StreamingOutput() { @@ -790,7 +812,7 @@ public class ItemsManager extends Impersonable{ long start = System.currentTimeMillis(); zos.setLevel(Deflater.BEST_COMPRESSION); log.debug("writing StreamOutput"); - Utils.zipNode(zos, allNodes, currentUser, originalPath, storageBackend); + compressHandler.zipNode(zos, allNodes, currentUser, originalPath); log.debug("StreamOutput written in {}",(System.currentTimeMillis()-start)); } catch (Exception e) { log.error("error writing stream",e); @@ -825,9 +847,11 @@ public class ItemsManager extends Impersonable{ return response; } - private Response downloadFileInternal(Session ses, AbstractFileItem fileItem, String login, boolean withAccounting) throws RepositoryException { + private Response downloadFileInternal(Session ses, AbstractFileItem fileItem, String login, boolean withAccounting) throws RepositoryException, PluginInitializationException, PluginNotFoundException, BackendGenericError { - final InputStream streamToWrite = storageBackend.download(fileItem.getContent().getStorageId()); + FolderManager folderManager = folderPluginHandler.getFolderManager(fileItem); + + final InputStream streamToWrite = folderManager.getStorageBackend().download(fileItem.getContent()); if (withAccounting) accountingHandler.createReadObj(fileItem.getTitle(), ses, (Node) fileItem.getRelatedNode(), login, true); @@ -877,11 +901,8 @@ public class ItemsManager extends Impersonable{ if (!(destinationItem instanceof FolderItem)) throw new InvalidItemException("destination item is not a folder"); - boolean movingSharedItemOutside = item.isShared() && (!destinationItem.isShared() || !getSharedParentNode(nodeToMove).getIdentifier().equals(getSharedParentNode(destination).getIdentifier())); - - try { ses.getWorkspace().getLockManager().lock(destination.getPath(), false, true, 0,currentUser); ses.getWorkspace().getLockManager().lock(nodeToMove.getPath(), true, true, 0,currentUser); @@ -899,7 +920,9 @@ public class ItemsManager extends Impersonable{ if (movingSharedItemOutside) item2Node.updateOwnerOnSubTree(nodeToMove, currentUser); - + + //folderHandler.onMove(source, destination); + accountingHandler.createFolderAddObj(uniqueName, item.getClass().getSimpleName(), mimeTypeForAccounting, ses, currentUser, destination, false); accountingHandler.createFolderRemoveObj(item.getTitle(), item.getClass().getSimpleName(), mimeTypeForAccounting, ses, currentUser, originalParent, false); ses.save(); @@ -958,9 +981,12 @@ public class ItemsManager extends Impersonable{ Node newNode = ses.getNode(newPath); newFileIdentifier = newNode.getIdentifier(); + //TODO: folderHandler.onCopy(source, destination); + if (item instanceof AbstractFileItem) { + FolderManager manager = folderPluginHandler.getFolderManager(item); ((AbstractFileItem) item).getContent().setRemotePath(newPath); - String newStorageID = storageBackend.copy((AbstractFileItem) item); + String newStorageID = manager.getStorageBackend().onCopy((AbstractFileItem) item); ((AbstractFileItem) item).getContent().setStorageId(newStorageID); item2Node.replaceContent(newNode, (AbstractFileItem) item, ItemAction.CLONED); } @@ -1213,6 +1239,9 @@ public class ItemsManager extends Impersonable{ if (itemToDelete instanceof SharedFolder || itemToDelete instanceof VreFolder || (itemToDelete instanceof FolderItem && Utils.hasSharedChildren(nodeToDelete))) throw new InvalidItemException("SharedFolder, VreFolder or folders with shared children cannot be deleted"); + if (itemToDelete.isExternalManaged() && !force) + throw new InvalidItemException("External managed Items cannot be moved to Trash"); + log.debug("item is trashed? {}", itemToDelete.isTrashed()); if (!itemToDelete.isTrashed() && !force) { diff --git a/src/main/java/org/gcube/data/access/storagehub/services/MessageManager.java b/src/main/java/org/gcube/data/access/storagehub/services/MessageManager.java new file mode 100644 index 0000000..4d4f87a --- /dev/null +++ b/src/main/java/org/gcube/data/access/storagehub/services/MessageManager.java @@ -0,0 +1,413 @@ +package org.gcube.data.access.storagehub.services; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.UUID; + +import javax.enterprise.context.RequestScoped; +import javax.inject.Inject; +import javax.jcr.ItemNotFoundException; +import javax.jcr.Node; +import javax.jcr.NodeIterator; +import javax.jcr.RepositoryException; +import javax.jcr.Session; +import javax.servlet.ServletContext; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.FormParam; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; + +import org.apache.jackrabbit.api.JackrabbitSession; +import org.apache.jackrabbit.api.security.user.User; +import org.gcube.common.gxrest.response.outbound.GXOutboundErrorResponse; +import org.gcube.common.storagehub.model.Excludes; +import org.gcube.common.storagehub.model.Paths; +import org.gcube.common.storagehub.model.exceptions.BackendGenericError; +import org.gcube.common.storagehub.model.exceptions.IdNotFoundException; +import org.gcube.common.storagehub.model.exceptions.InvalidCallParameters; +import org.gcube.common.storagehub.model.exceptions.StorageHubException; +import org.gcube.common.storagehub.model.exceptions.UserNotAuthorizedException; +import org.gcube.common.storagehub.model.items.AbstractFileItem; +import org.gcube.common.storagehub.model.items.Item; +import org.gcube.common.storagehub.model.items.nodes.Owner; +import org.gcube.common.storagehub.model.messages.Message; +import org.gcube.common.storagehub.model.service.ItemList; +import org.gcube.common.storagehub.model.types.ItemAction; +import org.gcube.common.storagehub.model.types.MessageList; +import org.gcube.common.storagehub.model.types.NodeProperty; +import org.gcube.data.access.storagehub.Constants; +import org.gcube.data.access.storagehub.PathUtil; +import org.gcube.data.access.storagehub.StorageHubAppllicationManager; +import org.gcube.data.access.storagehub.Utils; +import org.gcube.data.access.storagehub.accounting.AccountingHandler; +import org.gcube.data.access.storagehub.handlers.CredentialHandler; +import org.gcube.data.access.storagehub.handlers.TrashHandler; +import org.gcube.data.access.storagehub.handlers.items.Item2NodeConverter; +import org.gcube.data.access.storagehub.handlers.items.Item2NodeConverter.Values; +import org.gcube.data.access.storagehub.handlers.items.Node2ItemConverter; +import org.gcube.data.access.storagehub.handlers.plugins.FolderPluginHandler; +import org.gcube.data.access.storagehub.types.MessageSharable; +import org.gcube.smartgears.annotations.ManagedBy; +import org.gcube.smartgears.utils.InnerMethodName; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@Path("messages") +@ManagedBy(StorageHubAppllicationManager.class) +public class MessageManager extends Impersonable{ + + private static final Logger log = LoggerFactory.getLogger(MessageManager.class); + + RepositoryInitializer repository = StorageHubAppllicationManager.repository; + + @Inject + AccountingHandler accountingHandler; + + @RequestScoped + @PathParam("id") + String id; + + @Context + ServletContext context; + + @Inject PathUtil pathUtil; + + @Inject Node2ItemConverter node2Item; + @Inject Item2NodeConverter item2Node; + + @Inject TrashHandler trashHandler; + + @GET + @Path("{id}") + @Produces(MediaType.APPLICATION_JSON) + public Message getById(){ + InnerMethodName.instance.set("getMessageById"); + Session ses = null; + Message toReturn = null; + try{ + ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context)); + Node messageNode = ses.getNodeByIdentifier(id); + toReturn = node2Item.getMessageItem(messageNode); + checkRights(currentUser, toReturn); + }catch (ItemNotFoundException e) { + log.error("id {} not found",id,e); + GXOutboundErrorResponse.throwException(new IdNotFoundException(id, e), Status.NOT_FOUND); + }catch(RepositoryException re){ + log.error("jcr error getting item", re); + GXOutboundErrorResponse.throwException(new BackendGenericError("jcr error getting item", re)); + }catch(StorageHubException she ){ + log.error(she.getErrorMessage(), she); + GXOutboundErrorResponse.throwException(she, Response.Status.fromStatusCode(she.getStatus())); + }finally{ + if (ses!=null) + ses.logout(); + } + + return toReturn; + } + + @DELETE + @Path("{id}") + public void deleteById(){ + InnerMethodName.instance.set("deleteMessageById"); + Session ses = null; + try{ + ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context)); + Node messageNode = ses.getNodeByIdentifier(id); + Message message = node2Item.getMessageItem(messageNode); + Node personalNode = checkRights(currentUser, message); + + if (countSharedSet(messageNode)>1) + personalNode.removeShare(); + else { + if (message.isWithAttachments()) { + Node attachmentNode = messageNode.getNode(Constants.ATTACHMENTNODE_NAME); + List attachments = Utils.getItemList(attachmentNode, Excludes.GET_ONLY_CONTENT, null, true, AbstractFileItem.class); + trashHandler.removeOnlyNodesContent(ses, attachments); + } + messageNode.removeSharedSet(); + } + ses.save(); + }catch (ItemNotFoundException e) { + log.error("id {} not found",id,e); + GXOutboundErrorResponse.throwException(new IdNotFoundException(id, e), Status.NOT_FOUND); + }catch(RepositoryException re){ + log.error("jcr error getting item", re); + GXOutboundErrorResponse.throwException(new BackendGenericError("jcr error getting item", re)); + }catch(StorageHubException she ){ + log.error(she.getErrorMessage(), she); + GXOutboundErrorResponse.throwException(she, Response.Status.fromStatusCode(she.getStatus())); + }finally{ + if (ses!=null) + ses.logout(); + } + } + + @GET + @Path("{id}/attachments") + @Produces(MediaType.APPLICATION_JSON) + public ItemList getAttachments(){ + InnerMethodName.instance.set("getAttachmentsByMessageId"); + Session ses = null; + List attachments = new ArrayList<>(); + try{ + ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context)); + Node messageNode = ses.getNodeByIdentifier(id); + Message messageItem = node2Item.getMessageItem(messageNode); + checkRights(currentUser, messageItem); + Node attachmentNode = messageNode.getNode(Constants.ATTACHMENTNODE_NAME); + attachments = Utils.getItemList(attachmentNode, Excludes.GET_ONLY_CONTENT, null, true, AbstractFileItem.class); + }catch (ItemNotFoundException e) { + log.error("id {} not found",id,e); + GXOutboundErrorResponse.throwException(new IdNotFoundException(id, e), Status.NOT_FOUND); + }catch(RepositoryException re){ + log.error("jcr error getting item", re); + GXOutboundErrorResponse.throwException(new BackendGenericError("jcr error getting item", re)); + }catch(StorageHubException she ){ + log.error(she.getErrorMessage(), she); + GXOutboundErrorResponse.throwException(she, Response.Status.fromStatusCode(she.getStatus())); + }finally{ + if (ses!=null) + ses.logout(); + } + + return new ItemList(attachments); + } + + @GET + @Path("inbox") + @Produces(MediaType.APPLICATION_JSON) + public MessageList getReceivedMessages(@QueryParam("reduceBody") Integer reduceBody){ + InnerMethodName.instance.set("getReceivedMessages"); + Session ses = null; + List toReturn = null; + try{ + ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context)); + + Node node = ses.getNode(pathUtil.getInboxPath(currentUser).toPath()); + + //return sorted for createdTime + toReturn = getMessages(node, reduceBody); + }catch(RepositoryException re){ + log.error("jcr error getting item", re); + GXOutboundErrorResponse.throwException(new BackendGenericError("jcr error getting item", re)); + }finally{ + if (ses!=null) + ses.logout(); + } + + return new MessageList(toReturn); + } + + @GET + @Path("sent") + @Produces(MediaType.APPLICATION_JSON) + public MessageList getSentMessages(@QueryParam("reduceBody") Integer reduceBody){ + InnerMethodName.instance.set("getSentMessages"); + Session ses = null; + List toReturn = null; + try{ + ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context)); + + Node node = ses.getNode(pathUtil.getOutboxPath(currentUser).toPath()); + + toReturn = getMessages(node, reduceBody); + }catch(RepositoryException re){ + log.error("jcr error getting item", re); + GXOutboundErrorResponse.throwException(new BackendGenericError("jcr error getting item", re)); + }finally{ + if (ses!=null) + ses.logout(); + } + + return new MessageList(toReturn); + } + + @PUT + @Path("{id}/{prop}") + @Consumes(MediaType.APPLICATION_JSON) + public void setProperty(@PathParam("prop") String property,Object value){ + InnerMethodName.instance.set("setPropertyOnMessage("+property+")"); + Session ses = null; + try{ + ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context)); + Node messageNode = ses.getNodeByIdentifier(id); + Message messageItem = node2Item.getMessageItem(messageNode); + checkRights(currentUser, messageItem); + Values val = Item2NodeConverter.getObjectValue(value.getClass(), value); + messageNode.setProperty(property, val.getValue()); + ses.save(); + }catch (ItemNotFoundException e) { + log.error("id {} not found",id,e); + GXOutboundErrorResponse.throwException(new IdNotFoundException(id, e), Status.NOT_FOUND); + }catch(StorageHubException she ){ + log.error(she.getErrorMessage(), she); + GXOutboundErrorResponse.throwException(she, Response.Status.fromStatusCode(she.getStatus())); + }catch( Exception re){ + log.error("jcr error getting item", re); + GXOutboundErrorResponse.throwException(new BackendGenericError("jcr error getting item", re)); + }finally{ + if (ses!=null) + ses.logout(); + } + } + + + + @POST + @Path("send") + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + public String sendMessage(@FormParam("to[]") List addresses, + @FormParam("subject") String subject, @FormParam("body") String body, + @FormParam("attachments[]") List attachments){ + InnerMethodName.instance.set("sendMessage"); + JackrabbitSession ses = null; + String messageId = null; + try{ + if (addresses.size()==0 || body==null || subject==null) + throw new InvalidCallParameters(); + + ses = (JackrabbitSession) repository.getRepository().login(CredentialHandler.getAdminCredentials(context)); + + Message message = new MessageSharable(); + message.setAddresses(addresses.toArray(new String[0])); + message.setSubject(subject); + message.setBody(body); + message.setName(UUID.randomUUID().toString()); + User user = ses.getUserManager().getAuthorizable(currentUser, User.class); + Owner owner = new Owner(); + owner.setUserId(user.getID()); + owner.setUserName(user.getPrincipal().getName()); + message.setSender(owner); + + Node outbox = ses.getNode(pathUtil.getOutboxPath(currentUser).toPath()); + Node messageNode = saveMessage(ses, outbox, message, attachments); + ses.save(); + for (String to: addresses) + try { + String userMessagePath = Paths.append(pathUtil.getInboxPath(to), messageNode.getName()).toPath(); + ses.getWorkspace().clone(ses.getWorkspace().getName(), messageNode.getPath(), userMessagePath, false); + }catch (Exception e) { + log.warn("message not send to {}",to,e); + } + + ses.save(); + messageId = messageNode.getIdentifier(); + }catch(RepositoryException re){ + log.error("jcr error getting item", re); + GXOutboundErrorResponse.throwException(new BackendGenericError("jcr error getting item", re)); + }catch(StorageHubException she ){ + log.error(she.getErrorMessage(), she); + GXOutboundErrorResponse.throwException(she, Response.Status.fromStatusCode(she.getStatus())); + }finally{ + if (ses!=null) + ses.logout(); + } + + return messageId; + } + + + + private Node saveMessage(Session ses, Node messageFolderNode, Message message, List attachments) throws RepositoryException, BackendGenericError{ + Node messageNode = item2Node.getNode(messageFolderNode, message); + Node attachmentNode = messageNode.getNode(Constants.ATTACHMENTNODE_NAME); + for (String itemId: attachments) { + Node node = ses.getNodeByIdentifier(itemId); + Item item = node2Item.getItem(node, Excludes.GET_ONLY_CONTENT); + Node newNode = copyNode(ses, attachmentNode, item); + //removes accounting if exists + if (newNode.hasNode(NodeProperty.ACCOUNTING.toString())) + newNode.getNode(NodeProperty.ACCOUNTING.toString()).remove(); + } + return messageNode; + } + + //returns Messages sorted by createdTime + private List getMessages(Node node, Integer reduceBody) throws RepositoryException{ + List messages = new ArrayList(); + NodeIterator nodeIt = node.getNodes(); + while(nodeIt.hasNext()) { + Node child = nodeIt.nextNode(); + Message message = node2Item.getMessageItem(child); + if (reduceBody != null && reduceBody>0 && message.getBody().length()>reduceBody ) + message.setBody(message.getBody().substring(0, reduceBody)); + insertOrdered(messages, message); + } + return messages; + } + + private void insertOrdered(List messages, Message toInsert) { + if (messages.isEmpty()) messages.add(toInsert); + int i; + for ( i=0 ; i getWorkspace(@QueryParam("relPath") String relPath){ @@ -410,7 +410,7 @@ public class WorkspaceManager extends Impersonable{ @GET public String getTotalItemsCount(){ InnerMethodName.instance.set("getTotalItemsCount"); - return storageBackend.getTotalItemsCount(); + return folderHandler.getDefault().getStorageBackend().getTotalItemsCount(); } @@ -418,7 +418,7 @@ public class WorkspaceManager extends Impersonable{ @GET public String getTotalVolume(){ InnerMethodName.instance.set("getTotalSize"); - return storageBackend.getTotalVolume(); + return folderHandler.getDefault().getStorageBackend().getTotalSizeStored(); } diff --git a/src/main/java/org/gcube/data/access/storagehub/storage/backend/impl/GCubeFolderManagerConnector.java b/src/main/java/org/gcube/data/access/storagehub/storage/backend/impl/GCubeFolderManagerConnector.java new file mode 100644 index 0000000..419ce90 --- /dev/null +++ b/src/main/java/org/gcube/data/access/storagehub/storage/backend/impl/GCubeFolderManagerConnector.java @@ -0,0 +1,22 @@ +package org.gcube.data.access.storagehub.storage.backend.impl; + +import java.util.Map; + +import javax.inject.Singleton; + +import org.gcube.common.storagehub.model.exceptions.PluginInitializationException; +import org.gcube.common.storagehub.model.items.FolderItem; +import org.gcube.common.storagehub.model.plugins.FolderManager; +import org.gcube.common.storagehub.model.plugins.FolderManagerConnector; + +@Singleton +public class GCubeFolderManagerConnector implements FolderManagerConnector { + + @Override + public FolderManager connect(FolderItem item, Map parameters) throws PluginInitializationException { + return new GcubeFolderManager(); + } + + + +} diff --git a/src/main/java/org/gcube/data/access/storagehub/storage/backend/impl/GCubeStorageBackend.java b/src/main/java/org/gcube/data/access/storagehub/storage/backend/impl/GCubeStorageBackend.java index 0b40216..7764309 100644 --- a/src/main/java/org/gcube/data/access/storagehub/storage/backend/impl/GCubeStorageBackend.java +++ b/src/main/java/org/gcube/data/access/storagehub/storage/backend/impl/GCubeStorageBackend.java @@ -1,10 +1,11 @@ package org.gcube.data.access.storagehub.storage.backend.impl; import java.io.InputStream; - -import javax.inject.Singleton; +import java.util.UUID; import org.gcube.common.authorization.library.provider.AuthorizationProvider; +import org.gcube.common.storagehub.model.items.AbstractFileItem; +import org.gcube.common.storagehub.model.items.nodes.Content; import org.gcube.common.storagehub.model.storages.MetaInfo; import org.gcube.common.storagehub.model.storages.StorageBackend; import org.gcube.contentmanagement.blobstorage.service.IClient; @@ -14,7 +15,6 @@ import org.gcube.contentmanager.storageclient.wrapper.StorageClient; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -@Singleton public class GCubeStorageBackend implements StorageBackend { private static final Logger log = LoggerFactory.getLogger(GCubeStorageBackend.class); @@ -22,9 +22,13 @@ public class GCubeStorageBackend implements StorageBackend { private final static String SERVICE_NAME = "home-library"; private final static String SERVICE_CLASS = "org.gcube.portlets.user"; + + + protected GCubeStorageBackend() {} + @Override - public InputStream getContent(String id) { - return getStorageClient(AuthorizationProvider.instance.get().getClient().getId()).getClient().get().RFileAsInputStream(id); + public InputStream download(Content content) { + return getStorageClient(AuthorizationProvider.instance.get().getClient().getId()).getClient().get().RFileAsInputStream(content.getStorageId()); } @Override @@ -33,35 +37,37 @@ public class GCubeStorageBackend implements StorageBackend { } @Override - public String copy(String idToCopy, String path) { - String newStorageID = getStorageClient(AuthorizationProvider.instance.get().getClient().getId()).getClient().copyFile(true).from(idToCopy).to(path); - log.info("copying storage Id {} to newPath {} and the id returned by storage is {}", idToCopy, path, newStorageID); + public String onCopy(AbstractFileItem item) { + String newStorageID = getStorageClient(AuthorizationProvider.instance.get().getClient().getId()).getClient().copyFile(true).from(item.getContent().getStorageId()).to(item.getPath()); + log.info("copying storage Id {} to newPath {} and the id returned by storage is {}", item.getContent().getStorageId(), item.getPath(), newStorageID); return newStorageID; } @Override - public String move(String idToMove) { - return idToMove; + public String onMove(AbstractFileItem item) { + return item.getContent().getStorageId(); } @Override - public MetaInfo upload(InputStream stream, String itemPath) { + public MetaInfo upload(InputStream stream, String relPath, String name) { log.debug("uploading file"); IClient storageClient = getStorageClient(AuthorizationProvider.instance.get().getClient().getId()).getClient(); - String storageId =storageClient.put(true).LFile(stream).RFile(itemPath); + String uid = UUID.randomUUID().toString(); + String remotePath= String.format("%s/%s-%s",relPath,uid,name); + String storageId =storageClient.put(true).LFile(stream).RFile(remotePath); long size = storageClient.getSize().RFileById(storageId); MetaInfo info = new MetaInfo(); info.setSize(size); info.setStorageId(storageId); - info.setRemotePath(itemPath); + info.setRemotePath(remotePath); return info; } @Override - public void delete(String id) { + public void onDelete(Content content) { log.debug("deleting"); IClient storageClient = getStorageClient(AuthorizationProvider.instance.get().getClient().getId()).getClient(); - storageClient.remove().RFileById(id); + storageClient.remove().RFileById(content.getStorageId()); } private static StorageClient getStorageClient(String login){ @@ -81,8 +87,5 @@ public class GCubeStorageBackend implements StorageBackend { return storageClient.getUserTotalItems(); } - - - } diff --git a/src/main/java/org/gcube/data/access/storagehub/storage/backend/impl/GcubeFolderManager.java b/src/main/java/org/gcube/data/access/storagehub/storage/backend/impl/GcubeFolderManager.java new file mode 100644 index 0000000..bfe4bec --- /dev/null +++ b/src/main/java/org/gcube/data/access/storagehub/storage/backend/impl/GcubeFolderManager.java @@ -0,0 +1,48 @@ +package org.gcube.data.access.storagehub.storage.backend.impl; + +import javax.inject.Singleton; + +import org.gcube.common.storagehub.model.items.FolderItem; +import org.gcube.common.storagehub.model.plugins.FolderManager; +import org.gcube.common.storagehub.model.storages.StorageBackend; + +@Singleton +public class GcubeFolderManager implements FolderManager { + + @Override + public StorageBackend getStorageBackend() { + return new GCubeStorageBackend(); + } + + @Override + public boolean manageVersion() { + return true; + } + + @Override + public void onCreatedFolder(FolderItem folder) { + } + + @Override + public void onDeletingFolder(FolderItem folder) { + + } + + @Override + public void onMovedFolder(FolderItem movedFolder) { + // TODO Auto-generated method stub + + } + + @Override + public void onCopiedFolder(FolderItem copiedFolder) { + // TODO Auto-generated method stub + + } + + @Override + public FolderItem getRootFolder() { + return null; + } + +} diff --git a/src/main/java/org/gcube/data/access/storagehub/types/MessageSharable.java b/src/main/java/org/gcube/data/access/storagehub/types/MessageSharable.java new file mode 100644 index 0000000..15d6c74 --- /dev/null +++ b/src/main/java/org/gcube/data/access/storagehub/types/MessageSharable.java @@ -0,0 +1,16 @@ +package org.gcube.data.access.storagehub.types; + +import org.gcube.common.storagehub.model.annotations.RootNode; +import org.gcube.common.storagehub.model.messages.Message; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@RootNode("nthl:itemSentRequestSH") +public class MessageSharable extends Message { + +} diff --git a/src/main/webapp/WEB-INF/README b/src/main/webapp/WEB-INF/README index 9018e3b..e0b24a3 100644 --- a/src/main/webapp/WEB-INF/README +++ b/src/main/webapp/WEB-INF/README @@ -25,7 +25,7 @@ The projects leading to this software have received funding from a series of Version -------------------------------------------------- -1.3.0-SNAPSHOT (20210407-065343) +1.3.0-SNAPSHOT (20210504-093803) Please see the file named "changelog.xml" in this directory for the release notes.