Author: ngn
Date: Mon Aug 16 20:03:40 2010
New Revision: 986118

URL: http://svn.apache.org/viewvc?rev=986118&view=rev
Log:
Finished client ack implementation (VYSPER-239, 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/BoshResponse.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=986118&r1=986117&r2=986118&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:03:40 2010
@@ -56,6 +56,12 @@ public class BoshBackedSessionContext ex
     private final int maximumSentResponses = 10;
     
     /*
+     * The number of milliseconds that will have to pass for a response to be 
reported missing to the client by
+     * responding with a report and time attributes. See Response 
Acknowledgements in XEP-0124.
+     */
+    private final int brokenConnectionReportTimeout = 1000;
+    
+    /*
      * Keeps the suspended HTTP requests (does not respond to them) until the 
server has an asynchronous message
      * to send to the client. (Comet HTTP Long Polling technique - described 
in XEP-0124)
      * 
@@ -211,9 +217,9 @@ public class BoshBackedSessionContext ex
     private void error(BoshRequest br, String condition) {
         requestsWindow.put(br.getRid(), br);
         BoshRequest req = requestsWindow.remove(requestsWindow.firstKey());
-        Stanza stanza = boshHandler.getTerminateResponse();
-        stanza = boshHandler.addAttribute(stanza, "condition", condition);
-        BoshResponse boshResponse = getBoshResponse(stanza, null);
+        Stanza body = boshHandler.getTerminateResponse();
+        body = boshHandler.addAttribute(body, "condition", condition);
+        BoshResponse boshResponse = getBoshResponse(body, null);
         if (LOGGER.isDebugEnabled()) {
             LOGGER.debug("BOSH writing response: {}", new 
String(boshResponse.getContent()));
         }
@@ -227,9 +233,17 @@ public class BoshBackedSessionContext ex
      * Terminates the BOSH session
      */
     synchronized public void close() {
-        // respond to all the queued HTTP requests with empty responses
+        // respond to all the queued HTTP requests with termination responses
         while (!requestsWindow.isEmpty()) {
-            write0(boshHandler.getEmptyResponse());
+            BoshRequest req = requestsWindow.remove(requestsWindow.firstKey());
+            Stanza body = boshHandler.getTerminateResponse();
+            BoshResponse boshResponse = getBoshResponse(body, null);
+            if (LOGGER.isDebugEnabled()) {
+                LOGGER.debug("BOSH writing response: {}", new 
String(boshResponse.getContent()));
+            }
+            Continuation continuation = 
ContinuationSupport.getContinuation(req.getHttpServletRequest());
+            continuation.setAttribute("response", boshResponse);
+            continuation.resume();
         }
         
         serverRuntimeContext.getResourceRegistry().unbindSession(this);
@@ -434,10 +448,6 @@ public class BoshBackedSessionContext ex
             }
             latestEmptyPollingRequest = br;
         }
-        if (isClientAcknowledgements()) {
-            // TODO: if received client ack is not the expected one, then send 
a response report to the client informing him about this,
-            // so that he could rerequest the missing responses.
-        }
         
         requestsWindow.put(br.getRid(), br);
         if (highestReadRid == null) {
@@ -453,6 +463,27 @@ public class BoshBackedSessionContext ex
             }
         }
         
+        if (isClientAcknowledgements()) {
+            if (br.getBody().getAttribute("ack") == null) {
+                // if there is no ack attribute present then the client 
confirmed it received all the responses to all the previous requests
+                // and we clear the cache
+                sentResponses.clear();
+            } else if (!sentResponses.isEmpty()) {
+                // After receiving a request with an 'ack' value less than the 
'rid' of the last request that it has already responded to,
+                // the connection manager MAY inform the client of the 
situation. In this case it SHOULD include a 'report' attribute set
+                // to one greater than the 'ack' attribute it received from 
the client, and a 'time' attribute set to the number of milliseconds
+                // since it sent the response associated with the 'report' 
attribute.
+                long ack = 
Long.parseLong(br.getBody().getAttributeValue("ack"));
+                if (ack < sentResponses.lastKey() && 
sentResponses.containsKey(ack + 1)) {
+                    long delta = System.currentTimeMillis() - 
sentResponses.get(ack + 1).getTimestamp();
+                    if (delta >= brokenConnectionReportTimeout) {
+                        sendBrokenConnectionReport(ack + 1, delta);
+                        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;
@@ -472,6 +503,13 @@ public class BoshBackedSessionContext ex
         }
     }
     
+    private void sendBrokenConnectionReport(long report, long delta) {
+        Stanza body = boshHandler.getTerminateResponse();
+        body = boshHandler.addAttribute(body, "report", Long.toString(report));
+        body = boshHandler.addAttribute(body, "time", Long.toString(delta));
+        write0(body);
+    }
+    
     private void addContinuationExpirationListener(Continuation continuation) {
         // listen the continuation to be notified when the request expires
         continuation.addContinuationListener(new ContinuationListener() {

Modified: 
mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshResponse.java
URL: 
http://svn.apache.org/viewvc/mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshResponse.java?rev=986118&r1=986117&r2=986118&view=diff
==============================================================================
--- 
mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshResponse.java
 (original)
+++ 
mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshResponse.java
 Mon Aug 16 20:03:40 2010
@@ -30,9 +30,12 @@ public class BoshResponse {
 
     private final byte[] content;
 
+    private final long timestamp;
+
     public BoshResponse(String contentType, byte[] content) {
         this.contentType = contentType;
         this.content = content;
+        timestamp = System.currentTimeMillis();
     }
 
     public String getContentType() {
@@ -43,4 +46,8 @@ public class BoshResponse {
         return content;
     }
 
+    public long getTimestamp() {
+        return timestamp;
+    }
+
 }


Reply via email to