Author: foodmike
Date: Mon Mar 19 03:09:21 2012
New Revision: 1302264
URL: http://svn.apache.org/viewvc?rev=1302264&view=rev
Log:
Fix to address VYSPER-18. Modifications to XML parsing/handling in order to
recognize and act on stream close events. This fix adds a closed flag to the
XMLElementListener that allows the XMPPDecoder to determine when a stream is
closed.
Additionally added a check to the XMLTokenizer that allows it to ignore
whitespace when it is in the START state. This prevents is from buffering
unnecessary whitespace characters.
Modified:
mina/vysper/trunk/ (props changed)
mina/vysper/trunk/nbxml/src/main/java/org/apache/vysper/xml/decoder/XMLElementListener.java
mina/vysper/trunk/nbxml/src/main/java/org/apache/vysper/xml/decoder/XMPPContentHandler.java
mina/vysper/trunk/nbxml/src/main/java/org/apache/vysper/xml/decoder/XMPPDecoder.java
mina/vysper/trunk/nbxml/src/main/java/org/apache/vysper/xml/sax/impl/XMLTokenizer.java
mina/vysper/trunk/nbxml/src/test/java/org/apache/vysper/xml/sax/impl/XMPPContentHandlerTestCase.java
mina/vysper/trunk/nbxml/src/test/java/org/apache/vysper/xml/sax/perf/PerfRunner.java
mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/mina/XmppIoHandlerAdapter.java
mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/parser/XMLParserUtil.java
mina/vysper/trunk/server/extensions/websockets/src/main/java/org/apache/vysper/xmpp/extension/websockets/WebSocketBackedSessionContext.java
Propchange: mina/vysper/trunk/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Mon Mar 19 03:09:21 2012
@@ -2,3 +2,6 @@ target
.settings
.classpath
.project
+lib
+bogus_mina_tls.cert
+spring-config.xml
Modified:
mina/vysper/trunk/nbxml/src/main/java/org/apache/vysper/xml/decoder/XMLElementListener.java
URL:
http://svn.apache.org/viewvc/mina/vysper/trunk/nbxml/src/main/java/org/apache/vysper/xml/decoder/XMLElementListener.java?rev=1302264&r1=1302263&r2=1302264&view=diff
==============================================================================
---
mina/vysper/trunk/nbxml/src/main/java/org/apache/vysper/xml/decoder/XMLElementListener.java
(original)
+++
mina/vysper/trunk/nbxml/src/main/java/org/apache/vysper/xml/decoder/XMLElementListener.java
Mon Mar 19 03:09:21 2012
@@ -23,4 +23,6 @@ import org.apache.vysper.xml.fragment.XM
public interface XMLElementListener {
void element(XMLElement element);
+ void close();
+ boolean isClosed();
}
\ No newline at end of file
Modified:
mina/vysper/trunk/nbxml/src/main/java/org/apache/vysper/xml/decoder/XMPPContentHandler.java
URL:
http://svn.apache.org/viewvc/mina/vysper/trunk/nbxml/src/main/java/org/apache/vysper/xml/decoder/XMPPContentHandler.java?rev=1302264&r1=1302263&r2=1302264&view=diff
==============================================================================
---
mina/vysper/trunk/nbxml/src/main/java/org/apache/vysper/xml/decoder/XMPPContentHandler.java
(original)
+++
mina/vysper/trunk/nbxml/src/main/java/org/apache/vysper/xml/decoder/XMPPContentHandler.java
Mon Mar 19 03:09:21 2012
@@ -83,8 +83,7 @@ public class XMPPContentHandler implemen
// complete stanza, emit
emit();
} else if (depth == 0) {
- // end stream:stream element
- // TODO handle
+ // End of stream. Handled in endDocument().
} else {
builder.endInnerElement();
}
@@ -137,9 +136,10 @@ public class XMPPContentHandler implemen
}
/**
- * {@inheritDoc}
+ * End of the XMPP stream. Tell the XML listener we're done.
*/
- public void endDocument() throws SAXException { /* ignore */
+ public void endDocument() throws SAXException {
+ this.listener.close();
}
/**
Modified:
mina/vysper/trunk/nbxml/src/main/java/org/apache/vysper/xml/decoder/XMPPDecoder.java
URL:
http://svn.apache.org/viewvc/mina/vysper/trunk/nbxml/src/main/java/org/apache/vysper/xml/decoder/XMPPDecoder.java?rev=1302264&r1=1302263&r2=1302264&view=diff
==============================================================================
---
mina/vysper/trunk/nbxml/src/main/java/org/apache/vysper/xml/decoder/XMPPDecoder.java
(original)
+++
mina/vysper/trunk/nbxml/src/main/java/org/apache/vysper/xml/decoder/XMPPDecoder.java
Mon Mar 19 03:09:21 2012
@@ -34,7 +34,7 @@ import org.apache.vysper.xml.sax.impl.De
* @author The Apache MINA Project ([email protected])
*/
public class XMPPDecoder extends CumulativeProtocolDecoder {
-
+
private static final String XML_DECL = "<?xml";
private static final String STREAM_STREAM = "<stream:stream";
@@ -53,6 +53,7 @@ public class XMPPDecoder extends Cumulat
public static class MinaStanzaListener implements XMLElementListener {
private ProtocolDecoderOutput protocolDecoder;
+ private boolean closed = false;
public MinaStanzaListener(ProtocolDecoderOutput protocolDecoder) {
this.protocolDecoder = protocolDecoder;
@@ -65,6 +66,14 @@ public class XMPPDecoder extends Cumulat
protocolDecoder.write(element);
}
+
+ public void close() {
+ this.closed = true;
+ }
+
+ public boolean isClosed() {
+ return this.closed;
+ }
}
/**
@@ -90,11 +99,17 @@ public class XMPPDecoder extends Cumulat
}
XMPPContentHandler contentHandler = (XMPPContentHandler)
reader.getContentHandler();
- contentHandler.setListener(new MinaStanzaListener(out));
+ XMLElementListener listener = new MinaStanzaListener(out);
+ contentHandler.setListener(listener);
reader.parse(in, CharsetUtil.UTF8_DECODER);
-
- // we have parsed what we got, invoke again when more data is available
- return false;
+
+ if (listener.isClosed()) {
+ session.close(true);
+ return true;
+ } else {
+ // we have parsed what we got, invoke again when more data is
available
+ return false;
+ }
}
}
\ No newline at end of file
Modified:
mina/vysper/trunk/nbxml/src/main/java/org/apache/vysper/xml/sax/impl/XMLTokenizer.java
URL:
http://svn.apache.org/viewvc/mina/vysper/trunk/nbxml/src/main/java/org/apache/vysper/xml/sax/impl/XMLTokenizer.java?rev=1302264&r1=1302263&r2=1302264&view=diff
==============================================================================
---
mina/vysper/trunk/nbxml/src/main/java/org/apache/vysper/xml/sax/impl/XMLTokenizer.java
(original)
+++
mina/vysper/trunk/nbxml/src/main/java/org/apache/vysper/xml/sax/impl/XMLTokenizer.java
Mon Mar 19 03:09:21 2012
@@ -55,7 +55,6 @@ public class XMLTokenizer {
/**
* @param byteBuffer
* @param charsetDecoder
- * @return the new particle or NULL, if the buffer was exhausted before
the particle was completed
* @throws Exception
*/
public void parse(IoBuffer byteBuffer, CharsetDecoder decoder) throws
SAXException {
@@ -66,6 +65,8 @@ public class XMLTokenizer {
if (c == '<') {
emit(c, byteBuffer);
state = State.IN_TAG;
+ } else if (Character.isWhitespace(c)) {
+ // ignore
} else {
state = State.IN_TEXT;
buffer.put((byte) c);
Modified:
mina/vysper/trunk/nbxml/src/test/java/org/apache/vysper/xml/sax/impl/XMPPContentHandlerTestCase.java
URL:
http://svn.apache.org/viewvc/mina/vysper/trunk/nbxml/src/test/java/org/apache/vysper/xml/sax/impl/XMPPContentHandlerTestCase.java?rev=1302264&r1=1302263&r2=1302264&view=diff
==============================================================================
---
mina/vysper/trunk/nbxml/src/test/java/org/apache/vysper/xml/sax/impl/XMPPContentHandlerTestCase.java
(original)
+++
mina/vysper/trunk/nbxml/src/test/java/org/apache/vysper/xml/sax/impl/XMPPContentHandlerTestCase.java
Mon Mar 19 03:09:21 2012
@@ -39,10 +39,14 @@ public class XMPPContentHandlerTestCase
private static class TestListener implements XMLElementListener {
public List<XMLElement> elements = new ArrayList<XMLElement>();
+ private boolean closed = false;
public void element(XMLElement element) {
elements.add(element);
}
+
+ public void close() { closed = true; }
+ public boolean isClosed() { return closed; }
}
public void test() throws Exception {
@@ -63,6 +67,7 @@ public class XMPPContentHandlerTestCase
assertEquals("stanza", actual.next().getName());
assertEquals("message", actual.next().getName());
assertEquals("iq", actual.next().getName());
+ assertTrue(listener.isClosed());
}
private void parse(NonBlockingXMLReader reader, String xml) throws
Exception {
Modified:
mina/vysper/trunk/nbxml/src/test/java/org/apache/vysper/xml/sax/perf/PerfRunner.java
URL:
http://svn.apache.org/viewvc/mina/vysper/trunk/nbxml/src/test/java/org/apache/vysper/xml/sax/perf/PerfRunner.java?rev=1302264&r1=1302263&r2=1302264&view=diff
==============================================================================
---
mina/vysper/trunk/nbxml/src/test/java/org/apache/vysper/xml/sax/perf/PerfRunner.java
(original)
+++
mina/vysper/trunk/nbxml/src/test/java/org/apache/vysper/xml/sax/perf/PerfRunner.java
Mon Mar 19 03:09:21 2012
@@ -39,7 +39,9 @@ public class PerfRunner {
public void element(XMLElement element) {
counter++;
}
-
+
+ public void close() {}
+ public boolean isClosed() { return false; }
}
private static final String SINGLE_LEVEL_XML = "<child att='foo'
att2='bar'></child>";
Modified:
mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/mina/XmppIoHandlerAdapter.java
URL:
http://svn.apache.org/viewvc/mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/mina/XmppIoHandlerAdapter.java?rev=1302264&r1=1302263&r2=1302264&view=diff
==============================================================================
---
mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/mina/XmppIoHandlerAdapter.java
(original)
+++
mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/mina/XmppIoHandlerAdapter.java
Mon Mar 19 03:09:21 2012
@@ -31,6 +31,7 @@ import org.apache.vysper.xmpp.protocol.S
import org.apache.vysper.xmpp.protocol.StreamErrorCondition;
import org.apache.vysper.xmpp.server.ServerRuntimeContext;
import org.apache.vysper.xmpp.server.SessionContext;
+import org.apache.vysper.xmpp.server.SessionContext.SessionTerminationCause;
import org.apache.vysper.xmpp.server.response.ServerErrorResponses;
import org.apache.vysper.xmpp.stanza.Stanza;
import org.slf4j.Logger;
@@ -47,6 +48,8 @@ public class XmppIoHandlerAdapter implem
public static final String ATTRIBUTE_VYSPER_SESSIONSTATEHOLDER =
"vysperSessionStateHolder";
+ public static final String ATTRIBUTE_VYSPER_TERMINATE_REASON =
"vysperTerminateReason";
+
final Logger logger = LoggerFactory.getLogger(XmppIoHandlerAdapter.class);
private ServerRuntimeContext serverRuntimeContext;
@@ -106,6 +109,7 @@ public class XmppIoHandlerAdapter implem
SessionContext sessionContext = new
MinaBackedSessionContext(serverRuntimeContext, stateHolder, ioSession);
ioSession.setAttribute(ATTRIBUTE_VYSPER_SESSION, sessionContext);
ioSession.setAttribute(ATTRIBUTE_VYSPER_SESSIONSTATEHOLDER,
stateHolder);
+ ioSession.setAttribute(ATTRIBUTE_VYSPER_TERMINATE_REASON,
SessionTerminationCause.CLIENT_BYEBYE);
}
public void sessionOpened(IoSession ioSession) throws Exception {
@@ -114,10 +118,11 @@ public class XmppIoHandlerAdapter implem
public void sessionClosed(IoSession ioSession) throws Exception {
SessionContext sessionContext = extractSession(ioSession);
+ SessionTerminationCause cause = (SessionTerminationCause)
ioSession.getAttribute(ATTRIBUTE_VYSPER_TERMINATE_REASON);
String sessionId = "UNKNOWN";
if (sessionContext != null) {
sessionId = sessionContext.getSessionId();
-
sessionContext.endSession(SessionContext.SessionTerminationCause.CONNECTION_ABORT);
+ sessionContext.endSession(cause);
}
logger.info("session {} has been closed", sessionId);
}
@@ -129,12 +134,17 @@ public class XmppIoHandlerAdapter implem
public void exceptionCaught(IoSession ioSession, Throwable throwable)
throws Exception {
SessionContext sessionContext = extractSession(ioSession);
-
+
+ // Assume that the connection was aborted for now. Might be different
depending on
+ // cause of exception determined below.
+ ioSession.setAttribute(ATTRIBUTE_VYSPER_TERMINATE_REASON,
SessionTerminationCause.CONNECTION_ABORT);
+
Stanza errorStanza;
if(throwable.getCause() != null && throwable.getCause() instanceof
SAXParseException) {
logger.info("Client sent not well-formed XML, closing session",
throwable);
errorStanza =
ServerErrorResponses.getStreamError(StreamErrorCondition.XML_NOT_WELL_FORMED,
sessionContext.getXMLLang(), "Stanza not well-formed",
null);
+ ioSession.setAttribute(ATTRIBUTE_VYSPER_TERMINATE_REASON,
SessionTerminationCause.STREAM_ERROR);
} else if(throwable instanceof WriteToClosedSessionException) {
// ignore
return;
@@ -145,8 +155,8 @@ public class XmppIoHandlerAdapter implem
logger.warn("error caught on transportation layer", throwable);
errorStanza =
ServerErrorResponses.getStreamError(StreamErrorCondition.UNDEFINED_CONDITION,
sessionContext.getXMLLang(), "Unknown error", null);
+ ioSession.setAttribute(ATTRIBUTE_VYSPER_TERMINATE_REASON,
SessionTerminationCause.STREAM_ERROR);
}
sessionContext.getResponseWriter().write(errorStanza);
-
sessionContext.endSession(SessionContext.SessionTerminationCause.STREAM_ERROR);
}
}
Modified:
mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/parser/XMLParserUtil.java
URL:
http://svn.apache.org/viewvc/mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/parser/XMLParserUtil.java?rev=1302264&r1=1302263&r2=1302264&view=diff
==============================================================================
---
mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/parser/XMLParserUtil.java
(original)
+++
mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/parser/XMLParserUtil.java
Mon Mar 19 03:09:21 2012
@@ -41,7 +41,7 @@ public class XMLParserUtil {
/**
* Parses a complete XML document. If the XML string contains errors, a
- * {@link SAXException} will be trown. If the XML string is not a complete
+ * {@link SAXException} will be thrown. If the XML string is not a complete
* XML document, null will be returned
* @param xml A string with a complete XML document
* @return
@@ -60,6 +60,8 @@ public class XMLParserUtil {
public void element(XMLElement element) {
documents.add(element);
}
+ public void close() {}
+ public boolean isClosed() { return false; }
});
IoBuffer buffer = IoBuffer.wrap(xml.getBytes("UTF-8"));
Modified:
mina/vysper/trunk/server/extensions/websockets/src/main/java/org/apache/vysper/xmpp/extension/websockets/WebSocketBackedSessionContext.java
URL:
http://svn.apache.org/viewvc/mina/vysper/trunk/server/extensions/websockets/src/main/java/org/apache/vysper/xmpp/extension/websockets/WebSocketBackedSessionContext.java?rev=1302264&r1=1302263&r2=1302264&view=diff
==============================================================================
---
mina/vysper/trunk/server/extensions/websockets/src/main/java/org/apache/vysper/xmpp/extension/websockets/WebSocketBackedSessionContext.java
(original)
+++
mina/vysper/trunk/server/extensions/websockets/src/main/java/org/apache/vysper/xmpp/extension/websockets/WebSocketBackedSessionContext.java
Mon Mar 19 03:09:21 2012
@@ -60,6 +60,7 @@ public class WebSocketBackedSessionConte
private Connection outbound;
private NonBlockingXMLReader xmlReader = new DefaultNonBlockingXMLReader();
+ private boolean closed = false;
public WebSocketBackedSessionContext(ServerRuntimeContext
serverRuntimeContext) {
super(serverRuntimeContext, new SessionStateHolder());
@@ -174,7 +175,13 @@ public class WebSocketBackedSessionConte
*/
public void close() {
// TODO how to handle?
+ closed = true;
+ }
+
+ /**
+ * Implementation for XMLElementListener.
+ */
+ public boolean isClosed() {
+ return closed;
}
-
-
}