package org.gcube.data.access.storagehub.services; import java.util.Collections; import java.util.List; import javax.enterprise.context.RequestScoped; import javax.inject.Inject; import javax.jcr.Node; 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.PUT; import javax.ws.rs.Path; 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 org.apache.jackrabbit.api.JackrabbitSession; 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.InvalidCallParameters; import org.gcube.common.storagehub.model.exceptions.InvalidItemException; import org.gcube.common.storagehub.model.exceptions.StorageHubException; import org.gcube.common.storagehub.model.exceptions.UserNotAuthorizedException; 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.service.ItemList; import org.gcube.common.storagehub.model.service.ItemWrapper; import org.gcube.data.access.storagehub.AuthorizationChecker; import org.gcube.data.access.storagehub.Constants; import org.gcube.data.access.storagehub.PathUtil; import org.gcube.data.access.storagehub.Range; import org.gcube.data.access.storagehub.StorageHubAppllicationManager; import org.gcube.data.access.storagehub.Utils; 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.Node2ItemConverter; import org.gcube.data.access.storagehub.handlers.items.builders.FolderCreationParameters; import org.gcube.data.access.storagehub.handlers.plugins.FolderPluginHandler; import org.gcube.data.access.storagehub.handlers.vres.VRE; import org.gcube.data.access.storagehub.handlers.vres.VREManager; import org.gcube.data.access.storagehub.query.sql2.evaluators.Evaluators; import org.gcube.smartgears.annotations.ManagedBy; import org.gcube.smartgears.utils.InnerMethodName; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.webcohesion.enunciate.metadata.rs.RequestHeader; import com.webcohesion.enunciate.metadata.rs.RequestHeaders; @Path("/") @ManagedBy(StorageHubAppllicationManager.class) @RequestHeaders({ @RequestHeader( name = "Authorization", description = "Bearer token, see https://dev.d4science.org/how-to-access-resources"), }) public class WorkspaceManager extends Impersonable{ private static final Logger log = LoggerFactory.getLogger(WorkspaceManager.class); RepositoryInitializer repository = StorageHubAppllicationManager.repository; @Inject Evaluators evaluator; @Inject PathUtil pathUtil; @Inject VREManager vreManager; @Context ServletContext context; @Inject AuthorizationChecker authChecker; @Inject TrashHandler trashHandler; @RequestScoped @QueryParam("exclude") private List excludes = Collections.emptyList(); @Inject Node2ItemConverter node2Item; @Inject Item2NodeConverter item2Node; @Inject FolderPluginHandler folderHandler; @Path("/") @GET @Produces(MediaType.APPLICATION_JSON) public ItemWrapper getWorkspace(@QueryParam("relPath") String relPath){ InnerMethodName.instance.set("getWorkspace"); Session ses = null; org.gcube.common.storagehub.model.Path absolutePath; if (relPath==null) absolutePath = pathUtil.getWorkspacePath(currentUser); else absolutePath = Paths.append(pathUtil.getWorkspacePath(currentUser), relPath); Item toReturn = null; try{ ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context)); //TODO: remove when all user will have TRASH org.gcube.common.storagehub.model.Path trashPath = pathUtil.getTrashPath(currentUser, ses); if (!ses.nodeExists(trashPath.toPath())) { Node wsNode = ses.getNode(pathUtil.getWorkspacePath(currentUser).toPath()); FolderCreationParameters trashFolderParameters = FolderCreationParameters.builder().name(Constants.TRASH_ROOT_FOLDER_NAME) .description("trash of "+currentUser) .author(currentUser).on(wsNode.getIdentifier()).with(ses).build(); Utils.createFolderInternally(trashFolderParameters, null); ses.save(); } Node node = ses.getNode(absolutePath.toPath()); authChecker.checkReadAuthorizationControl(ses, currentUser, node.getIdentifier()); toReturn = node2Item.getItem(node, excludes); }catch(RepositoryException re ){ log.error("jcr error getting workspace item", re); GXOutboundErrorResponse.throwException(new BackendGenericError(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 ItemWrapper(toReturn); } @Path("vrefolder") @GET @Produces(MediaType.APPLICATION_JSON) public ItemWrapper getVreRootFolder(){ InnerMethodName.instance.set("getVreRootFolder"); JackrabbitSession ses = null; Item vreItem = null; try { ses = (JackrabbitSession) repository.getRepository().login(CredentialHandler.getAdminCredentials(context)); vreItem = vreManager.getVreFolderItem(ses, currentUser, excludes).getVreFolder(); }catch(RepositoryException re ){ log.error("jcr error getting vrefolder", re); GXOutboundErrorResponse.throwException(new BackendGenericError(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 ItemWrapper(vreItem); } @Path("vrefolder/recents") @GET @Produces(MediaType.APPLICATION_JSON) public ItemList getVreFolderRecentsDocument(){ InnerMethodName.instance.set("getVreFolderRecents"); JackrabbitSession ses = null; List recentItems = Collections.emptyList(); try{ ses = (JackrabbitSession) repository.getRepository().login(CredentialHandler.getAdminCredentials(context)); VRE vre = vreManager.getVreFolderItem(ses, currentUser, excludes); log.trace("VRE retrieved {}",vre.getVreFolder().getTitle()); recentItems = vre.getRecents(); log.trace("recents retrieved {}",vre.getVreFolder().getTitle()); return new ItemList(recentItems); }catch(RepositoryException re ){ log.error("jcr error getting recents", re); GXOutboundErrorResponse.throwException(new BackendGenericError(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(recentItems); } @Path("trash") @GET @Produces(MediaType.APPLICATION_JSON) public ItemWrapper getTrashRootFolder(){ InnerMethodName.instance.set("getTrashRootFolder"); Session ses = null; Item item = null; try{ long start = System.currentTimeMillis(); ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context)); org.gcube.common.storagehub.model.Path trashPath = pathUtil.getTrashPath(currentUser, ses); log.info("time to connect to repo {}",(System.currentTimeMillis()-start)); Node folder = ses.getNode(trashPath.toPath()); item = node2Item.getItem(folder, excludes); }catch(RepositoryException re ){ log.error("jcr error getting trash", re); GXOutboundErrorResponse.throwException(new BackendGenericError(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 ItemWrapper(item); } @Path("trash/empty") @DELETE public String emptyTrash(){ InnerMethodName.instance.set("emptyTrash"); Session ses = null; String toReturn = null; try{ ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context)); org.gcube.common.storagehub.model.Path trashPath = pathUtil.getTrashPath(currentUser, ses); Node trashNode = ses.getNode(trashPath.toPath()); List itemsToDelete = Utils.getItemList(trashNode, Excludes.ALL, null, true, null); trashHandler.removeNodes(ses, itemsToDelete); toReturn = trashNode.getIdentifier(); }catch(RepositoryException re ){ log.error("jcr error emptying trash", re); GXOutboundErrorResponse.throwException(new BackendGenericError(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; } @PUT @Consumes(MediaType.APPLICATION_FORM_URLENCODED) @Path("trash/restore") public String restoreItem(@FormParam("trashedItemId") String trashedItemId,@FormParam("destinationId") String destinationFolderId){ InnerMethodName.instance.set("restoreItem"); Session ses = null; String toReturn = null; try{ log.info("restoring node with id {}", trashedItemId); ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context)); final Node nodeToRestore = ses.getNodeByIdentifier(trashedItemId); Item itemToRestore = node2Item.getItem(nodeToRestore, Excludes.ALL); if (!(itemToRestore instanceof TrashItem)) throw new InvalidItemException("Only trash items can be restored"); org.gcube.common.storagehub.model.Path trashPath = pathUtil.getTrashPath(currentUser, ses); if (!itemToRestore.getPath().startsWith(trashPath.toPath())) throw new UserNotAuthorizedException("this item is not in the user "+currentUser+" trash"); Item destinationItem = null; if (destinationFolderId!=null ) { destinationItem = node2Item.getItem(ses.getNodeByIdentifier(destinationFolderId), Excludes.ALL); if (!(destinationItem instanceof FolderItem)) throw new InvalidCallParameters("destintation item is not a folder"); toReturn = trashHandler.restoreItem(ses, (TrashItem)itemToRestore, (FolderItem) destinationItem, currentUser); } else toReturn = trashHandler.restoreItem(ses, (TrashItem)itemToRestore, null, currentUser); }catch(RepositoryException re ){ log.error("error restoring item with id {}",trashedItemId, re); GXOutboundErrorResponse.throwException(new BackendGenericError(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; } @Path("vrefolders") @GET @Produces(MediaType.APPLICATION_JSON) public ItemList getVreFolders(){ InnerMethodName.instance.set("getVreFolders"); Session ses = null; List toReturn = null; org.gcube.common.storagehub.model.Path vrePath = null; try{ ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context)); vrePath = pathUtil.getVREsPath(currentUser, ses); log.info("vres folder path is {}",vrePath.toPath()); toReturn = Utils.getItemList(ses.getNode(vrePath.toPath()) , excludes, null, false, null); }catch(RepositoryException re ){ log.error("error reading the node children of {}",vrePath, re); GXOutboundErrorResponse.throwException(new BackendGenericError(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(toReturn); } @Path("vrefolders/paged") @GET @Produces(MediaType.APPLICATION_JSON) public ItemList getVreFoldersPaged(@QueryParam("start") Integer start, @QueryParam("limit") Integer limit){ InnerMethodName.instance.set("getVreFoldersPaged"); Session ses = null; org.gcube.common.storagehub.model.Path vrePath = null; List toReturn = null; try{ ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context)); vrePath = pathUtil.getVREsPath(currentUser, ses); toReturn = Utils.getItemList(ses.getNode(vrePath.toPath()) , excludes, new Range(start, limit), false, null); }catch(RepositoryException re ){ log.error("(paged) error reading the node children of {}",vrePath, re); GXOutboundErrorResponse.throwException(new BackendGenericError(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(toReturn); } @Path("count") @GET public String getTotalItemsCount(){ InnerMethodName.instance.set("getTotalItemsCount"); return folderHandler.getDefault().getStorageBackend().getTotalItemsCount(); } @Path("size") @GET public String getTotalVolume(){ InnerMethodName.instance.set("getTotalSize"); return folderHandler.getDefault().getStorageBackend().getTotalSizeStored(); } }