You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by ng...@apache.org on 2010/08/16 22:28:52 UTC

svn commit: r986126 - in /mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124: BoshBackedSessionContext.java BoshHandler.java

Author: ngn
Date: Mon Aug 16 20:28:52 2010
New Revision: 986126

URL: http://svn.apache.org/viewvc?rev=986126&view=rev
Log:
Adding support for detecting inactivity (VYSPER-240, by Bogdan Pistol)
Adding support for pause (VYSPER-241, by Bogdan Pistol)

Modified:
    mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshBackedSessionContext.java
    mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshHandler.java

Modified: mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshBackedSessionContext.java
URL: http://svn.apache.org/viewvc/mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshBackedSessionContext.java?rev=986126&r1=986125&r2=986126&view=diff
==============================================================================
--- mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshBackedSessionContext.java (original)
+++ mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshBackedSessionContext.java Mon Aug 16 20:28:52 2010
@@ -22,6 +22,8 @@ package org.apache.vysper.xmpp.extension
 import java.util.LinkedList;
 import java.util.Queue;
 import java.util.SortedMap;
+import java.util.Timer;
+import java.util.TimerTask;
 import java.util.TreeMap;
 
 import org.apache.vysper.xml.fragment.Renderer;
@@ -48,6 +50,8 @@ public class BoshBackedSessionContext ex
     private final static Logger LOGGER = LoggerFactory.getLogger(BoshBackedSessionContext.class);
 
     private final BoshHandler boshHandler;
+    
+    private final int maxpause = 120;
 
     private final int inactivity = 60;
 
@@ -91,6 +95,8 @@ public class BoshBackedSessionContext ex
 
     private int hold = 1;
     
+    private int currentInactivity = inactivity;
+    
     /*
      * The highest RID that can be read and processed, this is the highest (rightmost) contiguous RID.
      * The requests from the client can come theoretically with missing updates:
@@ -107,6 +113,14 @@ public class BoshBackedSessionContext ex
      * attribute in any request is meaningful.
      */
     private boolean clientAcknowledgements;
+    
+    /*
+     * The timestamp of the latest response wrote to the client is used to measure the inactivity period.
+     * When reaching the maximum inactivity the session will automatically close.
+     */
+    private long latestWriteTimestamp = System.currentTimeMillis();
+    
+    private Timer inactivityChecker = new Timer(true);
 
     /**
      * Creates a new context for a session
@@ -126,6 +140,25 @@ public class BoshBackedSessionContext ex
     }
     
     /**
+     * Periodically checks if the session reached the maximum inactivity period.
+     */
+    public void startInactivityChecker() {
+        inactivityChecker.schedule(new TimerTask() {
+            
+            @Override
+            public void run() {
+                synchronized (BoshBackedSessionContext.this) {
+                    if (System.currentTimeMillis() - latestWriteTimestamp >= currentInactivity * 1000 && requestsWindow.isEmpty()) {
+                        LOGGER.info("BOSH session reached maximum inactivity period, closing session...");
+                        close();
+                    }
+                }
+            }
+            
+        }, 1000, 1000);
+    }
+    
+    /**
      * Returns the highest RID that is received in a continuous (uninterrupted) sequence of RIDs.
      * Higher RIDs can exist with gaps separating them from the highestReadRid.
      * @return the highest continuous RID received so far
@@ -189,6 +222,7 @@ public class BoshBackedSessionContext ex
         Continuation continuation = ContinuationSupport.getContinuation(req.getHttpServletRequest());
         continuation.setAttribute("response", boshResponse);
         continuation.resume();
+        latestWriteTimestamp = System.currentTimeMillis();
     }
     
     private boolean isResponseSavable(BoshRequest req, Stanza response) {
@@ -249,6 +283,8 @@ public class BoshBackedSessionContext ex
         serverRuntimeContext.getResourceRegistry().unbindSession(this);
         sessionStateHolder.setState(SessionState.CLOSED);
         
+        inactivityChecker.cancel();
+        
         LOGGER.info("BOSH session {} closed", getSessionId());
     }
 
@@ -272,6 +308,14 @@ public class BoshBackedSessionContext ex
     public String getContentType() {
         return contentType;
     }
+    
+    /**
+     * Getter for the maximum length of a temporary session pause (in seconds) that a client can request
+     * @return
+     */
+    public int getMaxPause() {
+        return maxpause;
+    }
 
     /**
      * Setter for the BOSH 'wait' parameter, the longest time (in seconds) that the connection manager is allowed to
@@ -404,6 +448,9 @@ public class BoshBackedSessionContext ex
      * @param req the HTTP request
      */
     public void insertRequest(BoshRequest br) {
+        // reset the inactivity
+        currentInactivity = inactivity;
+        
         Continuation continuation = ContinuationSupport.getContinuation(br.getHttpServletRequest());
         addContinuationExpirationListener(continuation);
         continuation.setTimeout(wait * 1000);
@@ -484,6 +531,21 @@ public class BoshBackedSessionContext ex
             }
         }
         
