package org.gcube.data.access.storagehub.services; import java.io.BufferedInputStream; import java.io.InputStream; import java.util.Arrays; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import javax.inject.Inject; import javax.jcr.Node; import javax.jcr.Session; import javax.jcr.SimpleCredentials; import javax.servlet.ServletContext; import javax.ws.rs.Consumes; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.PathParam; 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 javax.ws.rs.core.UriInfo; import org.apache.tika.config.TikaConfig; import org.apache.tika.detect.Detector; import org.apache.tika.io.TikaInputStream; import org.apache.tika.metadata.Metadata; import org.gcube.common.authorization.library.provider.AuthorizationProvider; import org.gcube.common.authorization.library.provider.CalledMethodProvider; 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.service.ItemWrapper; import org.gcube.data.access.storagehub.Constants; import org.gcube.data.access.storagehub.MetaInfo; import org.gcube.data.access.storagehub.MultipleOutputStream; import org.gcube.data.access.storagehub.Utils; import org.gcube.data.access.storagehub.handlers.ItemHandler; import org.gcube.data.access.storagehub.handlers.VersionHandler; import org.gcube.data.access.storagehub.handlers.content.ContentHandler; import org.gcube.data.access.storagehub.handlers.content.ContentHandlerFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Path("item") public class ItemsCreator { private static final Logger log = LoggerFactory.getLogger(ItemsCreator.class); private static ExecutorService executor = Executors.newFixedThreadPool(100); @Context ServletContext context; @Inject RepositoryInitializer repository; @Inject ContentHandlerFactory contenthandlerFactory; @Inject VersionHandler versionHandler; @POST @Path("/{id}/create/{type:(?!FILE)[^/?$]*}") public Response createItem(@Context UriInfo uriInfo, @PathParam("id") String id, @PathParam("type") String type){ log.info("create generic item called"); Session ses = null; Item destinationItem = null; try{ final String login = AuthorizationProvider.instance.get().getClient().getId(); long start = System.currentTimeMillis(); //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())); //validate input parameters for Item Type log.info("time to connect to repo {}",(System.currentTimeMillis()-start)); Node destination = ses.getNodeByIdentifier(id); destinationItem = ItemHandler.getItem(destination,Arrays.asList("hl:accounting","jcr:content")); if (!(destinationItem instanceof FolderItem)) throw new Exception("an Item must be copyed to another directory"); //TODO: write control 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 "+destinationItem.getPath()); } //ses.getWorkspace().getLockManager().lock(destinationItem.getPath(), true, true, 0,login); //TODO for now only owner of the destination folder can move file ses.save(); }catch(Exception e){ log.error("error creating item", e); return Response.serverError().build(); } finally{ if (ses!=null){ if (destinationItem!=null) try { ses.getWorkspace().getLockManager().unlock(destinationItem.getPath()); } catch (Throwable t){ log.warn("error unlocking {}", destinationItem.getPath(), t); } ses.logout(); } } return Response.ok().build(); } @POST @Consumes(MediaType.APPLICATION_OCTET_STREAM) @Produces(MediaType.APPLICATION_JSON) @Path("/{id}/create/FILE") public Response createFileItem(InputStream stream , @PathParam("id") String id, @QueryParam("name") String name, @QueryParam("description") String description){ CalledMethodProvider.instance.set("createFileItem"); log.info("create file called"); Session ses = null; Item destinationItem = null; try{ final String login = AuthorizationProvider.instance.get().getClient().getId(); long start = System.currentTimeMillis(); //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())); //validate input parameters for Item Type log.info("time to connect to repo {}",(System.currentTimeMillis()-start)); Node destination = ses.getNodeByIdentifier(id); destinationItem = ItemHandler.getItem(destination,Arrays.asList("hl:accounting","jcr:content")); log.debug("destination item path is {}",destinationItem.getPath()); if (!(destinationItem instanceof FolderItem)) throw new Exception("an Item must be copyed to another directory"); //TODO: write control 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 "+destinationItem.getPath()); } ses.getWorkspace().getLockManager().lock(destinationItem.getPath(), true, true, 0,login); ContentHandler handler = getContentHandler(stream , name, destinationItem.getPath()); AbstractFileItem item =handler.buildItem(name, description, login); log.debug("item prepared, fulfilling content"); log.debug("content prepared"); Node newNode = ItemHandler.createNodeFromItem(ses, destination, item); versionHandler.makeVersionableContent(newNode, ses); ses.save(); versionHandler.checkinContentNode(newNode, ses);; log.info("item correctly created"); return Response.ok(new ItemWrapper<>(item)).build(); }catch(Throwable e){ log.error("error creating item", e); return Response.serverError().build(); } finally{ if (ses!=null){ if (destinationItem!=null) try { ses.getWorkspace().getLockManager().unlock(destinationItem.getPath()); } catch (Throwable t){ log.warn("error unlocking {}", destinationItem.getPath(), t); } ses.logout(); } } } private ContentHandler getContentHandler(InputStream stream , String name, String path) throws Exception { final MultipleOutputStream mos = new MultipleOutputStream(stream, 2); Callable mimeTypeDector = new Callable() { @Override public ContentHandler call() throws Exception { ContentHandler handler =null; try(BufferedInputStream is1 = new BufferedInputStream(mos.get(), 2048)){ org.apache.tika.mime.MediaType mediaType = null; TikaConfig config = TikaConfig.getDefaultConfig(); Detector detector = config.getDetector(); TikaInputStream stream = TikaInputStream.get(is1); Metadata metadata = new Metadata(); metadata.add(Metadata.RESOURCE_NAME_KEY, name); mediaType = detector.detect(stream, metadata); String mimeType = mediaType.getBaseType().toString(); handler = contenthandlerFactory.create(mimeType); is1.reset(); handler.initiliseSpecificContent(is1); handler.getContent().setMimeType(mimeType); } catch (Throwable e) { log.error("error retreiving content",e); throw new RuntimeException(e); } return handler; } }; Callable uploader = new Callable() { @Override public MetaInfo call() throws Exception { String remotePath= path+"/"+name; String storageId = Utils.getStorageClient(AuthorizationProvider.instance.get().getClient().getId()).getClient().put(true).LFile(mos.get()).RFile(remotePath); long size = Utils.getStorageClient(AuthorizationProvider.instance.get().getClient().getId()).getClient().getSize().RFileById(storageId); MetaInfo info = new MetaInfo(); info.setSize(size); info.setStorageId(storageId); return info; } }; Future detectorF = executor.submit(mimeTypeDector); Future uploaderF = executor.submit(uploader); mos.startWriting(); ContentHandler handler = detectorF.get(); handler.getContent().setData("jcr:content"); handler.getContent().setStorageId(uploaderF.get().getStorageId()); handler.getContent().setSize(uploaderF.get().getSize()); return handler; } /* private boolean hasSharedChildren(FolderItem folder, Session session) throws Exception{ Node currentNode = session.getNodeByIdentifier(folder.getId()); for (Item item : Utils.getItemList(currentNode,Arrays.asList("hl:accounting","jcr:content"), null)){ if (item instanceof FolderItem) return (item instanceof SharedFolder) || hasSharedChildren((FolderItem)item, session); } return false; }*/ }