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