You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by no...@apache.org on 2011/03/30 12:44:31 UTC

svn commit: r1086901 - in /james/imap/trunk: api/src/main/java/org/apache/james/imap/api/display/HumanReadableText.java processor/src/main/java/org/apache/james/imap/processor/IdleProcessor.java

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: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org