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/services/WorkspaceManager.java

426 lines
15 KiB
Java

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;
@Path("/")
@ManagedBy(StorageHubAppllicationManager.class)
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<String> excludes = Collections.emptyList();
@Inject Node2ItemConverter node2Item;
@Inject Item2NodeConverter item2Node;
@Inject
FolderPluginHandler folderHandler;
@Path("/")
@GET
@Produces(MediaType.APPLICATION_JSON)
public ItemWrapper<Item> 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<Item>(toReturn);
}
@Path("vrefolder")
@GET
@Produces(MediaType.APPLICATION_JSON)
public ItemWrapper<Item> 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<Item>(vreItem);
}
@Path("vrefolder/recents")
@GET
@Produces(MediaType.APPLICATION_JSON)
public ItemList getVreFolderRecentsDocument(){
InnerMethodName.instance.set("getVreFolderRecents");
JackrabbitSession ses = null;
List<Item> 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<Item> 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>(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<Item> 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<? extends Item> 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<? extends Item> 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("query")
@GET
@Produces(MediaType.APPLICATION_JSON)
public ItemList searchItems(@QueryParam("n") String node, @QueryParam("e") String jsonExpr, @QueryParam("o") List<String> orderField, @QueryParam("l") Integer limit, @QueryParam("f") Integer offset){
InnerMethodName.instance.set("searchItems");
Session ses = null;
List<? extends Item> toReturn = new ArrayList<>();
try{
ObjectMapper mapper = new ObjectMapper();
Expression<Boolean> expression = mapper.readValue(jsonExpr, Expression.class);
String stringExpression = evaluator.evaluate(new And(new ISDescendant(pathUtil.getWorkspacePath(currentUser)), expression));
String orderBy = "";
if (orderField!=null && orderField.size()>0)
orderBy= String.format("ORDER BY %s", orderField.stream().collect(Collectors.joining(",")).toString());
String sql2Query = String.format("SELECT * FROM [%s] AS node WHERE %s %s ",node, stringExpression,orderBy);
log.info("query sent is {}",sql2Query);
ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context));
Query jcrQuery = ses.getWorkspace().getQueryManager().createQuery(sql2Query, Constants.QUERY_LANGUAGE);
if (limit!=null && limit!=-1 )
jcrQuery.setLimit(limit);
if (offset!=null && offset!=-1 )
jcrQuery.setOffset(offset);
QueryResult result = jcrQuery.execute();
NodeIterator it = result.getNodes();
while (it.hasNext())
toReturn.add(node2Item.getItem(it.nextNode(), null));
}catch(RepositoryException | IOException re ){
log.error("error executing the query", 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();
}
}