@Override public void delete(final Mailbox mailbox) throws IOException { // purge all previously deleted objects // TODO: we should not instantiate here MessageDAO messageDAO = new CassandraMessageDAO(keyspace); messageDAO.purge(mailbox, new Date()); // delete all objects from object store try { List<UUID> messageIds = null; UUID start = null; // loop until we delete all items do { // get all message ids messageIds = LabelIndexPersistence.get( mailbox.getId(), ReservedLabels.ALL_MAILS.getId(), start, BatchConstants.BATCH_READS, true); // get all message headers Map<UUID, Message> messages = MessagePersistence.fetch(mailbox.getId(), messageIds, false); // delete message sources from object store for (UUID messageId : messages.keySet()) { blobStorage.delete(messages.get(messageId).getLocation()); } // set start element for the next loop start = messageIds.isEmpty() ? null : messageIds.get(messageIds.size() - 1); } while (messageIds.size() >= BatchConstants.BATCH_READS); } catch (Exception e) { throw new IOException(e); } // begin batch operation Mutator<String> m = createMutator(keyspace, strSe); // delete all MessageMetadata MessagePersistence.deleteAllMessages(m, mailbox.getId()); // delete all indexes from IndexLabel LabelIndexPersistence.deleteIndexes(m, mailbox.getId()); // delete all counters LabelCounterPersistence.deleteAll(m, mailbox.getId()); // delete Account data AccountPersistence.delete(m, mailbox.getId()); // commit batch operation m.execute(); }
/** * Delete multiple messages * * @param account * @param requestJSONContent JSON array of message UUIDs e.g. [uuid1, uuid2, ...] * @return */ @DELETE @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) public Response deleteMessages( @PathParam("user") final String user, @PathParam("domain") final String domain, final String requestJSONContent) { Mailbox mailbox = new Mailbox(user, domain); List<UUID> messageIds = null; try { messageIds = JSONUtils.toUUIDList(requestJSONContent); } catch (IllegalStateException jpe) { logger.info("Malformed JSON request: {}", jpe.getMessage()); throw new BadRequestException("Malformed JSON request"); } if (messageIds == null || messageIds.isEmpty()) throw new BadRequestException("Malformed JSON request"); try { // delete message and ignore other parameters messageDAO.delete(mailbox, messageIds); } catch (Exception e) { logger.error("Message deletion failed: ", e); throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR); } return Response.noContent().build(); }
/** * Modify multiple messages' labels and markers * * @param account * @param addLabels * @param removeLabels * @param addMarkers * @param removeMarkers * @param requestJSONContent JSON array of message UUIDs e.g. [uuid1, uuid2, ...] * @return */ @PUT @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) public Response modifyMessages( @PathParam("user") final String user, @PathParam("domain") final String domain, @QueryParam("addlabel") final Set<Integer> addLabels, @QueryParam("removelabel") final Set<Integer> removeLabels, @QueryParam("addmarker") final Set<Marker> addMarkers, @QueryParam("removemarker") final Set<Marker> removeMarkers, final String requestJSONContent) { Mailbox mailbox = new Mailbox(user, domain); List<UUID> messageIds = null; try { messageIds = JSONUtils.toUUIDList(requestJSONContent); } catch (IllegalStateException jpe) { logger.info("Malformed JSON request: {}", jpe.getMessage()); throw new BadRequestException("Malformed JSON request"); } if (messageIds == null || messageIds.isEmpty()) throw new BadRequestException("Malformed JSON request"); try { // TODO: make batch request // add labels to message messageDAO.addLabel(mailbox, addLabels, messageIds); // remove label from message messageDAO.removeLabel(mailbox, removeLabels, messageIds); // add marker messageDAO.addMarker(mailbox, addMarkers, messageIds); // remove marker messageDAO.removeMarker(mailbox, removeMarkers, messageIds); } catch (IllegalLabelException ile) { throw new BadRequestException(ile.getMessage()); } catch (Exception e) { logger.error("Message modifications failed: ", e); throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR); } return Response.noContent().build(); }
/** * Add/store new message with given labels and markers * * @param account * @param labels automatically assigned labels * @param markers automatically assigned markers * @param file * @return */ @POST @Produces(MediaType.APPLICATION_JSON) public Response addMessage( @PathParam("user") final String user, @PathParam("domain") final String domain, @QueryParam("label") Set<Integer> labels, @QueryParam("marker") Set<Marker> markers, File file) { Mailbox mailbox = new Mailbox(user, domain); // generate new UUID UUID messageId = new MessageIdBuilder().build(); try { FileInputStream in = new FileInputStream(file); MimeParser parser = new MimeParser(); // parse message parser.parse(in); Message message = parser.getMessage(); message.setSize(file.length()); // update message size in.close(); // add labels to message for (Integer label : labels) { message.addLabel(label); } // add markers to message for (Marker marker : markers) { message.addMarker(marker); } // store message in = new FileInputStream(file); messageDAO.put(mailbox, messageId, message, in); in.close(); } catch (MimeParserException mpe) { logger.error("Unable to parse message: ", mpe); throw new BadRequestException("Parsing error. Invalid MIME message."); } catch (OverQuotaException oqe) { throw new WebApplicationException( Response.status(Status.NOT_ACCEPTABLE) .entity(oqe.getMessage()) .type("text/plain") .build()); } catch (IOException ioe) { logger.error("Unable to read message stream: ", ioe); throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR); } catch (IllegalArgumentException e) { throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR); } catch (Exception e) { // HectorException throw new WebApplicationException(e, Response.Status.INTERNAL_SERVER_ERROR); } finally { if (file.exists()) { file.delete(); } } // build response URI messageUri = uriInfo.getAbsolutePathBuilder().path(messageId.toString()).build(); String responseJson = new StringBuilder("{\"id\":\"").append(messageId).append("\"}").toString(); return Response.created(messageUri).entity(responseJson).build(); }
@Override public Map<MailAddress, DeliveryReturnCode> deliver(MailEnvelope env, final String deliveryId) throws IOException { StopWatch stopWatch = Activator.getDefault().getStopWatch(); Message message; try { MimeParser parser = new MimeParser(); parser.parse(env.getMessageInputStream()); message = parser.getMessage(); } catch (MimeParserException mpe) { logger.error("DID" + deliveryId + ": unable to parse message: ", mpe); throw new DeliveryException("Unable to parse message: " + mpe.getMessage()); } catch (IOException ioe) { logger.error("DID" + deliveryId + ": unable to read message stream: ", ioe); throw new DeliveryException("Unable to read message stream: " + ioe.getMessage()); } message.setSize((long) env.getSize()); // update message size message.addLabel(ReservedLabels.INBOX.getId()); // default location logEnvelope(env, message, deliveryId); Map<MailAddress, DeliveryReturnCode> replies = new HashMap<MailAddress, DeliveryReturnCode>(); // Deliver to each recipient for (MailAddress recipient : env.getRecipients()) { DeliveryReturnCode reply = DeliveryReturnCode.TEMPORARY_FAILURE; // default LMTP reply DeliveryAction deliveryAction = DeliveryAction.DELIVER; // default delivery action Mailbox mailbox = new Mailbox(recipient.toString()); String logMsg = new StringBuilder(" ") .append(mailbox.getId()) .append(" DID") .append(deliveryId) .toString(); try { switch (deliveryAction) { case DELIVER: try { // generate new UUID UUID messageId = new MessageIdBuilder().build(); // store message messageDAO.put(mailbox, messageId, message, env.getMessageInputStream()); // successfully delivered stopWatch.stop("DELIVERY.success", logMsg); reply = DeliveryReturnCode.OK; } catch (OverQuotaException e) { // account is over quota, reject stopWatch.stop("DELIVERY.reject_overQuota", logMsg + " over quota"); reply = DeliveryReturnCode.OVER_QUOTA; } catch (IOException e) { // delivery error, defer stopWatch.stop("DELIVERY.defer", logMsg); logger.error("DID" + deliveryId + ": delivery error: ", e); reply = DeliveryReturnCode.TEMPORARY_FAILURE; } break; case DISCARD: // Local delivery is disabled. stopWatch.stop("DELIVERY.discard", logMsg); reply = DeliveryReturnCode.OK; break; case DEFER: // Delivery to mailbox skipped. Let MTA retry again later. stopWatch.stop("DELIVERY.defer", logMsg); reply = DeliveryReturnCode.TEMPORARY_FAILURE; break; case REJECT: // Reject delivery. Account or mailbox not found. stopWatch.stop("DELIVERY.reject_nonExistent", logMsg + " unknown mailbox"); reply = DeliveryReturnCode.NO_SUCH_USER; } } catch (Exception e) { stopWatch.stop("DELIVERY.defer_failure", logMsg); reply = DeliveryReturnCode.TEMPORARY_FAILURE; logger.error("DID" + deliveryId + ": delivery failed (defered): ", e); } replies.put(recipient, reply); // set delivery status for invoker } return replies; }