You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@labs.apache.org by be...@apache.org on 2007/10/30 22:19:31 UTC
svn commit: r590469 - in /labs/vysper/src: main/java/org/apache/vysper/mina/
main/java/org/apache/vysper/mina/codec/
main/java/org/apache/vysper/xmpp/writer/
main/java/org/apache/vysper/xmpp/xmldecoder/
test/java/org/apache/vysper/mina/codec/ test/java...
Author: berndf
Date: Tue Oct 30 14:19:28 2007
New Revision: 590469
URL: http://svn.apache.org/viewvc?rev=590469&view=rev
Log:
[vysper] completed first version of xml streaming parser
improved server stanza writing
Added:
labs/vysper/src/main/java/org/apache/vysper/mina/codec/StanzaWriteInfo.java
labs/vysper/src/main/java/org/apache/vysper/xmpp/xmldecoder/UnsupportedXMLException.java
Modified:
labs/vysper/src/main/java/org/apache/vysper/mina/MinaBackedSessionContext.java
labs/vysper/src/main/java/org/apache/vysper/mina/codec/StanzaWriterProtocolEncoder.java
labs/vysper/src/main/java/org/apache/vysper/xmpp/writer/StanzaWriter.java
labs/vysper/src/main/java/org/apache/vysper/xmpp/xmldecoder/XMLParticle.java
labs/vysper/src/main/java/org/apache/vysper/xmpp/xmldecoder/XMLRawToFragementConverter.java
labs/vysper/src/test/java/org/apache/vysper/mina/codec/XMLStreamTokenizerTestCase.java
labs/vysper/src/test/java/org/apache/vysper/xmpp/xmldecoder/XMLRawToFragementConverterConvertErrorTestCase.java
Modified: labs/vysper/src/main/java/org/apache/vysper/mina/MinaBackedSessionContext.java
URL: http://svn.apache.org/viewvc/labs/vysper/src/main/java/org/apache/vysper/mina/MinaBackedSessionContext.java?rev=590469&r1=590468&r2=590469&view=diff
==============================================================================
--- labs/vysper/src/main/java/org/apache/vysper/mina/MinaBackedSessionContext.java (original)
+++ labs/vysper/src/main/java/org/apache/vysper/mina/MinaBackedSessionContext.java Tue Oct 30 14:19:28 2007
@@ -1,16 +1,18 @@
package org.apache.vysper.mina;
+import org.apache.mina.common.IoSession;
+import org.apache.vysper.mina.codec.StanzaWriteInfo;
+import org.apache.vysper.xmpp.protocol.SessionStateHolder;
import org.apache.vysper.xmpp.server.DefaultSessionContext;
import org.apache.vysper.xmpp.server.ServerRuntimeContext;
-import org.apache.vysper.xmpp.protocol.SessionStateHolder;
-import org.apache.vysper.xmpp.writer.StanzaWriter;
import org.apache.vysper.xmpp.stanza.Stanza;
-import org.apache.mina.common.IoSession;
+import org.apache.vysper.xmpp.writer.StanzaWriter;
/**
*/
public class MinaBackedSessionContext extends DefaultSessionContext implements StanzaWriter {
private IoSession minaSession;
+ private boolean openingStanzaWritten = false;
public MinaBackedSessionContext(
ServerRuntimeContext serverRuntimeContext,
@@ -25,7 +27,8 @@
}
public void write(Stanza stanza) {
- minaSession.write(stanza);
+ minaSession.write(new StanzaWriteInfo(stanza, !openingStanzaWritten));
+ openingStanzaWritten = true;
}
public void close() {
Added: labs/vysper/src/main/java/org/apache/vysper/mina/codec/StanzaWriteInfo.java
URL: http://svn.apache.org/viewvc/labs/vysper/src/main/java/org/apache/vysper/mina/codec/StanzaWriteInfo.java?rev=590469&view=auto
==============================================================================
--- labs/vysper/src/main/java/org/apache/vysper/mina/codec/StanzaWriteInfo.java (added)
+++ labs/vysper/src/main/java/org/apache/vysper/mina/codec/StanzaWriteInfo.java Tue Oct 30 14:19:28 2007
@@ -0,0 +1,61 @@
+/***********************************************************************
+ * Copyright (c) 2006-2007 The Apache Software Foundation. *
+ * All rights reserved. *
+ * ------------------------------------------------------------------- *
+ * Licensed 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.mina.codec;
+
+import org.apache.vysper.xmpp.stanza.Stanza;
+
+/**
+ * a stanza plus the flags indicating which parts of the stanza are actually to be written.
+ * this is especially useful when opening the stream, where the opening tag is never/not immediately closed.
+ */
+public class StanzaWriteInfo {
+ private Stanza stanza = null;
+ private boolean writeProlog = true;
+ private boolean writeOpeningElement = true;
+ private boolean writeContent = true;
+ private boolean writeClosingElement = true;
+
+ public StanzaWriteInfo(Stanza stanza) {
+ this.stanza = stanza;
+ }
+
+ public StanzaWriteInfo(Stanza stanza, boolean isStreamOpening) {
+ this.stanza = stanza;
+ this.writeProlog = isStreamOpening;
+ this.writeClosingElement = !isStreamOpening;
+ }
+
+ public Stanza getStanza() {
+ return stanza;
+ }
+
+ public boolean isWriteProlog() {
+ return writeProlog;
+ }
+
+ public boolean isWriteOpeningElement() {
+ return writeOpeningElement;
+ }
+
+ public boolean isWriteContent() {
+ return writeContent;
+ }
+
+ public boolean isWriteClosingElement() {
+ return writeClosingElement;
+ }
+}
Modified: labs/vysper/src/main/java/org/apache/vysper/mina/codec/StanzaWriterProtocolEncoder.java
URL: http://svn.apache.org/viewvc/labs/vysper/src/main/java/org/apache/vysper/mina/codec/StanzaWriterProtocolEncoder.java?rev=590469&r1=590468&r2=590469&view=diff
==============================================================================
--- labs/vysper/src/main/java/org/apache/vysper/mina/codec/StanzaWriterProtocolEncoder.java (original)
+++ labs/vysper/src/main/java/org/apache/vysper/mina/codec/StanzaWriterProtocolEncoder.java Tue Oct 30 14:19:28 2007
@@ -21,32 +21,30 @@
import org.apache.mina.filter.codec.ProtocolEncoder;
import org.apache.mina.filter.codec.ProtocolEncoderOutput;
import org.apache.vysper.charset.CharsetUtil;
-import org.apache.vysper.xmpp.stanza.Stanza;
-import org.apache.vysper.xmpp.writer.StanzaWriter;
import org.apache.vysper.xmpp.xmlfragment.Renderer;
+import org.apache.vysper.xmpp.writer.StanzaWriter;
import java.nio.charset.CharsetEncoder;
/**
* connects MINA low level protocol and session stanza writer
*/
-public class StanzaWriterProtocolEncoder implements ProtocolEncoder, StanzaWriter {
+public class StanzaWriterProtocolEncoder implements ProtocolEncoder {
public void encode(IoSession ioSession, Object o, ProtocolEncoderOutput protocolEncoderOutput) throws Exception {
- if (!(o instanceof Stanza)) {
- throw new IllegalArgumentException("StanzaWriterProtocolEncoder only handles Stanza objects");
+ if (!(o instanceof StanzaWriteInfo)) {
+ throw new IllegalArgumentException("StanzaWriterProtocolEncoder only handles StanzaWriteInfo objects");
}
- Stanza stanza = (Stanza) o;
-
- Renderer renderer = new Renderer(stanza);
- System.out.print(renderer.getOpeningElement() + renderer.getElementContent());
+ StanzaWriteInfo stanzaWriteInfo = (StanzaWriteInfo) o;
+
+ Renderer renderer = new Renderer(stanzaWriteInfo.getStanza());
- boolean isFirst = true;
ByteBuffer byteBuffer = ByteBuffer.allocate(16).setAutoExpand(true);
- byteBuffer.putString(renderer.getOpeningElement(), getSessionEncoder());
- byteBuffer.putString(renderer.getElementContent(), getSessionEncoder());
- if (isFirst) byteBuffer.putString(renderer.getClosingElement(), getSessionEncoder());
+ if (stanzaWriteInfo.isWriteProlog()) byteBuffer.putString(StanzaWriter.XML_PROLOG, getSessionEncoder());
+ if (stanzaWriteInfo.isWriteOpeningElement()) byteBuffer.putString(renderer.getOpeningElement(), getSessionEncoder());
+ if (stanzaWriteInfo.isWriteContent()) byteBuffer.putString(renderer.getElementContent(), getSessionEncoder());
+ if (stanzaWriteInfo.isWriteClosingElement()) byteBuffer.putString(renderer.getClosingElement(), getSessionEncoder());
byteBuffer.flip();
protocolEncoderOutput.write(byteBuffer);
@@ -54,10 +52,6 @@
public void dispose(IoSession ioSession) throws Exception {
- }
-
- public void write(Stanza stanza) {
- System.err.println(stanza.toString());
}
public void close() {
Modified: labs/vysper/src/main/java/org/apache/vysper/xmpp/writer/StanzaWriter.java
URL: http://svn.apache.org/viewvc/labs/vysper/src/main/java/org/apache/vysper/xmpp/writer/StanzaWriter.java?rev=590469&r1=590468&r2=590469&view=diff
==============================================================================
--- labs/vysper/src/main/java/org/apache/vysper/xmpp/writer/StanzaWriter.java (original)
+++ labs/vysper/src/main/java/org/apache/vysper/xmpp/writer/StanzaWriter.java Tue Oct 30 14:19:28 2007
@@ -25,6 +25,7 @@
* when the writer is closed
*/
public interface StanzaWriter {
+ String XML_PROLOG = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
void write(Stanza stanza);
Added: labs/vysper/src/main/java/org/apache/vysper/xmpp/xmldecoder/UnsupportedXMLException.java
URL: http://svn.apache.org/viewvc/labs/vysper/src/main/java/org/apache/vysper/xmpp/xmldecoder/UnsupportedXMLException.java?rev=590469&view=auto
==============================================================================
--- labs/vysper/src/main/java/org/apache/vysper/xmpp/xmldecoder/UnsupportedXMLException.java (added)
+++ labs/vysper/src/main/java/org/apache/vysper/xmpp/xmldecoder/UnsupportedXMLException.java Tue Oct 30 14:19:28 2007
@@ -0,0 +1,39 @@
+/***********************************************************************
+ * Copyright (c) 2006-2007 The Apache Software Foundation. *
+ * All rights reserved. *
+ * ------------------------------------------------------------------- *
+ * Licensed 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.xmldecoder;
+
+/**
+ * some valid XML is unsupported in XMPP. see RFC3920/11.
+ * this exception signals XML, which might be valid, but is unsupported by our parser
+ */
+public class UnsupportedXMLException extends DecodingException {
+ public UnsupportedXMLException() {
+ super();
+ }
+
+ public UnsupportedXMLException(String s) {
+ super(s);
+ }
+
+ public UnsupportedXMLException(String s, Throwable throwable) {
+ super(s, throwable);
+ }
+
+ public UnsupportedXMLException(Throwable throwable) {
+ super(throwable);
+ }
+}
Modified: labs/vysper/src/main/java/org/apache/vysper/xmpp/xmldecoder/XMLParticle.java
URL: http://svn.apache.org/viewvc/labs/vysper/src/main/java/org/apache/vysper/xmpp/xmldecoder/XMLParticle.java?rev=590469&r1=590468&r2=590469&view=diff
==============================================================================
--- labs/vysper/src/main/java/org/apache/vysper/xmpp/xmldecoder/XMLParticle.java (original)
+++ labs/vysper/src/main/java/org/apache/vysper/xmpp/xmldecoder/XMLParticle.java Tue Oct 30 14:19:28 2007
@@ -98,19 +98,16 @@
public String getElementName() throws DecodingException {
if (elementName != null) return elementName;
+ Matcher matcher = null;
if (isClosingOnlyElement()) {
- Matcher matcher = PATTERN_NAME_FROM_CLOSINGONLY_ELEMENT.matcher(content);
+ matcher = PATTERN_NAME_FROM_CLOSINGONLY_ELEMENT.matcher(content);
if (!matcher.matches()) throw new DecodingException("closing element name could not be determined by parser for " + content);
- elementName = matcher.group(1);
- return elementName;
} else if (isOpeningElement()) {
- Matcher matcher = PATTERN_NAME_FROM_OPENING_ELEMENT.matcher(content);
- boolean matches = matcher.matches();
- if (!matches) throw new DecodingException("opening element name could not be determined by parser for " + content);
- elementName = matcher.group(1); // do caching
- return elementName;
- }
- return null;
+ matcher = PATTERN_NAME_FROM_OPENING_ELEMENT.matcher(content);
+ if (!matcher.matches()) throw new DecodingException("opening element name could not be determined by parser for " + content);
+ } else throw new IllegalStateException("element must be opening or closing (or both)");
+ elementName = matcher.group(1);
+ return elementName;
}
}
Modified: labs/vysper/src/main/java/org/apache/vysper/xmpp/xmldecoder/XMLRawToFragementConverter.java
URL: http://svn.apache.org/viewvc/labs/vysper/src/main/java/org/apache/vysper/xmpp/xmldecoder/XMLRawToFragementConverter.java?rev=590469&r1=590468&r2=590469&view=diff
==============================================================================
--- labs/vysper/src/main/java/org/apache/vysper/xmpp/xmldecoder/XMLRawToFragementConverter.java (original)
+++ labs/vysper/src/main/java/org/apache/vysper/xmpp/xmldecoder/XMLRawToFragementConverter.java Tue Oct 30 14:19:28 2007
@@ -83,6 +83,10 @@
while (!particles.isEmpty()) {
XMLParticle particle = particles.remove(0);
+ if (particle.isOpeningElement() && particle.getContent().startsWith("<!--")) {
+ throw new UnsupportedXMLException("XML comments are unsupported in XMPP");
+ }
+
if (particle.isOpeningElement() && particle.isClosingElement()) {
// has no inner elements, no need to find matching closer
XMLElement completeElement = getElementForOpening(particle, createStanza);
@@ -134,11 +138,14 @@
return createElementOrStanza(elementName, attributes, null, (List<XMLFragment>) null, createStanza);
}
- private XMLElement createElementOrStanza(String elementName, List<Attribute> attributes, String namespace, List<XMLFragment> innerFragments, boolean createStanza) {
+ private XMLElement createElementOrStanza(String elementName, List<Attribute> attributes, String namespace, List<XMLFragment> innerFragments, boolean createStanza) throws DecodingException {
int i = elementName.indexOf(":");
if (i >= 1) {
namespace = elementName.substring(i+1);
elementName = elementName.substring(0, i);
+ if ("".equals(namespace) || "".equals(elementName)) throw new DecodingException("illegal element name " + namespace + ":" + elementName);
+ } else if (i == 0) {
+ throw new DecodingException("':' is not a valid element name");
}
if (createStanza) return new Stanza(elementName, namespace, attributes, innerFragments);
else return new XMLElement(elementName, namespace, attributes, innerFragments);
@@ -181,7 +188,17 @@
break;
case BEFORE_KEY:
if (Character.isWhitespace(character)) stack.pop();
- else if (character == '/' || character == '!' || character == '?' || character == '>' ) {
+ else if (character == '/' || character == '!' || character == '?') {
+ character = stack.pop();
+ if (stack.isEmpty()) {
+ throw new DecodingException("preliminary end of element");
+ }
+ character = stack.pop();
+ if (character != '>' ) throw new DecodingException("preliminary end of element");
+ return attributes;
+ } else if (character == '>' ) {
+ character = stack.pop();
+ if (!stack.isEmpty()) throw new DecodingException("preliminary closing of tag");
return attributes;
} else if (Character.isLetterOrDigit(character)) {
currentState = AttributeParseState.IN_KEY;
Modified: labs/vysper/src/test/java/org/apache/vysper/mina/codec/XMLStreamTokenizerTestCase.java
URL: http://svn.apache.org/viewvc/labs/vysper/src/test/java/org/apache/vysper/mina/codec/XMLStreamTokenizerTestCase.java?rev=590469&r1=590468&r2=590469&view=diff
==============================================================================
--- labs/vysper/src/test/java/org/apache/vysper/mina/codec/XMLStreamTokenizerTestCase.java (original)
+++ labs/vysper/src/test/java/org/apache/vysper/mina/codec/XMLStreamTokenizerTestCase.java Tue Oct 30 14:19:28 2007
@@ -22,6 +22,7 @@
import org.apache.vysper.charset.CharsetUtil;
import org.apache.vysper.xmpp.xmlfragment.XMLFragment;
import org.apache.vysper.xmpp.xmlfragment.XMLText;
+import org.apache.vysper.xmpp.writer.StanzaWriter;
import java.nio.charset.CharsetEncoder;
import java.util.ArrayList;
@@ -39,7 +40,7 @@
ByteBuffer firstByteBuffer = createByteBuffer();
ByteBuffer secondByteBuffer = createByteBuffer();
- String stanza = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\r" +
+ String stanza = StanzaWriter.XML_PROLOG + "\n\r" +
"<stream:stream to='example.com' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'>" +
"<trailing-stanza/>";
@@ -77,7 +78,7 @@
MockProtocolDecoderOutput protocolDecoderOutput = new MockProtocolDecoderOutput();
ByteBuffer prolog = createByteBuffer();
- prolog.putString("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\r", CHARSET_ENCODER_UTF8).flip();
+ prolog.putString(StanzaWriter.XML_PROLOG + "\n\r", CHARSET_ENCODER_UTF8).flip();
decoder.decode(session, prolog, protocolDecoderOutput);
assertEquals(1, protocolDecoderOutput.size());
Modified: labs/vysper/src/test/java/org/apache/vysper/xmpp/xmldecoder/XMLRawToFragementConverterConvertErrorTestCase.java
URL: http://svn.apache.org/viewvc/labs/vysper/src/test/java/org/apache/vysper/xmpp/xmldecoder/XMLRawToFragementConverterConvertErrorTestCase.java?rev=590469&r1=590468&r2=590469&view=diff
==============================================================================
--- labs/vysper/src/test/java/org/apache/vysper/xmpp/xmldecoder/XMLRawToFragementConverterConvertErrorTestCase.java (original)
+++ labs/vysper/src/test/java/org/apache/vysper/xmpp/xmldecoder/XMLRawToFragementConverterConvertErrorTestCase.java Tue Oct 30 14:19:28 2007
@@ -143,11 +143,87 @@
List<XMLParticle> particles = new ArrayList<XMLParticle>();
XMLParticle particle = new XMLParticle("< />");
+ try {
+ String name = particle.getElementName();
+ fail("closing xml element must not be empty (direct access)");
+ } catch (DecodingException e) {
+ // test succeded
+ }
+ particles.add(particle);
+ try {
+ xmlRawToFragementConverter.convert(particles);
+ fail("closing xml element must not be empty (indirect access)");
+ } catch (DecodingException e) {
+ // test succeded
+ }
+ }
+
+ public void testElementNameColon_Only() throws DecodingException {
+ List<XMLParticle> particles = new ArrayList<XMLParticle>();
+
+ XMLParticle particle = new XMLParticle("<: />");
String name = particle.getElementName();
+ assertEquals(":", name);
+ particles.add(particle);
+ try {
+ xmlRawToFragementConverter.convert(particles);
+ fail("illegal element name ':'");
+ } catch (DecodingException e) {
+ // test succeded
+ }
+ }
+
+ public void testElementNameColon_NoNamespace() throws DecodingException {
+ List<XMLParticle> particles = new ArrayList<XMLParticle>();
+
+ XMLParticle particle = new XMLParticle("<:name />");
+ particles.add(particle);
+ try {
+ xmlRawToFragementConverter.convert(particles);
+ fail("illegal element name");
+ } catch (DecodingException e) {
+ // test succeded
+ }
+ }
+
+ public void testElementNameColon_NoName() throws DecodingException {
+ List<XMLParticle> particles = new ArrayList<XMLParticle>();
+
+ XMLParticle particle = new XMLParticle("<namespace: />");
particles.add(particle);
try {
xmlRawToFragementConverter.convert(particles);
- fail("closing xml element must not be empty");
+ fail("illegal element name");
+ } catch (DecodingException e) {
+ // test succeded
+ }
+ }
+
+ public void testMoreEmptyElements() throws DecodingException {
+ try {
+ String name = new XMLParticle("<>").getElementName();
+ fail("xml element name is mandatory");
+ } catch (DecodingException e) {
+ // test succeded
+ }
+
+ try {
+ String name = new XMLParticle("< >").getElementName();
+ fail("xml element name is mandatory");
+ } catch (DecodingException e) {
+ // test succeded
+ }
+
+ try {
+ String name = new XMLParticle("< attr='k' >").getElementName();
+ fail("xml element name is mandatory");
+ } catch (DecodingException e) {
+ // test succeded
+ }
+
+ try {
+ String name = new XMLParticle("< attr='k' ></>").getElementName();
+ fail("xml element name is mandatory");
} catch (DecodingException e) {
// test succeded
}
@@ -177,4 +253,33 @@
}
}
+ public void testUnsupportedXMLComment() {
+ List<XMLParticle> particles = new ArrayList<XMLParticle>();
+
+ particles.add(new XMLParticle("<!-- unsupported comment -->"));
+ try {
+ xmlRawToFragementConverter.convert(particles);
+ fail("comments are unsupported");
+ } catch (UnsupportedXMLException e) {
+ // test succeded
+ } catch (DecodingException e) {
+ fail("more generic exception as expected was thrown");
+ }
+ }
+
+ public void testUnsupportedXMLCommentNested() {
+ List<XMLParticle> particles = new ArrayList<XMLParticle>();
+
+ particles.add(new XMLParticle("<name attr='val'>"));
+ particles.add(new XMLParticle("<!-- unsupported comment -->"));
+ particles.add(new XMLParticle("</name >"));
+ try {
+ xmlRawToFragementConverter.convert(particles);
+ fail("comments are unsupported");
+ } catch (UnsupportedXMLException e) {
+ // test succeded
+ } catch (DecodingException e) {
+ fail("more generic exception as expected was thrown");
+ }
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@labs.apache.org
For additional commands, e-mail: commits-help@labs.apache.org