You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
storagehub/src/main/java/org/gcube/data/access/storagehub/handlers/TrashHandler.java

285 lines
11 KiB
Java

package org.gcube.data.access.storagehub.handlers;
import java.util.Calendar;
import java.util.HashSet;
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;
import javax.jcr.ItemNotFoundException;
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;
import org.gcube.common.storagehub.model.Paths;
import org.gcube.common.storagehub.model.exceptions.BackendGenericError;
import org.gcube.common.storagehub.model.exceptions.InvalidCallParameters;
import org.gcube.common.storagehub.model.exceptions.ItemLockedException;
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.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;
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;
@Singleton
public class TrashHandler {
private static Logger log = LoggerFactory.getLogger(TrashHandler.class);
ExecutorService executor = Executors.newFixedThreadPool(100);
@Inject
VersionHandler versionHandler;
@Inject
AuthorizationChecker authChecker;
@Inject
AccountingHandler accountingHandler;
@Inject
Item2NodeConverter item2Node;
@Inject
Node2ItemConverter node2Item;
@Inject
PathUtil pathUtil;
@Inject FolderPluginHandler managerHandler;
@Inject
FolderPluginHandler folderHandler;
public void removeNodes(Session ses, List<Item> itemsToDelete) throws RepositoryException, StorageHubException{
log.debug("defnitively removing nodes with ids {}",itemsToDelete);
for (Item item: itemsToDelete) {
removeNodesInternally(ses, item, false);
}
}
public void removeOnlyNodesContent(Session ses, List<Item> itemsToDelete) throws RepositoryException, StorageHubException{
log.debug("defnitively removing nodes with ids {}",itemsToDelete);
for (Item item: itemsToDelete) {
removeNodesInternally(ses, item, true);
}
}
private void retrieveContentsToDelete(Set<AbstractFileItem> 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<Item> 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<AbstractFileItem> itemsToDelete = new HashSet<>();
Node nodeToDelete = ses.getNodeByIdentifier(itemToDelete.getId());
if (itemToDelete instanceof TrashItem) {
List<Item> trashChildren = Utils.getItemList(nodeToDelete, Excludes.GET_ONLY_CONTENT, null, true, null);
for (Item itemContentToRetrieve: trashChildren)
retrieveContentsToDelete(itemsToDelete, itemContentToRetrieve);
} else
retrieveContentsToDelete(itemsToDelete, itemToDelete);
if (!onlyContent)
nodeToDelete.remove();
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 (AbstractFileItem item: itemsToDelete ) {
try {
FolderManager manager = folderHandler.getFolderManager(item);
manager.getStorageBackend().onDelete(item.getContent());
List<Version> 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 with id {} from storage",item.getId(), t);
}
}
}
});
executor.execute(deleteFromStorageRunnable);
if (!onlyContent)
ses.save();
}catch (LockException e) {
throw new ItemLockedException("the selected node or his parent is locked", e);
}catch (Exception e) {
throw new BackendGenericError("error permanetly deleting items",e);
}
}
public void moveToTrash(Session ses, Node nodeToDelete, Item item, String login) throws RepositoryException, BackendGenericError{
log.debug("moving node {} to trash ",item.getId());
final Node trashFolder = ses.getNode(pathUtil.getTrashPath(login, ses).toPath());
try {
ses.getWorkspace().getLockManager().lock(trashFolder.getPath(), true, true, 0,login);
ses.getWorkspace().getLockManager().lock(nodeToDelete.getPath(), true, true, 0,login);
log.debug("preparing thrash item");
TrashItem trashItem = new TrashItem();
trashItem.setDeletedBy(login);
trashItem.setDeletedFrom(nodeToDelete.getParent().getPath());
Calendar now = Calendar.getInstance();
trashItem.setDeletedTime(now);
trashItem.setHidden(false);
trashItem.setLastAction(ItemAction.CREATED);
trashItem.setDescription("trash item of node " + nodeToDelete.getPath());
trashItem.setParentId(trashFolder.getIdentifier());
trashItem.setParentPath(trashFolder.getPath());
//String pathUUid= UUID.randomUUID().toString();
trashItem.setTitle(item.getTitle());
trashItem.setName(item.getId());
trashItem.setOriginalParentId(nodeToDelete.getParent().getIdentifier());
trashItem.setOwner(login);
trashItem.setLastModificationTime(item.getLastModificationTime());
trashItem.setLastModifiedBy(item.getLastModifiedBy());
trashItem.setLenght(0);
if (item instanceof FolderItem) {
trashItem.setFolder(true);
}else if (item instanceof AbstractFileItem ) {
AbstractFileItem file = (AbstractFileItem) item;
if (file.getContent()!=null) {
trashItem.setMimeType(file.getContent().getMimeType());
trashItem.setLenght(file.getContent().getSize());
}
trashItem.setFolder(false);
}
log.debug("creating node");
Node newTrashItemNode = item2Node.getNode(trashFolder, trashItem);
ses.save();
log.debug("calling jcr move");
ses.getWorkspace().move(nodeToDelete.getPath(), Paths.append(Paths.getPath(newTrashItemNode.getPath()),nodeToDelete.getName()).toPath());
String mimetype = null;
if (item instanceof AbstractFileItem) {
if (((AbstractFileItem)item).getContent()!=null)
mimetype = ((AbstractFileItem) item).getContent().getMimeType();
else log.warn("the AbstractFileItem with id {} has no content (check it!!)", item.getId());
}
accountingHandler.createFolderRemoveObj(item.getName(), item.getClass().getSimpleName(), mimetype, ses, login, (Node) item.getRelatedNode(), true);
}catch(Throwable t) {
log.error("error exceuting move to trash",t);
throw new BackendGenericError(t);
}finally {
ses.getWorkspace().getLockManager().unlock(nodeToDelete.getPath());
ses.getWorkspace().getLockManager().unlock(trashFolder.getPath());
}
}
public String restoreItem(Session ses, TrashItem item, FolderItem destination, String login) throws RepositoryException, StorageHubException, BackendGenericError{
log.debug("restoring node from trash with user ");
//final Node trashFolder = ses.getNode(Paths.append(Utils.getHomePath(),Constants.TRASH_ROOT_FOLDER_NAME).toPath());
Node destinationNode= null;
if (destination==null) {
boolean originalParentExists = true;
boolean originalParentTrashed = false;
Node originalParent = null;
try {
originalParent = ses.getNodeByIdentifier(item.getOriginalParentId());
}catch (ItemNotFoundException e) {
originalParentExists = false;
}
Item originalParentItem = null;
if (originalParentExists) {
originalParentItem = node2Item.getItem(originalParent, Excludes.ALL);
originalParentTrashed = originalParentItem.isTrashed();
}
if(originalParentExists && !originalParentTrashed) {
destinationNode = originalParent;
}else {
String homeWS = pathUtil.getWorkspacePath(login).toPath();
Node node = ses.getNode(homeWS);
destinationNode = node;
}
} else {
Node node = (Node)destination.getRelatedNode();
if (!node2Item.checkNodeType(node, FolderItem.class))
throw new InvalidCallParameters("destination Node is not a folder");
destinationNode = node;
}
authChecker.checkWriteAuthorizationControl(ses, login, destinationNode.getIdentifier(), true );
ses.getWorkspace().getLockManager().lock(destinationNode.getPath(), true, true, 0,login);
String newNodePath = null;
try {
//the real node is a child of the Trash node
List<Item> items = Utils.getItemList(ses.getNodeByIdentifier(item.getId()), Excludes.ALL, null, false, null);
if (items.size()!=1) {
log.warn("a problem occurred restoring item from trash");
throw new BackendGenericError("An error occurred on trash item");
}
Item itemToMove = items.get(0);
item2Node.updateOwnerOnSubTree(ses.getNodeByIdentifier(itemToMove.getId()), login);
String uniqueName = Utils.checkExistanceAndGetUniqueName(ses, destinationNode, itemToMove.getName());
newNodePath = Paths.append(Paths.getPath(destinationNode.getPath()),uniqueName).toPath();
ses.move(itemToMove.getPath(), newNodePath);
Utils.setPropertyOnChangeNode(ses.getNode(newNodePath), login, ItemAction.MOVED);
ses.removeItem(item.getPath());
ses.save();
}catch (Exception e) {
if (ses.getWorkspace().getLockManager().isLocked(destinationNode.getPath()))
ses.getWorkspace().getLockManager().unlock(destinationNode.getPath());
}
return ses.getNode(newNodePath).getIdentifier();
}
}