package com.google.sitebricks.mail; import com.google.common.collect.Lists; import com.google.common.util.concurrent.SettableFuture; import com.google.sitebricks.mail.imap.Command; import com.google.sitebricks.mail.imap.ExtractionException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.List; /** * A generic command completion listener that aggregates incoming messages * until it forms a complete response to an issued command. * * @author dhanji@gmail.com (Dhanji R. Prasanna) */ class CommandCompletion { private static final Logger log = LoggerFactory.getLogger(CommandCompletion.class); private final SettableFuture<Object> valueFuture; private final List<String> value = Lists.newArrayList(); private final Long sequence; private final Command command; private final String commandString; @SuppressWarnings("unchecked") // Ugly gunk needed to prevent generics from spewing everywhere public CommandCompletion(Command command, Long sequence, SettableFuture<?> valueFuture, String commandString) { this.commandString = commandString; this.valueFuture = (SettableFuture<Object>) valueFuture; this.sequence = sequence; this.command = command; } public void error(String message, Exception e) { StringBuilder builder = new StringBuilder(); for (String piece : value) { builder.append(piece).append('\n'); } log.error("Exception while processing response:\n Command: {} (seq: {})\n\n--message follows--" + "\n{}\n--message end--\n--context follows--\n{}\n--context end--\n\n", new Object[] { commandString, sequence, message, builder.toString(), e }); // TODO Send this back to the client as an exception so it can be handled correctly. valueFuture.setException(new MailHandlingException(value, message, e)); } public boolean complete(String message) { value.add(message); // Base case (empty/newline message). if (message.isEmpty()) { return false; } try { if (Command.isEndOfSequence(sequence, message.toLowerCase())) { // Once we see the OK message, we should process the data and return. valueFuture.set(command.extract(value)); return true; } } catch(ExtractionException ee) { valueFuture.setException(ee); return true; } return false; } @Override public String toString() { return commandString; } }