Author: norman
Date: Wed Mar 30 10:44:30 2011
New Revision: 1086901
URL: http://svn.apache.org/viewvc?rev=1086901&view=rev
Log:
Send heartbeats during IDLE to workaround buggy OUTLOOK. This is part of
IMAP-272
Modified:
james/imap/trunk/api/src/main/java/org/apache/james/imap/api/display/HumanReadableText.java
james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/IdleProcessor.java
Modified:
james/imap/trunk/api/src/main/java/org/apache/james/imap/api/display/HumanReadableText.java
URL:
http://svn.apache.org/viewvc/james/imap/trunk/api/src/main/java/org/apache/james/imap/api/display/HumanReadableText.java?rev=1086901&r1=1086900&r2=1086901&view=diff
==============================================================================
---
james/imap/trunk/api/src/main/java/org/apache/james/imap/api/display/HumanReadableText.java
(original)
+++
james/imap/trunk/api/src/main/java/org/apache/james/imap/api/display/HumanReadableText.java
Wed Mar 30 10:44:30 2011
@@ -198,6 +198,8 @@ public class HumanReadableText {
public static final HumanReadableText IDLING = new HumanReadableText(
"org.apache.james.imap.IDLING", "Idling");
+ public static final HumanReadableText HEARTBEAT = new HumanReadableText(
+ "org.apache.james.imap.HEARTBEAT", "Still here");
public static final HumanReadableText DEFLATE_ACTIVE = new
HumanReadableText(
"org.apache.james.imap.DEFLATE", "DEFLATE active");
Modified:
james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/IdleProcessor.java
URL:
http://svn.apache.org/viewvc/james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/IdleProcessor.java?rev=1086901&r1=1086900&r2=1086901&view=diff
==============================================================================
---
james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/IdleProcessor.java
(original)
+++
james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/IdleProcessor.java
Wed Mar 30 10:44:30 2011
@@ -24,6 +24,10 @@ import static org.apache.james.imap.api.
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.james.imap.api.ImapCommand;
@@ -43,13 +47,32 @@ import org.apache.james.mailbox.MailboxM
import org.apache.james.mailbox.MailboxSession;
public class IdleProcessor extends AbstractMailboxProcessor<IdleRequest>
implements CapabilityImplementingProcessor {
+
+
+ private final ScheduledExecutorService heartbeatExecutor;
+
+ private final static String HEARTBEAT_FUTURE = "IDLE_HEARTBEAT_FUTURE";
+ public final static long DEFAULT_HEARTBEAT_INTERVAL = 2;
+ public final static TimeUnit DEFAULT_HEARTBEAT_INTERVAL_UNIT =
TimeUnit.MINUTES;
+ public final static int DEFAULT_SCHEDULED_POOL_CORE_SIZE = 5;
+ private final static String DONE = "DONE";
+ private final TimeUnit heartbeatIntervalUnit;
+ private final long heartbeatInterval;
public IdleProcessor(final ImapProcessor next, final MailboxManager
mailboxManager,
final StatusResponseFactory factory) {
- super(IdleRequest.class, next, mailboxManager, factory);
+ this(next, mailboxManager, factory, DEFAULT_HEARTBEAT_INTERVAL,
DEFAULT_HEARTBEAT_INTERVAL_UNIT,
Executors.newScheduledThreadPool(DEFAULT_SCHEDULED_POOL_CORE_SIZE));
}
+ public IdleProcessor(final ImapProcessor next, final MailboxManager
mailboxManager,
+ final StatusResponseFactory factory, long heartbeatInterval,
TimeUnit heartbeatIntervalUnit, ScheduledExecutorService heartbeatExecutor) {
+ super(IdleRequest.class, next, mailboxManager, factory);
+ this.heartbeatInterval = heartbeatInterval;
+ this.heartbeatIntervalUnit = heartbeatIntervalUnit;
+ this.heartbeatExecutor = heartbeatExecutor;
+
+ }
protected void doProcess(final IdleRequest message, final ImapSession
session,
final String tag, final ImapCommand command, final Responder
responder) {
@@ -84,15 +107,47 @@ public class IdleProcessor extends Abstr
closed.set(true);
session.popLineHandler();
- if (!"DONE".equals(line.toUpperCase(Locale.US))) {
+ if (!DONE.equals(line.toUpperCase(Locale.US))) {
StatusResponse response =
getStatusResponseFactory().taggedBad(tag, command,
HumanReadableText.INVALID_COMMAND);
responder.respond(response);
} else {
okComplete(command, tag, responder);
+
+ // See if we need to cancel the idle heartbeat handling
+ Object oFuture =
session.getAttribute(HEARTBEAT_FUTURE);
+ if (oFuture != null) {
+ ScheduledFuture<?> future =
(ScheduledFuture<?>)oFuture;
+ if (future.cancel(true) == false) {
+ // unable to cancel the future so
better logout now!
+ session.getLog().error("Unable to
disable idle heartbeat for unknown reason! Force logout");
+ session.logout();
+ }
+ }
}
}
});
+
+ // Check if we should send heartbeats
+ if (heartbeatInterval > 0) {
+ ScheduledFuture<?> heartbeatFuture =
heartbeatExecutor.scheduleWithFixedDelay(new Runnable() {
+
+ public void run() {
+ // Send a heartbeat to the client to make sure
we reset the idle timeout. This is kind of the same workaround as dovecot use.
+ //
+ // This is mostly needed because of the broken
outlook client, but can't harm for other clients too.
+ // See IMAP-272
+ StatusResponse response =
getStatusResponseFactory().untaggedOk(HumanReadableText.HEARTBEAT);
+ responder.respond(response);
+ }
+ }, heartbeatInterval, heartbeatInterval, heartbeatIntervalUnit);
+
+ // store future for later usage
+ session.setAttribute(HEARTBEAT_FUTURE, heartbeatFuture);
+ }
+
+
+
} catch (MailboxException e) {
closed.set(true);
// TODO: What should we do here?
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]