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/12 18:57:19 UTC
svn commit: r984863 - in
/mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src:
main/java/org/apache/vysper/xmpp/extension/xep0124/
test/java/org/apache/vysper/xmpp/extension/xep0124/
Author: ngn
Date: Thu Aug 12 16:57:19 2010
New Revision: 984863
URL: http://svn.apache.org/viewvc?rev=984863&view=rev
Log:
Implementation of the ack attribute (VYSPER-232, by Bogdan Pistol)
Added:
mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshRequest.java
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
mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/test/java/org/apache/vysper/xmpp/extension/xep0124/BoshBackedSessionContextTest.java
mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/test/java/org/apache/vysper/xmpp/extension/xep0124/BoshHandlerTest.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=984863&r1=984862&r2=984863&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 Thu Aug 12 16:57:19 2010
@@ -21,8 +21,8 @@ package org.apache.vysper.xmpp.extension
import java.util.LinkedList;
import java.util.Queue;
-
-import javax.servlet.http.HttpServletRequest;
+import java.util.SortedMap;
+import java.util.TreeMap;
import org.apache.vysper.xml.fragment.Renderer;
import org.apache.vysper.xmpp.protocol.SessionStateHolder;
@@ -61,12 +61,18 @@ public class BoshBackedSessionContext ex
private int wait = 60;
private int hold = 1;
-
+
+ private Long highestAcknowledgedRid = null;
+
+ private Long currentProcessingRequest = null;
+
/*
* 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)
+ *
+ * The BOSH requests sorted by their RIDs.
*/
- private Queue<HttpServletRequest> requestQueue;
+ private SortedMap<Long, BoshRequest> requestsWindow;
/*
* Keeps the asynchronous messages sent from server that cannot be delivered to the client because there are
@@ -86,9 +92,18 @@ public class BoshBackedSessionContext ex
sessionStateHolder.setState(SessionState.ENCRYPTED);
this.boshHandler = boshHandler;
- requestQueue = new LinkedList<HttpServletRequest>();
+ requestsWindow = new TreeMap<Long, BoshRequest>();
delayedResponseQueue = new LinkedList<Stanza>();
}
+
+ /**
+ * Returns the highest RID that is received in a continuous (uninterrupted) sequence of RIDs.
+ * Higher RIDs can exist with gaps separating them from the highestAcknowledgedRid.
+ * @return the highest continuous RID received so far
+ */
+ public long getHighestAcknowledgedRid() {
+ return highestAcknowledgedRid;
+ }
public SessionStateHolder getStateHolder() {
return sessionStateHolder;
@@ -119,16 +134,18 @@ public class BoshBackedSessionContext ex
* @param response The BOSH response to write
*/
void write0(Stanza response) {
- HttpServletRequest req = requestQueue.poll();
- if (req == null) {
+ BoshRequest req;
+ if (requestsWindow.isEmpty() || requestsWindow.firstKey() > highestAcknowledgedRid) {
delayedResponseQueue.offer(response);
return;
+ } else {
+ req = requestsWindow.remove(requestsWindow.firstKey());
}
- BoshResponse boshResponse = getBoshResponse(response);
+ BoshResponse boshResponse = getBoshResponse(response, req.getRid().equals(highestAcknowledgedRid) ? null : highestAcknowledgedRid);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("BOSH writing response: {}", new String(boshResponse.getContent()));
}
- Continuation continuation = ContinuationSupport.getContinuation(req);
+ Continuation continuation = ContinuationSupport.getContinuation(req.getHttpServletRequest());
continuation.setAttribute("response", boshResponse);
continuation.resume();
}
@@ -138,7 +155,7 @@ public class BoshBackedSessionContext ex
*/
public void close() {
// respond to all the queued HTTP requests with empty responses
- while (!requestQueue.isEmpty()) {
+ while (!requestsWindow.isEmpty()) {
write0(boshHandler.getEmptyResponse());
}
@@ -267,21 +284,13 @@ public class BoshBackedSessionContext ex
* expirations for the BOSH client while the current request expires.
*/
synchronized private void requestExpired(Continuation continuation) {
- HttpServletRequest req = (HttpServletRequest) continuation.getAttribute("request");
+ BoshRequest req = (BoshRequest) continuation.getAttribute("request");
if (req == null) {
LOGGER.warn("Continuation expired without having an associated request!");
return;
}
- continuation.setAttribute("response", getBoshResponse(boshHandler.getEmptyResponse()));
- for (;;) {
- HttpServletRequest r = requestQueue.peek();
- if (r == null) {
- break;
- }
+ while (!requestsWindow.isEmpty() && requestsWindow.firstKey() <= req.getRid()) {
write0(boshHandler.getEmptyResponse());
- if (r == req) {
- break;
- }
}
}
@@ -291,12 +300,28 @@ public class BoshBackedSessionContext ex
*
* @param req the HTTP request
*/
- public void addRequest(HttpServletRequest req) {
- Continuation continuation = ContinuationSupport.getContinuation(req);
+ public void insertRequest(BoshRequest br) {
+ if (highestAcknowledgedRid != null && br.getRid() <= highestAcknowledgedRid || requestsWindow.containsKey(br.getRid())) {
+ // TODO: return the old response
+ return;
+ }
+ Continuation continuation = ContinuationSupport.getContinuation(br.getHttpServletRequest());
continuation.setTimeout(wait * 1000);
continuation.suspend();
- continuation.setAttribute("request", req);
- requestQueue.offer(req);
+ continuation.setAttribute("request", br);
+ requestsWindow.put(br.getRid(), br);
+ if (highestAcknowledgedRid == null) {
+ highestAcknowledgedRid = br.getRid();
+ }
+ for (;;) {
+ // update the highestAcknowledgedRid to the latest value
+ // it is possible to have higher RIDs than the highestAcknowledgedRid with a gap between them (e.g. lost client request)
+ if (requestsWindow.containsKey(highestAcknowledgedRid + 1)) {
+ highestAcknowledgedRid++;
+ } else {
+ break;
+ }
+ }
// listen the continuation to be notified when the request expires
continuation.addContinuationListener(new ContinuationListener() {
@@ -325,14 +350,37 @@ public class BoshBackedSessionContext ex
// If there are more suspended enqueued requests than it is allowed by the BOSH 'hold' parameter,
// than we release the oldest one by sending an empty response.
- if (requestQueue.size() > hold) {
+ if (requestsWindow.size() > hold) {
write0(boshHandler.getEmptyResponse());
}
}
- private BoshResponse getBoshResponse(Stanza stanza) {
+ private BoshResponse getBoshResponse(Stanza stanza, Long ack) {
+ if (ack != null) {
+ stanza = boshHandler.addAck(stanza, ack);
+ }
byte[] content = new Renderer(stanza).getComplete().getBytes();
return new BoshResponse(contentType, content);
}
+ /**
+ * Returns the next BOSH body to process.
+ * It is possible to have more than one BOSH body to process in the case where a lost request is resent by the client.
+ * @return the next (by RID order) body to process
+ */
+ public BoshRequest getNextRequest() {
+ if (requestsWindow.isEmpty()) {
+ return null;
+ }
+ if (currentProcessingRequest == null || currentProcessingRequest < requestsWindow.firstKey()) {
+ currentProcessingRequest = requestsWindow.firstKey();
+ }
+ if (currentProcessingRequest > highestAcknowledgedRid) {
+ return null;
+ } else {
+ currentProcessingRequest++;
+ return requestsWindow.get(currentProcessingRequest - 1);
+ }
+ }
+
}
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=984863&r1=984862&r2=984863&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 Thu Aug 12 16:57:19 2010
@@ -25,6 +25,7 @@ import java.util.concurrent.ConcurrentHa
import javax.servlet.http.HttpServletRequest;
+import org.apache.vysper.xml.fragment.Attribute;
import org.apache.vysper.xml.fragment.XMLElement;
import org.apache.vysper.xmpp.protocol.NamespaceURIs;
import org.apache.vysper.xmpp.server.ServerRuntimeContext;
@@ -77,67 +78,76 @@ public class BoshHandler {
/**
* Processes BOSH requests
* @param httpRequest the HTTP request
- * @param boshRequest the decoded BOSH request
+ * @param body the decoded BOSH request
*/
- public void process(HttpServletRequest httpRequest, Stanza boshRequest) {
- if (!boshRequest.getNamespaceURI().equalsIgnoreCase(NamespaceURIs.XEP0124_BOSH)) {
- LOGGER.error("Invalid namespace for body wrapper '{}', must be '{}'!", boshRequest.getNamespaceURI(),
+ public void process(HttpServletRequest httpRequest, Stanza body) {
+ if (!body.getNamespaceURI().equalsIgnoreCase(NamespaceURIs.XEP0124_BOSH)) {
+ LOGGER.error("Invalid namespace for body wrapper '{}', must be '{}'!", body.getNamespaceURI(),
NamespaceURIs.XEP0124_BOSH);
return;
}
- if (!boshRequest.getName().equalsIgnoreCase("body")) {
- LOGGER.error("Invalid body wrapper '{}'!", boshRequest.getName());
+ if (!body.getName().equalsIgnoreCase("body")) {
+ LOGGER.error("Invalid body wrapper '{}'!", body.getName());
return;
}
- if (boshRequest.getAttribute("rid") == null) {
+ if (body.getAttribute("rid") == null) {
LOGGER.error("Invalid request that does not have a request identifier (rid) attribute!");
return;
}
-
- if (boshRequest.getAttribute("sid") == null) {
+ BoshRequest br = new BoshRequest(httpRequest, body, Long.parseLong(body.getAttributeValue("rid")));
+ if (body.getAttribute("sid") == null) {
// the session creation request (first request) does not have a "sid" attribute
try {
- createSession(httpRequest, boshRequest);
+ createSession(br);
} catch (IOException e) {
LOGGER.error("Exception thrown while processing the session creation request", e);
return;
}
} else {
- BoshBackedSessionContext session = sessions.get(boshRequest.getAttributeValue("sid"));
+ BoshBackedSessionContext session = sessions.get(body.getAttributeValue("sid"));
if (session == null) {
LOGGER.warn("Received an invalid 'sid'!");
return;
}
synchronized (session) {
- session.addRequest(httpRequest);
- processSession(session, boshRequest);
+ session.insertRequest(br);
+ for (;;) {
+ // When a request from the user comes in, it is possible that the request fills a gap
+ // created by previous lost request, and it could be possible to process more than the current request
+ // continuing with all the adjacent requests.
+ br = session.getNextRequest();
+ if (br == null) {
+ break;
+ }
+ processSession(session, br);
+ }
}
}
}
- private void processSession(BoshBackedSessionContext session, Stanza boshRequest) {
+ private void processSession(BoshBackedSessionContext session, BoshRequest br) {
if (session.getState() == SessionState.ENCRYPTED) {
- if (boshRequest.getInnerElements().isEmpty()) {
+ if (br.getBody().getInnerElements().isEmpty()) {
// session needs authentication
return;
}
- for (XMLElement element : boshRequest.getInnerElements()) {
+ for (XMLElement element : br.getBody().getInnerElements()) {
if (element.getNamespaceURI().equals(NamespaceURIs.URN_IETF_PARAMS_XML_NS_XMPP_SASL)) {
processStanza(session, element);
}
}
} else if (session.getState() == SessionState.AUTHENTICATED) {
- if ("true".equals(boshRequest.getAttributeValue(NamespaceURIs.URN_XMPP_XBOSH, "restart"))) {
+ if ("true".equals(br.getBody().getAttributeValue(NamespaceURIs.URN_XMPP_XBOSH, "restart"))) {
// restart request
session.write0(getRestartResponse());
} else {
// any other request
- for (XMLElement element : boshRequest.getInnerElements()) {
+ for (XMLElement element : br.getBody().getInnerElements()) {
processStanza(session, element);
}
// if the client solicited the session termination
- if ("terminate".equals(boshRequest.getAttributeValue("type"))) {
+ if ("terminate".equals(br.getBody().getAttributeValue("type"))) {
terminateSession(session);
}
}
@@ -162,28 +172,28 @@ public class BoshHandler {
session.getStateHolder());
}
- private void createSession(HttpServletRequest httpRequest, Stanza boshRequest) throws IOException {
+ private void createSession(BoshRequest br) throws IOException {
BoshBackedSessionContext session = new BoshBackedSessionContext(this, serverRuntimeContext);
- if (boshRequest.getAttribute("content") != null) {
- session.setContentType(boshRequest.getAttributeValue("content"));
+ if (br.getBody().getAttribute("content") != null) {
+ session.setContentType(br.getBody().getAttributeValue("content"));
}
- if (boshRequest.getAttribute("wait") != null) {
- int wait = Integer.parseInt(boshRequest.getAttributeValue("wait"));
+ if (br.getBody().getAttribute("wait") != null) {
+ int wait = Integer.parseInt(br.getBody().getAttributeValue("wait"));
session.setWait(wait);
}
- if (boshRequest.getAttribute("hold") != null) {
- int hold = Integer.parseInt(boshRequest.getAttributeValue("hold"));
+ if (br.getBody().getAttribute("hold") != null) {
+ int hold = Integer.parseInt(br.getBody().getAttributeValue("hold"));
session.setHold(hold);
}
- if (boshRequest.getAttribute("ver") != null) {
- String ver = boshRequest.getAttributeValue("ver");
+ if (br.getBody().getAttribute("ver") != null) {
+ String ver = br.getBody().getAttributeValue("ver");
session.setBoshVersion(ver);
}
- if (boshRequest.getAttribute(NamespaceURIs.XML, "lang") != null) {
- String lang = boshRequest.getAttributeValue(NamespaceURIs.XML, "lang");
+ if (br.getBody().getAttribute(NamespaceURIs.XML, "lang") != null) {
+ String lang = br.getBody().getAttributeValue(NamespaceURIs.XML, "lang");
session.setXMLLang(lang);
}
- session.addRequest(httpRequest);
+ session.insertRequest(br);
sessions.put(session.getSessionId(), session);
session.write0(getSessionCreationResponse(session));
@@ -200,6 +210,10 @@ public class BoshHandler {
body.addAttribute("ver", session.getBoshVersion());
body.addAttribute("from", session.getServerJID().getFullQualifiedName());
body.addAttribute("secure", "true");
+
+ // 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.
+ body.addAttribute("ack", Long.toString(session.getHighestAcknowledgedRid()));
Stanza features = new ServerResponses().getFeaturesForAuthentication(serverRuntimeContext.getServerFeatures()
.getAuthenticationMethods());
@@ -266,5 +280,17 @@ public class BoshHandler {
stanzaBuilder.addAttribute("type", "terminate");
return stanzaBuilder.build();
}
+
+ public Stanza addAck(Stanza stanza, Long ack) {
+ StanzaBuilder stanzaBuilder = new StanzaBuilder("body", NamespaceURIs.XEP0124_BOSH);
+ for (Attribute attr : stanza.getAttributes()) {
+ stanzaBuilder.addAttribute(attr);
+ }
+ stanzaBuilder.addAttribute("ack", ack.toString());
+ for (XMLElement element : stanza.getInnerElements()) {
+ stanzaBuilder.addPreparedElement(element);
+ }
+ return stanzaBuilder.build();
+ }
}
Added: mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshRequest.java
URL: http://svn.apache.org/viewvc/mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshRequest.java?rev=984863&view=auto
==============================================================================
--- mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshRequest.java (added)
+++ mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshRequest.java Thu Aug 12 16:57:19 2010
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.vysper.xmpp.extension.xep0124;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.vysper.xmpp.stanza.Stanza;
+
+/**
+ * Wraps an HTTP request with its XML BOSH body.
+ *
+ * @author The Apache MINA Project (dev@mina.apache.org)
+ */
+public class BoshRequest implements Comparable<BoshRequest> {
+
+ private final HttpServletRequest httpServletRequest;
+
+ private final Stanza body;
+
+ private final Long rid;
+
+ public BoshRequest(HttpServletRequest httpServletRequest, Stanza body, Long rid) {
+ this.httpServletRequest = httpServletRequest;
+ this.body = body;
+ this.rid = rid;
+ }
+
+ public HttpServletRequest getHttpServletRequest() {
+ return httpServletRequest;
+ }
+
+ public Stanza getBody() {
+ return body;
+ }
+
+ public Long getRid() {
+ return rid;
+ }
+
+ public int compareTo(BoshRequest br) {
+ return rid.compareTo(br.rid);
+ }
+
+ @Override
+ public int hashCode() {
+ return rid.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ BoshRequest other = (BoshRequest) obj;
+ if (rid == null) {
+ if (other.rid != null)
+ return false;
+ } else if (!rid.equals(other.rid))
+ return false;
+ return true;
+ }
+
+}
\ No newline at end of file
Modified: mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/test/java/org/apache/vysper/xmpp/extension/xep0124/BoshBackedSessionContextTest.java
URL: http://svn.apache.org/viewvc/mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/test/java/org/apache/vysper/xmpp/extension/xep0124/BoshBackedSessionContextTest.java?rev=984863&r1=984862&r2=984863&view=diff
==============================================================================
--- mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/test/java/org/apache/vysper/xmpp/extension/xep0124/BoshBackedSessionContextTest.java (original)
+++ mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/test/java/org/apache/vysper/xmpp/extension/xep0124/BoshBackedSessionContextTest.java Thu Aug 12 16:57:19 2010
@@ -51,8 +51,6 @@ public class BoshBackedSessionContextTes
private ServerRuntimeContext serverRuntimeContext;
- private BoshBackedSessionContext boshBackedSessionContext;
-
@Before
public void setUp() throws Exception {
mocksControl = createControl();
@@ -74,7 +72,7 @@ public class BoshBackedSessionContextTes
expect(httpServletRequest.getAttribute(Continuation.ATTRIBUTE)).andReturn(continuation);
expectLastCall().atLeastOnce();
continuation.setTimeout(anyLong());
- continuation.setAttribute("request", httpServletRequest);
+ continuation.setAttribute(eq("request"), EasyMock.<BoshRequest> notNull());
continuation.suspend();
continuation.resume();
continuation.addContinuationListener(EasyMock.<ContinuationListener> anyObject());
@@ -82,12 +80,12 @@ public class BoshBackedSessionContextTes
continuation.setAttribute(eq("response"), EasyMock.<BoshResponse> capture(captured));
mocksControl.replay();
- boshBackedSessionContext = new BoshBackedSessionContext(boshHandler, serverRuntimeContext);
- boshBackedSessionContext.addRequest(httpServletRequest);
+ BoshBackedSessionContext boshBackedSessionContext = new BoshBackedSessionContext(boshHandler, serverRuntimeContext);
Stanza body = new StanzaBuilder("body", NamespaceURIs.XEP0124_BOSH).build();
+ boshBackedSessionContext.insertRequest(new BoshRequest(httpServletRequest, body, 1L));
boshBackedSessionContext.write0(body);
mocksControl.verify();
-
+
BoshResponse boshResponse = captured.getValue();
assertEquals(BoshServlet.XML_CONTENT_TYPE, boshResponse.getContentType());
assertEquals(new Renderer(body).getComplete(), new String(boshResponse.getContent()));
@@ -96,17 +94,19 @@ public class BoshBackedSessionContextTes
@Test
public void testSetBoshVersion1() {
mocksControl.replay();
- boshBackedSessionContext = new BoshBackedSessionContext(boshHandler, serverRuntimeContext);
+ BoshBackedSessionContext boshBackedSessionContext = new BoshBackedSessionContext(boshHandler, serverRuntimeContext);
boshBackedSessionContext.setBoshVersion("1.8");
assertEquals("1.8", boshBackedSessionContext.getBoshVersion());
+ mocksControl.verify();
}
@Test
public void testSetBoshVersion2() {
mocksControl.replay();
- boshBackedSessionContext = new BoshBackedSessionContext(boshHandler, serverRuntimeContext);
+ BoshBackedSessionContext boshBackedSessionContext = new BoshBackedSessionContext(boshHandler, serverRuntimeContext);
boshBackedSessionContext.setBoshVersion("2.0");
assertEquals("1.9", boshBackedSessionContext.getBoshVersion());
+ mocksControl.verify();
}
@Test
@@ -120,13 +120,15 @@ public class BoshBackedSessionContextTes
expectLastCall().atLeastOnce();
continuation.setTimeout(anyLong());
continuation.suspend();
- continuation.setAttribute("request", httpServletRequest);
+ continuation.setAttribute(eq("request"), EasyMock.<BoshRequest> notNull());
Capture<ContinuationListener> listenerCaptured = new Capture<ContinuationListener>();
continuation.addContinuationListener(EasyMock.<ContinuationListener> capture(listenerCaptured));
+
+ BoshRequest br = new BoshRequest(httpServletRequest, body, 1L);
// requestExpired
- expect(continuation.getAttribute("request")).andReturn(httpServletRequest);
+ expect(continuation.getAttribute("request")).andReturn(br);
Capture<BoshResponse> responseCaptured = new Capture<BoshResponse>();
continuation.setAttribute(eq("response"), EasyMock.<BoshResponse> capture(responseCaptured));
@@ -134,12 +136,12 @@ public class BoshBackedSessionContextTes
expectLastCall().atLeastOnce();
// write0
- continuation.setAttribute(eq("response"), EasyMock.<BoshResponse> anyObject());
continuation.resume();
mocksControl.replay();
- boshBackedSessionContext = new BoshBackedSessionContext(boshHandler, serverRuntimeContext);
- boshBackedSessionContext.addRequest(httpServletRequest);
+ BoshBackedSessionContext boshBackedSessionContext = new BoshBackedSessionContext(boshHandler, serverRuntimeContext);
+
+ boshBackedSessionContext.insertRequest(br);
listenerCaptured.getValue().onTimeout(continuation);
mocksControl.verify();
@@ -160,12 +162,17 @@ public class BoshBackedSessionContextTes
expectLastCall().atLeastOnce();
continuation1.setTimeout(anyLong());
continuation1.suspend();
- continuation1.setAttribute("request", httpServletRequest1);
+ Capture<BoshRequest> br1 = new Capture<BoshRequest>();
+ continuation1.setAttribute(eq("request"), EasyMock.<BoshRequest> capture(br1));
continuation2.setTimeout(anyLong());
continuation2.suspend();
- continuation2.setAttribute("request", httpServletRequest2);
+ Capture<BoshRequest> br2 = new Capture<BoshRequest>();
+ continuation2.setAttribute(eq("request"), EasyMock.<BoshRequest> capture(br2));
continuation1.addContinuationListener(EasyMock.<ContinuationListener> anyObject());
continuation2.addContinuationListener(EasyMock.<ContinuationListener> anyObject());
+
+ Stanza body = new StanzaBuilder("body", NamespaceURIs.XEP0124_BOSH).build();
+ expect(boshHandler.addAck(eq(body), EasyMock.anyLong())).andReturn(body);
// write0
Capture<BoshResponse> captured = new Capture<BoshResponse>();
@@ -173,14 +180,17 @@ public class BoshBackedSessionContextTes
continuation1.resume();
mocksControl.replay();
- boshBackedSessionContext = new BoshBackedSessionContext(boshHandler, serverRuntimeContext);
+ BoshBackedSessionContext boshBackedSessionContext = new BoshBackedSessionContext(boshHandler, serverRuntimeContext);
boshBackedSessionContext.setHold(2);
- boshBackedSessionContext.addRequest(httpServletRequest1);
- boshBackedSessionContext.addRequest(httpServletRequest2);
- Stanza body = new StanzaBuilder("body", NamespaceURIs.XEP0124_BOSH).build();
+ // consecutive writes with RID 1 and 2
+ boshBackedSessionContext.insertRequest(new BoshRequest(httpServletRequest1, body, 1L));
+ boshBackedSessionContext.insertRequest(new BoshRequest(httpServletRequest2, body, 2L));
boshBackedSessionContext.write0(body);
mocksControl.verify();
+
+ assertEquals(httpServletRequest1, br1.getValue().getHttpServletRequest());
+ assertEquals(httpServletRequest2, br2.getValue().getHttpServletRequest());
assertEquals(new Renderer(body).getComplete(), new String(captured.getValue().getContent()));
assertEquals(BoshServlet.XML_CONTENT_TYPE, captured.getValue().getContentType());
@@ -194,7 +204,7 @@ public class BoshBackedSessionContextTes
expectLastCall().atLeastOnce();
continuation.setTimeout(anyLong());
continuation.suspend();
- continuation.setAttribute("request", httpServletRequest);
+ continuation.setAttribute(eq("request"), EasyMock.<BoshRequest> notNull());
continuation.addContinuationListener(EasyMock.<ContinuationListener> anyObject());
@@ -209,10 +219,10 @@ public class BoshBackedSessionContextTes
mocksControl.replay();
- boshBackedSessionContext = new BoshBackedSessionContext(boshHandler, serverRuntimeContext);
+ BoshBackedSessionContext boshBackedSessionContext = new BoshBackedSessionContext(boshHandler, serverRuntimeContext);
boshBackedSessionContext.write0(body1);
boshBackedSessionContext.write0(body2);
- boshBackedSessionContext.addRequest(httpServletRequest);
+ boshBackedSessionContext.insertRequest(new BoshRequest(httpServletRequest, body1, 1L));
mocksControl.verify();
}
Modified: mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/test/java/org/apache/vysper/xmpp/extension/xep0124/BoshHandlerTest.java
URL: http://svn.apache.org/viewvc/mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/test/java/org/apache/vysper/xmpp/extension/xep0124/BoshHandlerTest.java?rev=984863&r1=984862&r2=984863&view=diff
==============================================================================
--- mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/test/java/org/apache/vysper/xmpp/extension/xep0124/BoshHandlerTest.java (original)
+++ mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/test/java/org/apache/vysper/xmpp/extension/xep0124/BoshHandlerTest.java Thu Aug 12 16:57:19 2010
@@ -32,7 +32,6 @@ import java.util.Collections;
import javax.servlet.http.HttpServletRequest;
-import org.apache.vysper.xml.fragment.Renderer;
import org.apache.vysper.xml.fragment.XMLElement;
import org.apache.vysper.xmpp.addressing.EntityImpl;
import org.apache.vysper.xmpp.authorization.SASLMechanism;
@@ -85,7 +84,8 @@ public class BoshHandlerTest {
expect(httpServletRequest.getAttribute(Continuation.ATTRIBUTE)).andReturn(continuation);
expectLastCall().atLeastOnce();
continuation.setTimeout(anyLong());
- continuation.setAttribute("request", httpServletRequest);
+ Capture<BoshRequest> br = new Capture<BoshRequest>();
+ continuation.setAttribute(eq("request"), EasyMock.<BoshRequest> capture(br));
continuation.addContinuationListener(EasyMock.<ContinuationListener> anyObject());
continuation.suspend();
@@ -101,6 +101,9 @@ public class BoshHandlerTest {
Stanza boshRequest = createSessionRequest();
boshHandler.process(httpServletRequest, boshRequest);
mocksControl.verify();
+
+ assertEquals(httpServletRequest, br.getValue().getHttpServletRequest());
+ assertEquals(boshRequest, br.getValue().getBody());
Stanza response = new XMLUtil(new String(captured.getValue().getContent())).parse();
assertNotNull(response);
@@ -126,7 +129,7 @@ public class BoshHandlerTest {
expectLastCall().atLeastOnce();
continuation.setTimeout(anyLong());
continuation.suspend();
- continuation.setAttribute("request", httpServletRequest);
+ continuation.setAttribute(eq("request"), EasyMock.<BoshRequest> capture(br));
continuation.addContinuationListener(EasyMock.<ContinuationListener> anyObject());
StanzaProcessor stanzaProcessor = mocksControl.createMock(StanzaProcessor.class);
expect(serverRuntimeContext.getStanzaProcessor()).andReturn(stanzaProcessor);
@@ -137,6 +140,10 @@ public class BoshHandlerTest {
boshRequest = createSaslRequest();
boshHandler.process(httpServletRequest, boshRequest);
mocksControl.verify();
+
+ assertEquals(httpServletRequest, br.getValue().getHttpServletRequest());
+ assertEquals(boshRequest, br.getValue().getBody());
+
Stanza stanza = stanzaCaptured.getValue();
assertNotNull(stanza);
assertEquals("auth", stanza.getName());