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/05/05 15:19:14 UTC

svn commit: r941276 - in /mina/vysper/trunk/nbxml/src: main/java/org/apache/vysper/xml/decoder/ main/java/org/apache/vysper/xml/sax/impl/ test/java/org/apache/vysper/xml/sax/impl/

Author: ngn
Date: Wed May  5 13:19:13 2010
New Revision: 941276

URL: http://svn.apache.org/viewvc?rev=941276&view=rev
Log:
Moving stream restart into the parser, rather than in the decoder

Added:
    mina/vysper/trunk/nbxml/src/test/java/org/apache/vysper/xml/sax/impl/StreamRestartTestCase.java
Modified:
    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/DefaultNonBlockingXMLReader.java
    mina/vysper/trunk/nbxml/src/main/java/org/apache/vysper/xml/sax/impl/XMLParser.java
    mina/vysper/trunk/nbxml/src/test/java/org/apache/vysper/xml/sax/impl/AbstractAsyncXMLReaderTestCase.java
    mina/vysper/trunk/nbxml/src/test/java/org/apache/vysper/xml/sax/impl/ParseCommentsTestCase.java
    mina/vysper/trunk/nbxml/src/test/java/org/apache/vysper/xml/sax/impl/TestHandler.java

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=941276&r1=941275&r2=941276&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 Wed May  5 13:19:13 2010
@@ -187,5 +187,8 @@ public class XMPPContentHandler implemen
     /**
      * {@inheritDoc}
      */