+        // we cannot pause if there are missing requests, this is tested with
+        // br.getRid().equals(requestsWindow.lastKey()) && highestReadRid.equals(br.getRid())
+        if (br.getBody().getAttribute("pause") != null && br.getRid().equals(requestsWindow.lastKey()) && highestReadRid.equals(br.getRid())) {
+            int pause = Integer.parseInt(br.getBody().getAttributeValue("pause"));
+            if (pause > maxpause) {
+                // do not allow to pause more than maxpause
+                pause = maxpause;
+            }
+            if (pause < 0) {
+                pause = 0;
+            }
+            respondToPause(pause);
+            return;
+        }
+        
         // If there are delayed responses waiting to be sent to the BOSH client, then we wrap them all in
         // a <body/> element and send them as a HTTP response to the current HTTP request.
         Stanza delayedResponse;
@@ -503,6 +565,18 @@ public class BoshBackedSessionContext ex
         }
     }
     
+    private void respondToPause(int pause) {
+        LOGGER.debug("Setting inactivity period to {}", pause);
+        currentInactivity = pause;
+        for (;;) {
+            BoshRequest boshRequest = getNextRequest();
+            if (boshRequest == null) {
+                break;
+            }
+            write0(boshHandler.getEmptyResponse());
+        }
+    }
+    
     private void sendBrokenConnectionReport(long report, long delta) {
         Stanza body = boshHandler.getTerminateResponse();
         body = boshHandler.addAttribute(body, "report", Long.toString(report));
@@ -533,6 +607,7 @@ public class BoshBackedSessionContext ex
         Continuation continuation = ContinuationSupport.getContinuation(br.getHttpServletRequest());
         continuation.setAttribute("response", boshResponse);
         continuation.resume();
+        latestWriteTimestamp = System.currentTimeMillis();
     }
 
     private BoshResponse getBoshResponse(Stanza stanza, Long ack) {

Modified: mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshHandler.java
URL: http://svn.apache.org/viewvc/mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshHandler.java?rev=986126&r1=986125&r2=986126&view=diff
==============================================================================
--- mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshHandler.java (original)
+++ mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshHandler.java Mon Aug 16 20:28:52 2010
@@ -196,6 +196,7 @@ public class BoshHandler {
         if ("1".equals(br.getBody().getAttributeValue("ack"))) {
             session.setClientAcknowledgements(true);
         }
+        session.startInactivityChecker();
         session.insertRequest(br);
         sessions.put(session.getSessionId(), session);
 
@@ -213,6 +214,7 @@ public class BoshHandler {
         body.addAttribute("ver", session.getBoshVersion());
         body.addAttribute("from", session.getServerJID().getFullQualifiedName());
         body.addAttribute("secure", "true");
+        body.addAttribute("maxpause", Integer.toString(session.getMaxPause()));
         
         // adding the ack attribute here is needed because when responding to o request with the same RID (as is the case here)
         // the ack would not be included on BoshBackedSessionContext#write0, but this first ack is required.