package org.gcube.data.access.storagehub.services; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.UUID; import javax.enterprise.context.RequestScoped; import javax.inject.Inject; import javax.jcr.ItemNotFoundException; import javax.jcr.Node; import javax.jcr.NodeIterator; 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.POST; 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.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status; import org.apache.jackrabbit.api.JackrabbitSession; import org.apache.jackrabbit.api.security.user.User; 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.IdNotFoundException; import org.gcube.common.storagehub.model.exceptions.InvalidCallParameters; import org.gcube.common.storagehub.model.exceptions.StorageHubException; import org.gcube.common.storagehub.model.exceptions.UserNotAuthorizedException; import org.gcube.common.storagehub.model.items.AbstractFileItem; import org.gcube.common.storagehub.model.items.Item; import org.gcube.common.storagehub.model.items.nodes.Owner; import org.gcube.common.storagehub.model.messages.Message; import org.gcube.common.storagehub.model.service.ItemList; import org.gcube.common.storagehub.model.types.ItemAction; import org.gcube.common.storagehub.model.types.MessageList; import org.gcube.common.storagehub.model.types.NodeProperty; import org.gcube.data.access.storagehub.Constants; import org.gcube.data.access.storagehub.PathUtil; import org.gcube.data.access.storagehub.StorageHubAppllicationManager; import org.gcube.data.access.storagehub.Utils; import org.gcube.data.access.storagehub.accounting.AccountingHandler; 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.Item2NodeConverter.Values; import org.gcube.data.access.storagehub.handlers.items.Node2ItemConverter; import org.gcube.data.access.storagehub.handlers.plugins.FolderPluginHandler; import org.gcube.data.access.storagehub.types.MessageSharable; import org.gcube.smartgears.annotations.ManagedBy; import org.gcube.smartgears.utils.InnerMethodName; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Path("messages") @ManagedBy(StorageHubAppllicationManager.class) public class MessageManager extends Impersonable{ private static final Logger log = LoggerFactory.getLogger(MessageManager.class); RepositoryInitializer repository = StorageHubAppllicationManager.repository; @Inject AccountingHandler accountingHandler; @RequestScoped @PathParam("id") String id; @Context ServletContext context; @Inject PathUtil pathUtil; @Inject Node2ItemConverter node2Item; @Inject Item2NodeConverter item2Node; @Inject TrashHandler trashHandler; @GET @Path("{id}") @Produces(MediaType.APPLICATION_JSON) public Message getById(){ InnerMethodName.instance.set("getMessageById"); Session ses = null; Message toReturn = null; try{ ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context)); Node messageNode = ses.getNodeByIdentifier(id); toReturn = node2Item.getMessageItem(messageNode); checkRights(currentUser, toReturn); }catch (ItemNotFoundException e) { log.error("id {} not found",id,e); GXOutboundErrorResponse.throwException(new IdNotFoundException(id, e), Status.NOT_FOUND); }catch(RepositoryException re){ log.error("jcr error getting item", re); GXOutboundErrorResponse.throwException(new BackendGenericError("jcr error getting item", 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; } @DELETE @Path("{id}") public void deleteById(){ InnerMethodName.instance.set("deleteMessageById"); Session ses = null; try{ ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context)); Node messageNode = ses.getNodeByIdentifier(id); Message message = node2Item.getMessageItem(messageNode); Node personalNode = checkRights(currentUser, message); if (countSharedSet(messageNode)>1) personalNode.removeShare(); else { if (message.isWithAttachments()) { Node attachmentNode = messageNode.getNode(Constants.ATTACHMENTNODE_NAME); List attachments = Utils.getItemList(attachmentNode, Excludes.GET_ONLY_CONTENT, null, true, AbstractFileItem.class); trashHandler.removeOnlyNodesContent(ses, attachments); } messageNode.removeSharedSet(); } ses.save(); }catch (ItemNotFoundException e) { log.error("id {} not found",id,e); GXOutboundErrorResponse.throwException(new IdNotFoundException(id, e), Status.NOT_FOUND); }catch(RepositoryException re){ log.error("jcr error getting item", re); GXOutboundErrorResponse.throwException(new BackendGenericError("jcr error getting item", re)); }catch(StorageHubException she ){ log.error(she.getErrorMessage(), she); GXOutboundErrorResponse.throwException(she, Response.Status.fromStatusCode(she.getStatus())); }finally{ if (ses!=null) ses.logout(); } } @GET @Path("{id}/attachments") @Produces(MediaType.APPLICATION_JSON) public ItemList getAttachments(){ InnerMethodName.instance.set("getAttachmentsByMessageId"); Session ses = null; List attachments = new ArrayList<>(); try{ ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context)); Node messageNode = ses.getNodeByIdentifier(id); Message messageItem = node2Item.getMessageItem(messageNode); checkRights(currentUser, messageItem); Node attachmentNode = messageNode.getNode(Constants.ATTACHMENTNODE_NAME); attachments = Utils.getItemList(attachmentNode, Excludes.GET_ONLY_CONTENT, null, true, AbstractFileItem.class); }catch (ItemNotFoundException e) { log.error("id {} not found",id,e); GXOutboundErrorResponse.throwException(new IdNotFoundException(id, e), Status.NOT_FOUND); }catch(RepositoryException re){ log.error("jcr error getting item", re); GXOutboundErrorResponse.throwException(new BackendGenericError("jcr error getting item", 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(attachments); } @GET @Path("inbox") @Produces(MediaType.APPLICATION_JSON) public MessageList getReceivedMessages(@QueryParam("reduceBody") Integer reduceBody){ InnerMethodName.instance.set("getReceivedMessages"); Session ses = null; List toReturn = null; try{ ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context)); Node node = ses.getNode(pathUtil.getInboxPath(currentUser).toPath()); //return sorted for createdTime toReturn = getMessages(node, reduceBody); }catch(RepositoryException re){ log.error("jcr error getting item", re); GXOutboundErrorResponse.throwException(new BackendGenericError("jcr error getting item", re)); }finally{ if (ses!=null) ses.logout(); } return new MessageList(toReturn); } @GET @Path("sent") @Produces(MediaType.APPLICATION_JSON) public MessageList getSentMessages(@QueryParam("reduceBody") Integer reduceBody){ InnerMethodName.instance.set("getSentMessages"); Session ses = null; List toReturn = null; try{ ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context)); Node node = ses.getNode(pathUtil.getOutboxPath(currentUser).toPath()); toReturn = getMessages(node, reduceBody); }catch(RepositoryException re){ log.error("jcr error getting item", re); GXOutboundErrorResponse.throwException(new BackendGenericError("jcr error getting item", re)); }finally{ if (ses!=null) ses.logout(); } return new MessageList(toReturn); } @PUT @Path("{id}/{prop}") @Consumes(MediaType.APPLICATION_JSON) public void setProperty(@PathParam("prop") String property,Object value){ InnerMethodName.instance.set("setPropertyOnMessage("+property+")"); Session ses = null; try{ ses = repository.getRepository().login(CredentialHandler.getAdminCredentials(context)); Node messageNode = ses.getNodeByIdentifier(id); Message messageItem = node2Item.getMessageItem(messageNode); checkRights(currentUser, messageItem); Values val = Item2NodeConverter.getObjectValue(value.getClass(), value); messageNode.setProperty(property, val.getValue()); ses.save(); }catch (ItemNotFoundException e) { log.error("id {} not found",id,e); GXOutboundErrorResponse.throwException(new IdNotFoundException(id, e), Status.NOT_FOUND); }catch(StorageHubException she ){ log.error(she.getErrorMessage(), she); GXOutboundErrorResponse.throwException(she, Response.Status.fromStatusCode(she.getStatus())); }catch( Exception re){ log.error("jcr error getting item", re); GXOutboundErrorResponse.throwException(new BackendGenericError("jcr error getting item", re)); }finally{ if (ses!=null) ses.logout(); } } @POST @Path("send") @Consumes(MediaType.APPLICATION_FORM_URLENCODED) public String sendMessage(@FormParam("to[]") List addresses, @FormParam("subject") String subject, @FormParam("body") String body, @FormParam("attachments[]") List attachments){ InnerMethodName.instance.set("sendMessage"); JackrabbitSession ses = null; String messageId = null; try{ if (addresses.size()==0 || body==null || subject==null) throw new InvalidCallParameters(); log.debug("attachments send are {}",attachments); ses = (JackrabbitSession) repository.getRepository().login(CredentialHandler.getAdminCredentials(context)); Message message = new MessageSharable(); message.setAddresses(addresses.toArray(new String[0])); message.setSubject(subject); message.setBody(body); message.setName(UUID.randomUUID().toString()); User user = ses.getUserManager().getAuthorizable(currentUser, User.class); Owner owner = new Owner(); owner.setUserId(user.getID()); owner.setUserName(user.getPrincipal().getName()); message.setSender(owner); Node outbox = ses.getNode(pathUtil.getOutboxPath(currentUser).toPath()); Node messageNode = item2Node.getNode(outbox, message); ses.save(); if (attachments!=null && !attachments.isEmpty()) { saveAttachments(ses, messageNode, attachments); ses.save(); } for (String to: addresses) try { String userMessagePath = Paths.append(pathUtil.getInboxPath(to), messageNode.getName()).toPath(); ses.getWorkspace().clone(ses.getWorkspace().getName(), messageNode.getPath(), userMessagePath, false); }catch (Exception e) { log.warn("message not send to {}",to,e); } ses.save(); messageId = messageNode.getIdentifier(); }catch(RepositoryException re){ log.error("jcr error getting item", re); GXOutboundErrorResponse.throwException(new BackendGenericError("jcr error getting item", re)); }catch(StorageHubException she ){ log.error(she.getErrorMessage(), she); GXOutboundErrorResponse.throwException(she, Response.Status.fromStatusCode(she.getStatus())); }finally{ if (ses!=null) ses.logout(); } return messageId; } private Node saveAttachments(Session ses, Node messageNode , List attachments) throws RepositoryException, BackendGenericError{ Node attachmentNode = messageNode.getNode(Constants.ATTACHMENTNODE_NAME); for (String itemId: attachments) { Node node = ses.getNodeByIdentifier(itemId); Item item = node2Item.getItem(node, Excludes.GET_ONLY_CONTENT); Node newNode = copyNode(ses, attachmentNode, item); //removes accounting if exists if (newNode.hasNode(NodeProperty.ACCOUNTING.toString())) newNode.getNode(NodeProperty.ACCOUNTING.toString()).remove(); } return messageNode; } //returns Messages sorted by createdTime private List getMessages(Node node, Integer reduceBody) throws RepositoryException{ List messages = new ArrayList(); NodeIterator nodeIt = node.getNodes(); while(nodeIt.hasNext()) { Node child = nodeIt.nextNode(); log.info("message type "+child.getPrimaryNodeType().getName()); Message message = node2Item.getMessageItem(child); if (message == null) { log.info("message discarded"); continue; } if (reduceBody != null && reduceBody>0 && message.getBody().length()>reduceBody ) message.setBody(message.getBody().substring(0, reduceBody)); insertOrdered(messages, message); } return messages; } private void insertOrdered(List messages, Message toInsert) { if (messages.isEmpty()) messages.add(toInsert); else { int i; for ( i=0 ; i