-	public void startDocument() throws SAXException { /* ignore */ }
+	public void startDocument() throws SAXException { 
+		depth = 0;
+		builder = null;
+	}
 }

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=941276&r1=941275&r2=941276&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 Wed May  5 13:19:13 2010
@@ -75,17 +75,16 @@ public class XMPPDecoder extends Cumulat
 			IoBuffer in, ProtocolDecoderOutput out) throws Exception {
     	NonBlockingXMLReader reader = (NonBlockingXMLReader) session.getAttribute(SESSION_ATTRIBUTE_NAME);
     	
-    	// peek to find XML stream resets
-    	// TODO this is a bit ugly, revisit
-    	in.mark();
-    	String peek = in.getString(14, CharsetUtil.UTF8_DECODER);
-    	in.reset();
-
-    	if (reader == null || STREAM_STREAM.equals(peek) || (peek != null && peek.startsWith(XML_DECL))) {
+    	if (reader == null) {
         	reader = new DefaultNonBlockingXMLReader();
         	
         	// we need to check the jabber:client/jabber:server NS declarations
         	reader.setFeature(DefaultNonBlockingXMLReader.FEATURE_NAMESPACE_PREFIXES, true);
+        	
+        	// allow parser to restart XML stream
+        	reader.setFeature(DefaultNonBlockingXMLReader.FEATURE_RESTART_ALLOWED, true);
+        	reader.setProperty(DefaultNonBlockingXMLReader.PROPERTY_RESTART_QNAME, "stream:stream");
+        	
         	reader.setContentHandler(new XMPPContentHandler(builderFactory));
         	
         	session.setAttribute(SESSION_ATTRIBUTE_NAME, reader);

Modified: mina/vysper/trunk/nbxml/src/main/java/org/apache/vysper/xml/sax/impl/DefaultNonBlockingXMLReader.java
URL: http://svn.apache.org/viewvc/mina/vysper/trunk/nbxml/src/main/java/org/apache/vysper/xml/sax/impl/DefaultNonBlockingXMLReader.java?rev=941276&r1=941275&r2=941276&view=diff
==============================================================================
--- mina/vysper/trunk/nbxml/src/main/java/org/apache/vysper/xml/sax/impl/DefaultNonBlockingXMLReader.java (original)
+++ mina/vysper/trunk/nbxml/src/main/java/org/apache/vysper/xml/sax/impl/DefaultNonBlockingXMLReader.java Wed May  5 13:19:13 2010
@@ -44,6 +44,8 @@ public class DefaultNonBlockingXMLReader
 	public static final String FEATURE_NAMESPACES = "http://xml.org/sax/features/namespaces";
 	public static final String FEATURE_NAMESPACE_PREFIXES = "http://xml.org/sax/features/namespace-prefixes";
 	public static final String FEATURE_COMMENTS_ALLOWED = "http://mina.apache.org/vysper/features/comments-allowed";
+	public static final String FEATURE_RESTART_ALLOWED = "http://mina.apache.org/vysper/features/restart-allowed";
+	public static final String PROPERTY_RESTART_QNAME = "http://mina.apache.org/vysper/properties/restart-qname";
 	
 	private ErrorHandler errorHandler = new DefaultHandler();
 	private ContentHandler contentHandler = new DefaultHandler();
@@ -51,12 +53,14 @@ public class DefaultNonBlockingXMLReader
 	private XMLParser parser;
 	
 	private Map<String, Boolean> features = new HashMap<String, Boolean>();
+	private Map<String, Object> properties = new HashMap<String, Object>();
 	
 	public DefaultNonBlockingXMLReader() {
 		// set default features
 		features.put(FEATURE_NAMESPACES, true);
 		features.put(FEATURE_NAMESPACE_PREFIXES, false);
 		features.put(FEATURE_COMMENTS_ALLOWED, true);
+		features.put(FEATURE_RESTART_ALLOWED, false);
 	}
 	
 	/**
@@ -91,6 +95,8 @@ public class DefaultNonBlockingXMLReader
     			features.put(FEATURE_NAMESPACE_PREFIXES, value);
     		} else if(name.equals(FEATURE_COMMENTS_ALLOWED)) {
     			features.put(FEATURE_COMMENTS_ALLOWED, value);
+    		} else if(name.equals(FEATURE_RESTART_ALLOWED)) {
+    			features.put(FEATURE_RESTART_ALLOWED, value);
     		} else {
     			throw new SAXNotSupportedException("Not supported");
     		}
@@ -105,7 +111,7 @@ public class DefaultNonBlockingXMLReader
 	 */
     public Object getProperty (String name)
 	throws SAXNotRecognizedException, SAXNotSupportedException {
-    	return null;
+    	return properties.get(name);
     }
 
 	/**
@@ -113,7 +119,7 @@ public class DefaultNonBlockingXMLReader
 	 */
     public void setProperty (String name, Object value)
     	throws SAXNotRecognizedException, SAXNotSupportedException {
-    	
+    	properties.put(name, value);
     }
 
 	/**
@@ -174,7 +180,7 @@ public class DefaultNonBlockingXMLReader
 	 */
     public void parse (IoBuffer buffer, CharsetDecoder decoder) throws IOException, SAXException {
     	if(parser == null) {
-    		parser = new XMLParser(contentHandler, errorHandler, features);
+    		parser = new XMLParser(contentHandler, errorHandler, features, properties);
     	}
     	
 		parser.parse(buffer, decoder);

Modified: mina/vysper/trunk/nbxml/src/main/java/org/apache/vysper/xml/sax/impl/XMLParser.java
URL: http://svn.apache.org/viewvc/mina/vysper/trunk/nbxml/src/main/java/org/apache/vysper/xml/sax/impl/XMLParser.java?rev=941276&r1=941275&r2=941276&view=diff
==============================================================================
--- mina/vysper/trunk/nbxml/src/main/java/org/apache/vysper/xml/sax/impl/XMLParser.java (original)
+++ mina/vysper/trunk/nbxml/src/main/java/org/apache/vysper/xml/sax/impl/XMLParser.java Wed May  5 13:19:13 2010
@@ -94,16 +94,22 @@ public class XMLParser implements TokenL
 	private boolean sentStartDocument = false; 
 	
 	// features
-	boolean reportNsAttributes = false;
-	boolean commentsAllowed = true;
+	private boolean reportNsAttributes = false;
+	private boolean commentsAllowed = true;
+	private boolean restartsAllowed = false;
+	private String restartQname = null;
 
 	
-	public XMLParser(ContentHandler contentHandler, ErrorHandler errorHandler, Map<String, Boolean> features) {
+	public XMLParser(ContentHandler contentHandler, ErrorHandler errorHandler, Map<String, Boolean> features, Map<String, Object> properties) {
 		this.contentHandler = contentHandler;
 		this.errorHandler = errorHandler;
 		
 		commentsAllowed = feature(features, DefaultNonBlockingXMLReader.FEATURE_COMMENTS_ALLOWED, true);
 		reportNsAttributes = feature(features, DefaultNonBlockingXMLReader.FEATURE_NAMESPACE_PREFIXES, false);
+		reportNsAttributes = feature(features, DefaultNonBlockingXMLReader.FEATURE_NAMESPACE_PREFIXES, false);
+		restartsAllowed = feature(features, DefaultNonBlockingXMLReader.FEATURE_RESTART_ALLOWED, false);
+		restartQname = (String)properties.get(DefaultNonBlockingXMLReader.PROPERTY_RESTART_QNAME);
+		
 		
 		this.tokenizer = new XMLTokenizer(this);
 	}
@@ -148,6 +154,7 @@ public class XMLParser implements TokenL
 				state = State.IN_END_TAG;
 			} else if(c == '?') {
 					state = State.IN_DECLARATION;
+					xmlDeclaration();
 			} else if(c == '!') {
 				if(commentsAllowed) {
 					state = State.AFTER_COMMENT_BANG;
@@ -320,6 +327,31 @@ public class XMLParser implements TokenL
         return NAME_PATTERN.matcher(name).find() && !NAME_PREFIX_PATTERN.matcher(name).find();
 	}
 	
+	private boolean needsRestart() {
+		return elements.size() > 0;
+	}
+	
+	private void restart() {
+		log.trace("Restarting XML stream");
+		
+		elements.clear();
+		nsResolver = new ParserNamespaceResolver();
+		sentStartDocument = false;
+	}
+	
+	private void xmlDeclaration() {
+		// we got an XML declaration, should we restart stream?
+		// TODO could also be a PI, if we want to support PIs, this code needs further attention
+		if(needsRestart()) {
+			if(restartsAllowed) {
+				// ok, restart
+				restart();
+			} else {
+				// restarts not allowed, fail 
+			}
+		}
+	}
+	
 	private void startDocument() throws SAXException {
 		if(!sentStartDocument) {
 			contentHandler.startDocument();
@@ -330,6 +362,11 @@ public class XMLParser implements TokenL
 	private void startElement() throws SAXException {
 		log.trace("StartElement {}", qname);
 		
+		// check if this should restart stream
+		if(restartsAllowed && needsRestart() && qname.equals(restartQname)) {
+			restart();
+		}
+		
 		if(elements.isEmpty()) {
 			startDocument();
 		}

Modified: mina/vysper/trunk/nbxml/src/test/java/org/apache/vysper/xml/sax/impl/AbstractAsyncXMLReaderTestCase.java
URL: http://svn.apache.org/viewvc/mina/vysper/trunk/nbxml/src/test/java/org/apache/vysper/xml/sax/impl/AbstractAsyncXMLReaderTestCase.java?rev=941276&r1=941275&r2=941276&view=diff
==============================================================================
--- mina/vysper/trunk/nbxml/src/test/java/org/apache/vysper/xml/sax/impl/AbstractAsyncXMLReaderTestCase.java (original)
+++ mina/vysper/trunk/nbxml/src/test/java/org/apache/vysper/xml/sax/impl/AbstractAsyncXMLReaderTestCase.java Wed May  5 13:19:13 2010
@@ -117,10 +117,10 @@ public abstract class AbstractAsyncXMLRe
 	}
 
 	protected List<TestEvent> parse(String xml) throws Exception {
-		return parse(xml, null);
+		return parse(xml, null, null);
 	}
 	
-	protected List<TestEvent> parse(String xml, Map<String, Boolean> features) throws Exception {
+	protected List<TestEvent> parse(String xml, Map<String, Boolean> features, Map<String, Object> properties) throws Exception {
 		TestHandler handler = new TestHandler();
 		NonBlockingXMLReader reader = new DefaultNonBlockingXMLReader();
 		if(features != null) {
@@ -128,6 +128,11 @@ public abstract class AbstractAsyncXMLRe
 				reader.setFeature(feature.getKey(), feature.getValue());
 			}
 		}
+		if(properties != null) {
+			for(Entry<String, Object> property : properties.entrySet()) {
+				reader.setProperty(property.getKey(), property.getValue());
+			}
+		}
 		
 		reader.setContentHandler(handler);
 		reader.setErrorHandler(handler);

Modified: mina/vysper/trunk/nbxml/src/test/java/org/apache/vysper/xml/sax/impl/ParseCommentsTestCase.java
URL: http://svn.apache.org/viewvc/mina/vysper/trunk/nbxml/src/test/java/org/apache/vysper/xml/sax/impl/ParseCommentsTestCase.java?rev=941276&r1=941275&r2=941276&view=diff
==============================================================================
--- mina/vysper/trunk/nbxml/src/test/java/org/apache/vysper/xml/sax/impl/ParseCommentsTestCase.java (original)
+++ mina/vysper/trunk/nbxml/src/test/java/org/apache/vysper/xml/sax/impl/ParseCommentsTestCase.java Wed May  5 13:19:13 2010
@@ -117,7 +117,7 @@ public class ParseCommentsTestCase exten
 		Map<String, Boolean> features = new HashMap<String, Boolean>();
 		features.put("http://mina.apache.org/vysper/features/comments-allowed", false);
 		
-		Iterator<TestEvent> events = parse("<root><!-- comment --></root>", features).iterator();
+		Iterator<TestEvent> events = parse("<root><!-- comment --></root>", features, null).iterator();
 
 		assertStartDocument(events.next());
 		assertStartElement("", "root", "root", events.next());

Added: mina/vysper/trunk/nbxml/src/test/java/org/apache/vysper/xml/sax/impl/StreamRestartTestCase.java
URL: http://svn.apache.org/viewvc/mina/vysper/trunk/nbxml/src/test/java/org/apache/vysper/xml/sax/impl/StreamRestartTestCase.java?rev=941276&view=auto
==============================================================================
--- mina/vysper/trunk/nbxml/src/test/java/org/apache/vysper/xml/sax/impl/StreamRestartTestCase.java (added)
+++ mina/vysper/trunk/nbxml/src/test/java/org/apache/vysper/xml/sax/impl/StreamRestartTestCase.java Wed May  5 13:19:13 2010
@@ -0,0 +1,76 @@
+/*
+ *  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.xml.sax.impl;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.vysper.xml.sax.impl.TestHandler.TestEvent;
+
+
+/**
+ * @author The Apache MINA Project (dev@mina.apache.org)
+ */
+public class StreamRestartTestCase extends AbstractAsyncXMLReaderTestCase {
+
+	public void testRestartByXmlDeclaration() throws Exception {
+		Map<String, Boolean> features = new HashMap<String, Boolean>();
+		features.put(DefaultNonBlockingXMLReader.FEATURE_RESTART_ALLOWED, true);
+
+		Iterator<TestEvent> events = parse("<?xml version=\"1.0\"?>\n <root><?xml version=\"1.0\"?><root />", features, null).iterator();
+
+		assertStartDocument(events.next());
+		// no event for the declaration
+		assertStartElement("", "root", "root", events.next());
+		
+		// parser gets restarted
+		assertStartDocument(events.next());
+		assertStartElement("", "root", "root", events.next());
+		assertEndElement("", "root", "root", events.next());
+		assertEndDocument(events.next());
+		
+		assertNoMoreevents(events);
+	}
+
+	public void testRestartByQName() throws Exception {
+		Map<String, Boolean> features = new HashMap<String, Boolean>();
+		features.put(DefaultNonBlockingXMLReader.FEATURE_RESTART_ALLOWED, true);
+
+		Map<String, Object> properties = new HashMap<String, Object>();
+		properties.put(DefaultNonBlockingXMLReader.PROPERTY_RESTART_QNAME, "root");
+
+		Iterator<TestEvent> events = parse("<root><foo><root />", features, properties).iterator();
+
+		assertStartDocument(events.next());
+		// no event for the declaration
+		assertStartElement("", "root", "root", events.next());
+		assertStartElement("", "foo", "foo", events.next());
+		
+		// parser gets restarted
+		assertStartDocument(events.next());
+		assertStartElement("", "root", "root", events.next());
+		assertEndElement("", "root", "root", events.next());
+		assertEndDocument(events.next());
+		
+		assertNoMoreevents(events);
+	}
+
+}

Modified: mina/vysper/trunk/nbxml/src/test/java/org/apache/vysper/xml/sax/impl/TestHandler.java
URL: http://svn.apache.org/viewvc/mina/vysper/trunk/nbxml/src/test/java/org/apache/vysper/xml/sax/impl/TestHandler.java?rev=941276&r1=941275&r2=941276&view=diff
==============================================================================
--- mina/vysper/trunk/nbxml/src/test/java/org/apache/vysper/xml/sax/impl/TestHandler.java (original)
+++ mina/vysper/trunk/nbxml/src/test/java/org/apache/vysper/xml/sax/impl/TestHandler.java Wed May  5 13:19:13 2010
@@ -213,6 +213,7 @@ public class TestHandler implements Cont
 
 	public void startElement(String uri, String localName, String qName,
 			Attributes atts) throws SAXException {
+		System.out.println("sax start element " + qName);
 		events.add(new StartElementEvent(uri, localName, qName, atts));
 		
 	}