storagehub/src/main/java/org/gcube/data/access/storagehub/services/ItemsManager.java

321 lines
12 KiB
Java

package org.gcube.data.access.storagehub.services;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.Arrays;
import java.util.Deque;
import java.util.List;
import java.util.zip.Deflater;
import java.util.zip.ZipOutputStream;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.jcr.Node;
import javax.jcr.Session;
import javax.jcr.SimpleCredentials;
import javax.servlet.ServletContext;
import javax.ws.rs.GET;
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.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.StreamingOutput;
import org.gcube.common.authorization.library.provider.AuthorizationProvider;
import org.gcube.common.storagehub.model.Paths;
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.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.Range;
import org.gcube.data.access.storagehub.SingleFileStreamingOutput;
import org.gcube.data.access.storagehub.Utils;
import org.gcube.data.access.storagehub.accounting.AccountingHandler;
import org.gcube.data.access.storagehub.handlers.ItemHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Path("item")
public class ItemsManager {
private static final Logger log = LoggerFactory.getLogger(ItemsManager.class);
@Inject
RepositoryInitializer repository;
@Inject
AccountingHandler accountingHandler;
@RequestScoped
@PathParam("id")
String id;
@Context
ServletContext context;
@Inject
AuthorizationChecker authChecker;
@GET()
@Path("{id}")
@Produces(MediaType.APPLICATION_JSON)
public ItemWrapper<Item> getById(@QueryParam("exclude") List<String> excludes){
Session ses = null;
Item toReturn = null;
try{
String login = AuthorizationProvider.instance.get().getClient().getId();
long start = System.currentTimeMillis();
ses = repository.getRepository().login(new SimpleCredentials(login,Utils.getSecurePassword(login).toCharArray()));
authChecker.checkReadAuthorizationControl(ses, id);
log.info("time to connect to repo {}",(System.currentTimeMillis()-start));
log.info("excludes is {}",excludes);
toReturn = ItemHandler.getItem(ses.getNodeByIdentifier(id), excludes);
}catch(Throwable e){
log.error("error reading the node children of {}",id,e);
throw new WebApplicationException(e);
}finally{
if (ses!=null)
ses.logout();
}
return new ItemWrapper<Item>(toReturn);
}
@GET
@Path("{id}/children/count")
@Produces(MediaType.APPLICATION_JSON)
public Long countById(@QueryParam("showHidden") Boolean showHidden, @QueryParam("exclude") List<String> excludes){
Session ses = null;
Long toReturn = null;
try{
String login = AuthorizationProvider.instance.get().getClient().getId();
long start = System.currentTimeMillis();
ses = repository.getRepository().login(new SimpleCredentials(login,Utils.getSecurePassword(login).toCharArray()));
authChecker.checkReadAuthorizationControl(ses, id);
log.info("time to connect to repo {}",(System.currentTimeMillis()-start));
log.info("excludes is {}",excludes);
toReturn = Utils.getItemCount(ses.getNodeByIdentifier(id), showHidden==null?false:showHidden);
}catch(Throwable e){
log.error("error reading the node children of {}",id,e);
throw new WebApplicationException(e);
}finally{
if (ses!=null)
ses.logout();
}
return toReturn ;
}
@GET
@Path("{id}/children")
@Produces(MediaType.APPLICATION_JSON)
public ItemList listById(@QueryParam("showHidden") Boolean showHidden, @QueryParam("exclude") List<String> excludes){
Session ses = null;
List<? extends Item> toReturn = null;
try{
String login = AuthorizationProvider.instance.get().getClient().getId();
long start = System.currentTimeMillis();
ses = repository.getRepository().login(new SimpleCredentials(login,Utils.getSecurePassword(login).toCharArray()));
authChecker.checkReadAuthorizationControl(ses, id);
log.info("time to connect to repo {}",(System.currentTimeMillis()-start));
log.info("excludes is {}",excludes);
toReturn = Utils.getItemList(ses.getNodeByIdentifier(id), excludes, null, showHidden==null?false:showHidden);
}catch(Throwable e){
log.error("error reading the node children of {}",id,e);
throw new WebApplicationException(e);
}finally{
if (ses!=null)
ses.logout();
}
return new ItemList(toReturn);
}
@GET
@Path("{id}/children/paged")
@Produces(MediaType.APPLICATION_JSON)
public ItemList listByIdPaged(@QueryParam("showHidden") Boolean showHidden, @QueryParam("start") Integer start, @QueryParam("limit") Integer limit, @QueryParam("exclude") List<String> excludes){
Session ses = null;
List<? extends Item> toReturn = null;
try{
String login = AuthorizationProvider.instance.get().getClient().getId();
ses = repository.getRepository().login(new SimpleCredentials(login,Utils.getSecurePassword(login).toCharArray()));
authChecker.checkReadAuthorizationControl(ses, id);
log.info("time to connect to repo {}",(System.currentTimeMillis()-start));
log.info("excludes is {}",excludes);
toReturn = Utils.getItemList(ses.getNodeByIdentifier(id), excludes, new Range(start, limit),showHidden==null?false:showHidden);
}catch(Throwable e){
log.error("error reading the node children of {}",id,e);
throw new WebApplicationException(e);
}finally{
if (ses!=null)
ses.logout();
}
return new ItemList(toReturn);
}
@GET
@Path("{id}/publiclink")
public URL getPubliclink() {
//TODO: check who can call this method
Session ses = null;
try{
String login = AuthorizationProvider.instance.get().getClient().getId();
ses = repository.getRepository().login(new SimpleCredentials(login,Utils.getSecurePassword(login).toCharArray()));
authChecker.checkReadAuthorizationControl(ses, id);
String url = Utils.getStorageClient(login).getClient().getHttpsUrl().RFileById(id);
return new URL(url);
}catch(Throwable e){
log.error("error reading the node children of {}",id,e);
throw new WebApplicationException(e);
}finally{
if (ses!=null)
ses.logout();
}
}
@GET
@Path("{id}/download")
public Response download(){
Session ses = null;
try{
final String login = AuthorizationProvider.instance.get().getClient().getId();
long start = System.currentTimeMillis();
ses = repository.getRepository().login(new SimpleCredentials(context.getInitParameter(Constants.ADMIN_PARAM_NAME),context.getInitParameter(Constants.ADMIN_PARAM_PWD).toCharArray()));
log.info("time to connect to repo {}",(System.currentTimeMillis()-start));
final Node node = ses.getNodeByIdentifier(id);
authChecker.checkReadAuthorizationControl(ses, id);
final Item item = ItemHandler.getItem(node, null);
if (item instanceof AbstractFileItem){
AbstractFileItem fileItem =(AbstractFileItem) item;
final InputStream streamToWrite = Utils.getStorageClient(login).getClient().get().RFileAsInputStream(fileItem.getContent().getStorageId());
accountingHandler.createReadObj(fileItem.getTitle(), ses, node, true);
StreamingOutput so = new SingleFileStreamingOutput(streamToWrite);
return Response
.ok(so)
.header("content-disposition","attachment; filename = "+fileItem.getName())
.header("Content-Length", fileItem.getContent().getSize())
.build();
} else if (item instanceof FolderItem){
try {
final Deque<Item> allNodes = Utils.getAllNodesForZip((FolderItem)item, ses, accountingHandler);
final org.gcube.common.storagehub.model.Path originalPath = Paths.getPath(item.getPath());
StreamingOutput so = new StreamingOutput() {
@Override
public void write(OutputStream os) {
try(ZipOutputStream zos = new ZipOutputStream(os)){
long start = System.currentTimeMillis();
zos.setLevel(Deflater.BEST_COMPRESSION);
log.debug("writing StreamOutput");
Utils.zipNode(zos, allNodes, login, originalPath);
log.debug("StreamOutput written in {}",(System.currentTimeMillis()-start));
} catch (Exception e) {
log.error("error writing stream",e);
}
}
};
return Response
.ok(so)
.header("content-disposition","attachment; filename = directory.zip")
.header("Content-Length", -1l)
.build();
}finally {
if (ses!=null) ses.save();
}
} else throw new Exception("item type not supported for download: "+item.getClass());
}catch(Exception e ){
log.error("error downloading item content",e);
throw new WebApplicationException(e);
} finally{
if (ses!=null) ses.logout();
}
}
@PUT
@Path("{id}/move")
public Response move(@QueryParam("newpath") String path, @PathParam("id") String identifier){
Session ses = null;
try{
final String login = AuthorizationProvider.instance.get().getClient().getId();
long start = System.currentTimeMillis();
//ses = RepositoryInitializer.getRepository().login(new SimpleCredentials(login,Utils.getSecurePassword(login).toCharArray()));
//TODO check if it is possible to change all the ACL on a workspace
ses = repository.getRepository().login(new SimpleCredentials(context.getInitParameter(Constants.ADMIN_PARAM_NAME),context.getInitParameter(Constants.ADMIN_PARAM_PWD).toCharArray()));
authChecker.checkReadAuthorizationControl(ses, id);
log.info("time to connect to repo {}",(System.currentTimeMillis()-start));
final Node nodeToMove = ses.getNodeByIdentifier(identifier);
final Node destination = ses.getNode(path);
Item destinationItem = ItemHandler.getItem(destination,null);
//TODO for now only owner of the destination folder can move file
if (!destinationItem.getOwner().equals(login)){
/*AccessControlManager accessControlManager = ses.getAccessControlManager();
boolean canWrite = accessControlManager.hasPrivileges(path, new Privilege[] {
accessControlManager.privilegeFromName(Privilege.JCR_ADD_CHILD_NODES)});*/
//if (!canWrite)
throw new IllegalAccessException("Insufficent Provileges to write in "+path);
}
final Item item = ItemHandler.getItem(nodeToMove, null);
if (item instanceof SharedFolder){
throw new Exception("shared folder cannot be moved");
}else if (item instanceof FolderItem){
if (hasSharedChildren((FolderItem) item, ses)) throw new Exception("folder item with shared children cannot be moved");
ses.getWorkspace().move(nodeToMove.getPath(), destination.getPath()+"/"+nodeToMove.getName());
}else {
item.setParentId(destinationItem.getId());
ses.getWorkspace().move(nodeToMove.getPath(), destination.getPath()+"/"+nodeToMove.getName());
}
ses.save();
}catch(Exception e){
log.error("error moving item with id {} in path {}",identifier, path,e);
throw new WebApplicationException(e);
} finally{
if (ses!=null) ses.logout();
}
return Response.ok().build();
}
private boolean hasSharedChildren(FolderItem item, Session session) throws Exception{
Node currentNode = session.getNodeByIdentifier(item.getId());
for (Item children : Utils.getItemList(currentNode,Arrays.asList("hl:accounting","jcr:content"), null, false)){
if (children instanceof FolderItem)
return (children instanceof SharedFolder) || hasSharedChildren((FolderItem)item, session);
}
return false;
}
}