2018-10-25 16:33:23 +02:00
|
|
|
package org.gcube.data.access.storagehub.handlers;
|
|
|
|
|
|
|
|
import java.util.Calendar;
|
|
|
|
import java.util.HashSet;
|
|
|
|
import java.util.List;
|
|
|
|
import java.util.Set;
|
2020-04-08 21:11:43 +02:00
|
|
|
import java.util.concurrent.ExecutorService;
|
|
|
|
import java.util.concurrent.Executors;
|
2018-10-25 16:33:23 +02:00
|
|
|
|
|
|
|
import javax.inject.Inject;
|
|
|
|
import javax.inject.Singleton;
|
2020-04-08 21:11:43 +02:00
|
|
|
import javax.jcr.ItemNotFoundException;
|
2018-10-25 16:33:23 +02:00
|
|
|
import javax.jcr.Node;
|
|
|
|
import javax.jcr.RepositoryException;
|
|
|
|
import javax.jcr.Session;
|
2019-05-23 14:58:02 +02:00
|
|
|
import javax.jcr.lock.LockException;
|
2018-10-25 16:33:23 +02:00
|
|
|
|
2019-05-23 14:58:02 +02:00
|
|
|
import org.gcube.common.authorization.library.AuthorizedTasks;
|
2018-10-25 16:33:23 +02:00
|
|
|
import org.gcube.common.authorization.library.provider.AuthorizationProvider;
|
|
|
|
import org.gcube.common.storagehub.model.Excludes;
|
|
|
|
import org.gcube.common.storagehub.model.Paths;
|
|
|
|
import org.gcube.common.storagehub.model.exceptions.BackendGenericError;
|
2020-04-14 18:52:59 +02:00
|
|
|
import org.gcube.common.storagehub.model.exceptions.InvalidCallParameters;
|
2019-05-23 14:58:02 +02:00
|
|
|
import org.gcube.common.storagehub.model.exceptions.ItemLockedException;
|
|
|
|
import org.gcube.common.storagehub.model.exceptions.StorageHubException;
|
2018-10-25 16:33:23 +02:00
|
|
|
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.items.Item;
|
|
|
|
import org.gcube.common.storagehub.model.items.TrashItem;
|
|
|
|
import org.gcube.common.storagehub.model.types.ItemAction;
|
|
|
|
import org.gcube.data.access.storagehub.AuthorizationChecker;
|
|
|
|
import org.gcube.data.access.storagehub.Constants;
|
|
|
|
import org.gcube.data.access.storagehub.Utils;
|
|
|
|
import org.gcube.data.access.storagehub.accounting.AccountingHandler;
|
2020-04-08 21:11:43 +02:00
|
|
|
import org.gcube.data.access.storagehub.handlers.items.Item2NodeConverter;
|
|
|
|
import org.gcube.data.access.storagehub.handlers.items.Node2ItemConverter;
|
2018-10-25 16:33:23 +02:00
|
|
|
import org.slf4j.Logger;
|
|
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
|
|
|
|
@Singleton
|
|
|
|
public class TrashHandler {
|
|
|
|
|
|
|
|
private static Logger log = LoggerFactory.getLogger(TrashHandler.class);
|
|
|
|
|
2020-04-08 21:11:43 +02:00
|
|
|
ExecutorService executor = Executors.newFixedThreadPool(100);
|
2020-04-14 18:52:59 +02:00
|
|
|
|
2018-10-25 16:33:23 +02:00
|
|
|
@Inject
|
|
|
|
VersionHandler versionHandler;
|
|
|
|
|
|
|
|
@Inject
|
|
|
|
AccountingHandler accountingHandler;
|
|
|
|
|
|
|
|
@Inject
|
|
|
|
AuthorizationChecker authChecker;
|
2019-05-22 17:47:15 +02:00
|
|
|
|
2018-10-25 16:33:23 +02:00
|
|
|
@Inject
|
|
|
|
Item2NodeConverter item2Node;
|
2020-04-14 18:52:59 +02:00
|
|
|
|
2020-04-08 21:11:43 +02:00
|
|
|
@Inject
|
|
|
|
Node2ItemConverter node2Item;
|
2018-10-25 16:33:23 +02:00
|
|
|
|
2019-07-05 12:09:16 +02:00
|
|
|
@Inject
|
|
|
|
StorageBackendHandler storageHandler;
|
2020-04-14 18:52:59 +02:00
|
|
|
|
2019-05-23 14:58:02 +02:00
|
|
|
public void removeNodes(Session ses, List<Item> itemsToDelete) throws RepositoryException, StorageHubException{
|
2018-10-25 16:33:23 +02:00
|
|
|
log.debug("defnitively removing nodes with ids {}",itemsToDelete);
|
2019-05-22 17:47:15 +02:00
|
|
|
for (Item item: itemsToDelete) {
|
|
|
|
removeNodesInternally(ses, item);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-23 14:58:02 +02:00
|
|
|
private void removeNodesInternally(Session ses, Item itemToDelete) throws RepositoryException, StorageHubException {
|
2020-04-14 18:52:59 +02:00
|
|
|
|
2018-10-25 16:33:23 +02:00
|
|
|
try {
|
|
|
|
Set<String> contentIdsToDelete = new HashSet<>();
|
|
|
|
|
2019-05-22 17:47:15 +02:00
|
|
|
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)
|
|
|
|
Utils.getAllContentIds(ses, contentIdsToDelete, itemContentToRetrieve, versionHandler);
|
|
|
|
} else {
|
|
|
|
Utils.getAllContentIds(ses, contentIdsToDelete, itemToDelete, versionHandler);
|
2018-10-25 16:33:23 +02:00
|
|
|
}
|
2019-05-22 17:47:15 +02:00
|
|
|
nodeToDelete.remove();
|
2020-04-14 18:52:59 +02:00
|
|
|
|
2019-05-22 17:47:15 +02:00
|
|
|
log.debug("content ids to remove are {}",contentIdsToDelete);
|
|
|
|
|
2020-03-05 15:39:34 +01:00
|
|
|
//String user = AuthorizationProvider.instance.get().getClient().getId();
|
2019-05-23 14:58:02 +02:00
|
|
|
Runnable deleteFromStorageRunnable = AuthorizedTasks.bind(new Runnable() {
|
2020-04-14 18:52:59 +02:00
|
|
|
|
2019-05-23 14:58:02 +02:00
|
|
|
@Override
|
2018-10-25 16:33:23 +02:00
|
|
|
public void run() {
|
|
|
|
for (String id: contentIdsToDelete) {
|
|
|
|
try {
|
2019-07-05 12:09:16 +02:00
|
|
|
storageHandler.delete(id);
|
2018-10-25 16:33:23 +02:00
|
|
|
log.debug("file with id {} correctly removed on storage",id);
|
|
|
|
}catch(Throwable t) {
|
|
|
|
log.warn("error removing file on storage with id {}",id, t);
|
|
|
|
}
|
|
|
|
}
|
2020-04-14 18:52:59 +02:00
|
|
|
|
2018-10-25 16:33:23 +02:00
|
|
|
}
|
2019-05-23 14:58:02 +02:00
|
|
|
});
|
2020-04-08 21:11:43 +02:00
|
|
|
executor.execute(deleteFromStorageRunnable);
|
2020-04-14 18:52:59 +02:00
|
|
|
|
2018-10-25 16:33:23 +02:00
|
|
|
ses.save();
|
2019-05-23 14:58:02 +02:00
|
|
|
}catch (LockException e) {
|
2019-05-23 15:29:47 +02:00
|
|
|
throw new ItemLockedException("the selected node or his parent is locked", e);
|
2019-05-22 17:47:15 +02:00
|
|
|
}catch (Exception e) {
|
|
|
|
throw new BackendGenericError("error permanetly deleting items",e);
|
2018-10-25 16:33:23 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void moveToTrash(Session ses, Node nodeToDelete, Item item) throws RepositoryException, BackendGenericError{
|
|
|
|
log.debug("moving node {} to trash ",item.getId());
|
2018-12-17 14:55:43 +01:00
|
|
|
final Node trashFolder = ses.getNode(Paths.append(Utils.getWorkspacePath(),Constants.TRASH_ROOT_FOLDER_NAME).toPath());
|
2018-10-25 16:33:23 +02:00
|
|
|
|
|
|
|
final String login = AuthorizationProvider.instance.get().getClient().getId();
|
|
|
|
|
|
|
|
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(AuthorizationProvider.instance.get().getClient().getId());
|
|
|
|
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());
|
|
|
|
|
2020-04-15 17:36:11 +02:00
|
|
|
trashItem.setOwner(login);
|
2018-10-25 16:33:23 +02:00
|
|
|
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");
|
|
|
|
|
2019-02-14 12:01:59 +01:00
|
|
|
Node newTrashItemNode = item2Node.getNode(trashFolder, trashItem);
|
2018-10-25 16:33:23 +02:00
|
|
|
|
|
|
|
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();
|
2019-05-22 17:47:15 +02:00
|
|
|
else log.warn("the AbstractFileItem with id {} has no content (check it!!)", item.getId());
|
2018-10-25 16:33:23 +02:00
|
|
|
}
|
|
|
|
accountingHandler.createFolderRemoveObj(item.getName(), item.getClass().getSimpleName(), mimetype, ses, ses.getNodeByIdentifier(item.getParentId()), true);
|
|
|
|
}catch(Throwable t) {
|
2019-05-22 17:47:15 +02:00
|
|
|
log.error("error exceuting move to trash",t);
|
2018-10-25 16:33:23 +02:00
|
|
|
throw new BackendGenericError(t);
|
|
|
|
}finally {
|
|
|
|
ses.getWorkspace().getLockManager().unlock(nodeToDelete.getPath());
|
|
|
|
ses.getWorkspace().getLockManager().unlock(trashFolder.getPath());
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-04-14 18:52:59 +02:00
|
|
|
public String restoreItem(Session ses, TrashItem item, FolderItem destination) throws RepositoryException, StorageHubException, BackendGenericError{
|
2018-10-25 16:33:23 +02:00
|
|
|
log.debug("restoring node from trash");
|
|
|
|
final String login = AuthorizationProvider.instance.get().getClient().getId();
|
|
|
|
//final Node trashFolder = ses.getNode(Paths.append(Utils.getHomePath(),Constants.TRASH_ROOT_FOLDER_NAME).toPath());
|
2020-04-14 18:52:59 +02:00
|
|
|
|
2020-04-08 21:11:43 +02:00
|
|
|
Node destinationNode= null;
|
2020-04-14 18:52:59 +02:00
|
|
|
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 = Utils.getWorkspacePath(login).toPath();
|
|
|
|
Node node = ses.getNode(homeWS);
|
|
|
|
destinationNode = node;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Node node = ses.getNodeByIdentifier(destination.getId());
|
2020-04-15 17:36:11 +02:00
|
|
|
|
2020-04-14 18:52:59 +02:00
|
|
|
if (!node2Item.checkNodeType(node, FolderItem.class))
|
|
|
|
throw new InvalidCallParameters("destination Node is not a folder");
|
|
|
|
|
2020-04-08 21:11:43 +02:00
|
|
|
destinationNode = node;
|
|
|
|
}
|
2020-04-14 18:52:59 +02:00
|
|
|
|
2020-04-15 17:36:11 +02:00
|
|
|
authChecker.checkWriteAuthorizationControl(ses, destinationNode.getIdentifier(), true );
|
2020-04-14 18:52:59 +02:00
|
|
|
|
2020-04-15 17:36:11 +02:00
|
|
|
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.RESTORED);
|
|
|
|
ses.removeItem(item.getPath());
|
|
|
|
ses.save();
|
|
|
|
}catch (Exception e) {
|
|
|
|
if (ses.getWorkspace().getLockManager().isLocked(destinationNode.getPath()))
|
|
|
|
ses.getWorkspace().getLockManager().unlock(destinationNode.getPath());
|
|
|
|
}
|
2018-10-25 16:33:23 +02:00
|
|
|
return ses.getNode(newNodePath).getIdentifier();
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|