Updated to use MINA 2
Cleaned up no longer used classes
Adding Javadocs

git-svn-id: https://svn.apache.org/repos/asf/mina/vysper/branches/nbxml-sax@940435 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/pom.xml b/pom.xml
index 43d4b4c..747b17e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -20,7 +20,7 @@
   <parent>
     <artifactId>vysper-parent</artifactId>
     <groupId>org.apache.vysper</groupId>
-    <version>1.0.0-SNAPSHOT</version>
+    <version>0.6-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <groupId>org.apache.vysper</groupId>
diff --git a/src/main/java/org/apache/vysper/charset/CharsetUtil.java b/src/main/java/org/apache/vysper/charset/CharsetUtil.java
index 4c4f9ab..edf1390 100644
--- a/src/main/java/org/apache/vysper/charset/CharsetUtil.java
+++ b/src/main/java/org/apache/vysper/charset/CharsetUtil.java
@@ -29,6 +29,14 @@
  * @author The Apache MINA Project (dev@mina.apache.org)
  */
 public class CharsetUtil {
+	
+	/**
+	 * Charset decoder for UTF-8
+	 */
     public static final CharsetDecoder UTF8_DECODER = Charset.forName("UTF-8").newDecoder();
+    
+    /**
+     * Charset encoder for UTF-8
+     */
     public static final CharsetEncoder UTF8_ENCODER = Charset.forName("UTF-8").newEncoder();
 }
\ No newline at end of file
diff --git a/src/main/java/org/apache/vysper/xml/decoder/XMLElementBuilderFactory.java b/src/main/java/org/apache/vysper/xml/decoder/XMLElementBuilderFactory.java
index 32ca9a6..fe30364 100644
--- a/src/main/java/org/apache/vysper/xml/decoder/XMLElementBuilderFactory.java
+++ b/src/main/java/org/apache/vysper/xml/decoder/XMLElementBuilderFactory.java
@@ -29,11 +29,20 @@
 
 
 /**
- *
+ * Factory for creating {@link XMLElementBuilder} instances
  * @author The Apache MINA Project (dev@mina.apache.org)
  */
 public class XMLElementBuilderFactory {
 
+	/**
+	 * Create a {@link XMLElementBuilder}
+	 * @param elementName The element local name
+	 * @param namespaceURI The element namespace URI
+	 * @param namespacePrefix The element namespace prefix, or null if namespace should be default
+	 * @param attributes The element attributes or null if no attributes
+	 * @param innerFragments The element inner fragments or null if no inner fragments 
+	 * @return
+	 */
 	public AbstractXMLElementBuilder<?, ?> createBuilder(String elementName, String namespaceURI, String namespacePrefix, List<Attribute> attributes, List<XMLFragment> innerFragments) {
 		return new XMLElementBuilder(elementName, namespaceURI, namespacePrefix, attributes, innerFragments);
 	}
diff --git a/src/main/java/org/apache/vysper/xml/decoder/XMPPContentHandler.java b/src/main/java/org/apache/vysper/xml/decoder/XMPPContentHandler.java
index 70a2fc8..930607e 100644
--- a/src/main/java/org/apache/vysper/xml/decoder/XMPPContentHandler.java
+++ b/src/main/java/org/apache/vysper/xml/decoder/XMPPContentHandler.java
@@ -22,7 +22,6 @@
 import org.apache.vysper.xml.fragment.AbstractXMLElementBuilder;
 import org.apache.vysper.xml.fragment.Renderer;
 import org.apache.vysper.xml.fragment.XMLElement;
-import org.apache.vysper.xml.sax.impl.XMLParser;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.xml.sax.Attributes;
@@ -32,7 +31,7 @@
 
 
 /**
- * partitions the incoming byte stream in particles of XML. either those enclosed by '<' and '>', or the text inbetween.
+ * SAX content handler for the purpose of parsing an incoming XMPP XML stream.
  *
  * @author The Apache MINA Project (dev@mina.apache.org)
  */
@@ -71,6 +70,9 @@
     }
 
 	
+    /**
+     * {@inheritDoc}
+     */
 	public void characters(char[] ch, int start, int length)
 			throws SAXException {
 		// TODO handle start and length
@@ -78,6 +80,9 @@
 		
 	}
 
+    /**
+     * {@inheritDoc}
+     */
 	public void endElement(String uri, String localName, String qName)
 			throws SAXException {
 		depth--;
@@ -93,11 +98,13 @@
 		
 	}
 
+    /**
+     * {@inheritDoc}
+     */
 	public void startElement(String uri, String localName, String qName,
 			Attributes atts) throws SAXException {
 		// increase element depth
 		depth++;
-		
 		if(builder == null) {
 			builder = builderFactory.createBuilder(localName, uri, extractPrefix(qName), null, null);
 		} else {
@@ -107,9 +114,9 @@
 		for(int i = 0; i<atts.getLength(); i++) {
 			builder.addAttribute(atts.getURI(i), atts.getLocalName(i), atts.getValue(i));
 		}
-		
+
 		if(depth == 1) {
-			// outer stanza:stanza element, needs to be dispatched right away
+			// outer stream:stream element, needs to be dispatched right away
 			emitStanza();
 		}
 	}
@@ -137,25 +144,46 @@
 		}
 	}
 
+    /**
+     * {@inheritDoc}
+     */
 	public void endDocument() throws SAXException { /* ignore */ }
 	
+    /**
+     * {@inheritDoc}
+     */
 	public void startPrefixMapping(String prefix, String uri)
 			throws SAXException { /* ignore */ }
 
+    /**
+     * {@inheritDoc}
+     */
 	public void endPrefixMapping(String prefix) throws SAXException { /* ignore */ }
 
+    /**
+     * {@inheritDoc}
+     */
 	public void ignorableWhitespace(char[] ch, int start, int length)
 			throws SAXException { /* ignore */ }
 
+    /**
+     * {@inheritDoc}
+     */
 	public void processingInstruction(String target, String data)
 			throws SAXException { /* ignore */ }
 
+    /**
+     * {@inheritDoc}
+     */
 	public void setDocumentLocator(Locator locator) { /* ignore */ }
 
+    /**
+     * {@inheritDoc}
+     */
 	public void skippedEntity(String name) throws SAXException { /* ignore */ }
 
+    /**
+     * {@inheritDoc}
+     */
 	public void startDocument() throws SAXException { /* ignore */ }
-
-
-	
 }
diff --git a/src/main/java/org/apache/vysper/xml/decoder/XMPPDecoder.java b/src/main/java/org/apache/vysper/xml/decoder/XMPPDecoder.java
index 2e4f730..aea6231 100644
--- a/src/main/java/org/apache/vysper/xml/decoder/XMPPDecoder.java
+++ b/src/main/java/org/apache/vysper/xml/decoder/XMPPDecoder.java
@@ -19,8 +19,8 @@
  */
 package org.apache.vysper.xml.decoder;
 
-import org.apache.mina.common.ByteBuffer;
-import org.apache.mina.common.IoSession;
+import org.apache.mina.core.buffer.IoBuffer;
+import org.apache.mina.core.session.IoSession;
 import org.apache.mina.filter.codec.CumulativeProtocolDecoder;
 import org.apache.mina.filter.codec.ProtocolDecoderOutput;
 import org.apache.vysper.charset.CharsetUtil;
@@ -36,7 +36,9 @@
  */
 public class XMPPDecoder extends CumulativeProtocolDecoder {
 
-    public static final String SESSION_ATTRIBUTE_NAME = "xmppParser";
+    private static final String STREAM_STREAM = "<stream:stream";
+
+	public static final String SESSION_ATTRIBUTE_NAME = "xmppParser";
 
     private XMLElementBuilderFactory builderFactory = new XMLElementBuilderFactory();
     
@@ -56,28 +58,44 @@
 		}
 
 		public void stanza(XMLElement element) {
+			if(element.getName().equals("stream")) {
+				// reset the reader 
+			}
+			
 			protocolDecoder.write(element);
 		}
     }
     
-    @Override
-    public boolean doDecode(IoSession ioSession, ByteBuffer byteBuffer, ProtocolDecoderOutput protocolDecoderOutput) throws Exception {
-
-    	NonBlockingXMLReader reader = (NonBlockingXMLReader) ioSession.getAttribute(SESSION_ATTRIBUTE_NAME);
+    /**
+     * {@inheritDoc}
+     */
+	@Override
+	protected boolean doDecode(IoSession session,
+			IoBuffer in, ProtocolDecoderOutput out) throws Exception {
+    	NonBlockingXMLReader reader = (NonBlockingXMLReader) session.getAttribute(SESSION_ATTRIBUTE_NAME);
     	
-        if (reader == null) {
+    	// 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)) {
         	reader = new DefaultNonBlockingXMLReader();
+        	
+        	// we need to check the jabber:client/jabber:server NS declarations
+        	reader.setFeature(DefaultNonBlockingXMLReader.FEATURE_NAMESPACE_PREFIXES, true);
         	reader.setContentHandler(new XMPPContentHandler(builderFactory));
         	
-            ioSession.setAttribute(SESSION_ATTRIBUTE_NAME, reader);
+        	session.setAttribute(SESSION_ATTRIBUTE_NAME, reader);
         }
         
         XMPPContentHandler contentHandler = (XMPPContentHandler) reader.getContentHandler();
-        contentHandler.setListener(new MinaStanzaListener(protocolDecoderOutput));
+        contentHandler.setListener(new MinaStanzaListener(out));
     	
-        reader.parse(byteBuffer, CharsetUtil.UTF8_DECODER);
+        reader.parse(in, CharsetUtil.UTF8_DECODER);
     	
         // we have parsed what we got, invoke again when more data is available
         return false;
-    }
+	}
 }
\ No newline at end of file
diff --git a/src/main/java/org/apache/vysper/xml/fragment/NamespaceResolver.java b/src/main/java/org/apache/vysper/xml/fragment/NamespaceResolver.java
deleted file mode 100644
index 19d6346..0000000
--- a/src/main/java/org/apache/vysper/xml/fragment/NamespaceResolver.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- *  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.fragment;
-
-
-public interface NamespaceResolver {
-	
-	String resolveUri(String prefix);
-	String resolvePrefix(String uri);	
-}
diff --git a/src/main/java/org/apache/vysper/xml/fragment/Renderer.java b/src/main/java/org/apache/vysper/xml/fragment/Renderer.java
index 9627716..8c2064b 100644
--- a/src/main/java/org/apache/vysper/xml/fragment/Renderer.java
+++ b/src/main/java/org/apache/vysper/xml/fragment/Renderer.java
@@ -37,7 +37,7 @@
     public Renderer(XMLElement element) {
         this.topElement = element;
         
-        StackNamespaceResolver nsResolver = new StackNamespaceResolver();
+        ResolverNamespaceResolver nsResolver = new ResolverNamespaceResolver();
         renderXMLElement(topElement, nsResolver, openElementBuffer, elementContentBuffer, closeElementBuffer);
     }
 
@@ -57,7 +57,7 @@
         return openElementBuffer.toString() + elementContentBuffer.toString() + closeElementBuffer.toString();
     }
 
-    private void renderXMLElement(XMLElement element, StackNamespaceResolver nsResolver, StringBuilder openElementBuffer, StringBuilder elementContentBuffer, StringBuilder closeElementBuffer) {
+    private void renderXMLElement(XMLElement element, ResolverNamespaceResolver nsResolver, StringBuilder openElementBuffer, StringBuilder elementContentBuffer, StringBuilder closeElementBuffer) {
         nsResolver.push(element);
     	
     	openElementBuffer.append("<");
@@ -77,12 +77,15 @@
         }
         
         for (Attribute attribute : element.getAttributes()) {
-        	// make sure we do not render namespace attributes, 
+        	// make sure we do not render namespace attributes,
         	// nor normal attributes containing namespace declarations (probably due to
         	// the parser not correctly creating namespace attributes for these which are then 
         	// copied into for example error responses)
-    		openElementBuffer.append(" ");
-    		renderAttribute(openElementBuffer, attribute, nsResolver);
+        	
+        	if(!attribute.getName().startsWith("xmlns")) {
+        		openElementBuffer.append(" ");
+        		renderAttribute(openElementBuffer, attribute, nsResolver);        		
+        	}
         }
         openElementBuffer.append(">");
 
@@ -108,7 +111,7 @@
     	return name.equals("xmlns") || name.startsWith("xmlns:");
     }
     
-    private void renderElementName(StringBuilder buffer, XMLElement element, NamespaceResolver nsResolver) {
+    private void renderElementName(StringBuilder buffer, XMLElement element, ResolverNamespaceResolver nsResolver) {
         // if the element has a namespace prefix, retrieves the prefix from the defining attribute
         if (element.getNamespacePrefix().length() > 0) {
             buffer.append(element.getNamespacePrefix()).append(COLON);
@@ -123,7 +126,7 @@
         buffer.append(element.getName());
     }
 
-    private void renderAttribute(StringBuilder buffer, Attribute attribute, NamespaceResolver nsResolver) {
+    private void renderAttribute(StringBuilder buffer, Attribute attribute, ResolverNamespaceResolver nsResolver) {
     	String qname;
     	if(!attribute.getNamespaceUri().equals("")) {
     		// attribute is in a namespace, resolve prefix
diff --git a/src/main/java/org/apache/vysper/xml/fragment/StackNamespaceResolver.java b/src/main/java/org/apache/vysper/xml/fragment/ResolverNamespaceResolver.java
similarity index 97%
rename from src/main/java/org/apache/vysper/xml/fragment/StackNamespaceResolver.java
rename to src/main/java/org/apache/vysper/xml/fragment/ResolverNamespaceResolver.java
index 7b2e17a..f1b0884 100644
--- a/src/main/java/org/apache/vysper/xml/fragment/StackNamespaceResolver.java
+++ b/src/main/java/org/apache/vysper/xml/fragment/ResolverNamespaceResolver.java
@@ -29,11 +29,11 @@
 /**
  * Naive implementation, will be replaced in later stages of this change
  */
-public class StackNamespaceResolver implements NamespaceResolver {
+public class ResolverNamespaceResolver {
 	
 	private Stack<XMLElement> elements = new Stack<XMLElement>();
 	
-	public StackNamespaceResolver() {
+	public ResolverNamespaceResolver() {
 	}
 
 	public void push(XMLElement elm) {
diff --git a/src/main/java/org/apache/vysper/xml/fragment/XMLElementVerifier.java b/src/main/java/org/apache/vysper/xml/fragment/XMLElementVerifier.java
index 90a481b..6997de5 100644
--- a/src/main/java/org/apache/vysper/xml/fragment/XMLElementVerifier.java
+++ b/src/main/java/org/apache/vysper/xml/fragment/XMLElementVerifier.java
@@ -20,6 +20,7 @@
 
 package org.apache.vysper.xml.fragment;
 
+import java.util.Collection;
 import java.util.List;
 
 /**
@@ -139,9 +140,13 @@
 	}
 
 	public boolean namespacePresent(String namespaceURI) {
-		for (Attribute attribute : element.getAttributes()) {
-			if (isNamespaceAttribute(attribute)
-					&& attribute.getValue().equals(namespaceURI)) {
+		Collection<String> nsUris = element.getDeclaredNamespaces().values();
+		if(nsUris.contains(namespaceURI)) {
+			return true;
+		}
+		
+		for(Attribute attribute : element.getAttributes()) {
+			if(attribute.getName().startsWith("xmlns") && attribute.getValue().equals(namespaceURI)) {
 				return true;
 			}
 		}
diff --git a/src/main/java/org/apache/vysper/xml/sax/NonBlockingXMLReader.java b/src/main/java/org/apache/vysper/xml/sax/NonBlockingXMLReader.java
index 7ebb292..47fa641 100644
--- a/src/main/java/org/apache/vysper/xml/sax/NonBlockingXMLReader.java
+++ b/src/main/java/org/apache/vysper/xml/sax/NonBlockingXMLReader.java
@@ -22,7 +22,8 @@
 import java.io.IOException;
 import java.nio.charset.CharsetDecoder;
 
-import org.apache.mina.common.ByteBuffer;
+import org.apache.mina.core.buffer.IoBuffer;
+import org.apache.vysper.xml.sax.impl.XMLParser;
 import org.xml.sax.ContentHandler;
 import org.xml.sax.DTDHandler;
 import org.xml.sax.EntityResolver;
@@ -300,7 +301,14 @@
      */
     public ErrorHandler getErrorHandler ();
 
-    public void parse (ByteBuffer buffer, CharsetDecoder decoder) throws IOException, SAXException;
+    /**
+     * Parse XML in non-blocking mode. Issues events to the registered {@link ContentHandler} and {@link ErrorHandler}
+     * @param buffer Buffer containing XML input data 
+     * @param decoder The charset decoder to use for parsing
+     * @throws IOException
+     * @throws SAXException
+     */
+    public void parse (IoBuffer buffer, CharsetDecoder decoder) throws IOException, SAXException;
 
 
 
diff --git a/src/main/java/org/apache/vysper/xml/sax/impl/DefaultNonBlockingXMLReader.java b/src/main/java/org/apache/vysper/xml/sax/impl/DefaultNonBlockingXMLReader.java
index 63cf53b..e43ca8b 100644
--- a/src/main/java/org/apache/vysper/xml/sax/impl/DefaultNonBlockingXMLReader.java
+++ b/src/main/java/org/apache/vysper/xml/sax/impl/DefaultNonBlockingXMLReader.java
@@ -24,7 +24,7 @@
 import java.util.HashMap;
 import java.util.Map;
 
-import org.apache.mina.common.ByteBuffer;
+import org.apache.mina.core.buffer.IoBuffer;
 import org.apache.vysper.xml.sax.NonBlockingXMLReader;
 import org.xml.sax.ContentHandler;
 import org.xml.sax.DTDHandler;
@@ -84,11 +84,11 @@
     	}
     	
     	if(features.containsKey(name)) {
-    		// TODO make configurable fatures and values easier to manage
+    		// TODO make configurable features and values easier to manage
     		if(name.equals(FEATURE_NAMESPACES) && value) {
     			// ok
-    		} else if(name.equals(FEATURE_NAMESPACE_PREFIXES) && !value) {
-    			// ok
+    		} else if(name.equals(FEATURE_NAMESPACE_PREFIXES)) {
+    			features.put(FEATURE_NAMESPACE_PREFIXES, value);
     		} else if(name.equals(FEATURE_COMMENTS_ALLOWED)) {
     			features.put(FEATURE_COMMENTS_ALLOWED, value);
     		} else {
@@ -172,7 +172,7 @@
 	/**
 	 * {@inheritDoc}
 	 */
-    public void parse (ByteBuffer buffer, CharsetDecoder decoder) throws IOException, SAXException {
+    public void parse (IoBuffer buffer, CharsetDecoder decoder) throws IOException, SAXException {
     	if(parser == null) {
     		parser = new XMLParser(contentHandler, errorHandler, features);
     	}
diff --git a/src/main/java/org/apache/vysper/xml/sax/impl/StackNamespaceResolver2.java b/src/main/java/org/apache/vysper/xml/sax/impl/ParserNamespaceResolver.java
similarity index 93%
rename from src/main/java/org/apache/vysper/xml/sax/impl/StackNamespaceResolver2.java
rename to src/main/java/org/apache/vysper/xml/sax/impl/ParserNamespaceResolver.java
index 6e1d9a8..eca1a24 100644
--- a/src/main/java/org/apache/vysper/xml/sax/impl/StackNamespaceResolver2.java
+++ b/src/main/java/org/apache/vysper/xml/sax/impl/ParserNamespaceResolver.java
@@ -24,18 +24,17 @@
 import java.util.Stack;
 import java.util.Map.Entry;
 
-import org.apache.vysper.xml.fragment.NamespaceResolver;
 import org.apache.vysper.xml.fragment.Namespaces;
 
 
 /**
  * Naive implementation, will be replaced in later stages of this change
  */
-public class StackNamespaceResolver2 {
+public class ParserNamespaceResolver {
 	
 	private Stack<Map<String, String>> elements = new Stack<Map<String, String>>();
 	
-	public StackNamespaceResolver2() {
+	public ParserNamespaceResolver() {
 	}
 
 	public void push(Map<String, String> elmXmlns) {
diff --git a/src/main/java/org/apache/vysper/xml/sax/impl/XMLParser.java b/src/main/java/org/apache/vysper/xml/sax/impl/XMLParser.java
index 6b4cbf1..5681a42 100644
--- a/src/main/java/org/apache/vysper/xml/sax/impl/XMLParser.java
+++ b/src/main/java/org/apache/vysper/xml/sax/impl/XMLParser.java
@@ -29,7 +29,7 @@
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-import org.apache.mina.common.ByteBuffer;
+import org.apache.mina.core.buffer.IoBuffer;
 import org.apache.vysper.xml.sax.impl.XMLTokenizer.TokenListener;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -56,11 +56,12 @@
 	private ContentHandler contentHandler;
 	private ErrorHandler errorHandler;
 	
-	private StackNamespaceResolver2 nsResolver = new StackNamespaceResolver2();
+	private ParserNamespaceResolver nsResolver = new ParserNamespaceResolver();
 
 	private static enum State {
 		START,
 		IN_TAG,
+		IN_DECLARATION,
 		IN_END_TAG,
 		AFTER_START_NAME,
 		AFTER_END_NAME,
@@ -93,6 +94,7 @@
 	private boolean sentStartDocument = false; 
 	
 	// features
+	boolean reportNsAttributes = false;
 	boolean commentsAllowed = true;
 
 	
@@ -101,6 +103,7 @@
 		this.errorHandler = errorHandler;
 		
 		commentsAllowed = feature(features, DefaultNonBlockingXMLReader.FEATURE_COMMENTS_ALLOWED, true);
+		reportNsAttributes = feature(features, DefaultNonBlockingXMLReader.FEATURE_NAMESPACE_PREFIXES, false);
 		
 		this.tokenizer = new XMLTokenizer(this);
 	}
@@ -113,18 +116,19 @@
 		}
 	}
 	
-    public void parse(ByteBuffer byteBuffer, CharsetDecoder charsetDecoder) throws SAXException {
+    public void parse(IoBuffer byteBuffer, CharsetDecoder charsetDecoder) throws SAXException {
     	if(state == State.CLOSED) throw new SAXException("Parser is closed");
     	
     	try {
     		tokenizer.parse(byteBuffer, charsetDecoder);
     	} catch(RuntimeException e) {
+    		e.printStackTrace();
     		fatalError(e.getMessage());
     	}
     }
 
 	public void token(char c, String token) throws SAXException {
-		if(log.isDebugEnabled()) {
+		if(log.isTraceEnabled()) {
 			String s = (token == null) ? Character.toString(c) : token;
 			log.trace("Parser got token {} in state {}", s, state);
 		}
@@ -142,6 +146,8 @@
 			// token must be element name or / for a end tag
 			if(c == '/') {
 				state = State.IN_END_TAG;
+			} else if(c == '?') {
+					state = State.IN_DECLARATION;
 			} else if(c == '!') {
 				if(commentsAllowed) {
 					state = State.AFTER_COMMENT_BANG;
@@ -283,6 +289,12 @@
 				return;
 			}
 			break;
+		case IN_DECLARATION:
+			// wait for >
+			if(c == '>') {
+				state = State.START;
+			} 
+			break;
 		}
 	}
 	
@@ -335,17 +347,27 @@
 		List<Attribute> nonNsAttributes = new ArrayList<Attribute>();
 		for(Entry<String, String> attribute: attributes.entrySet()) {
 			String attQname = attribute.getKey();
-			if(!attQname.equals("xmlns")  && !attQname.startsWith("xmlns:")) {
+			
+			// only report NS declaration attributes if the feature is set to
+			if(reportNsAttributes) {
+				nonNsAttributes.add(new Attribute(attQname, null, attQname, attribute.getValue()));
+			} else if(!attQname.equals("xmlns")  && !attQname.startsWith("xmlns:")) {
 				String attLocalName = extractLocalName(attQname);
 				String attPrefix = extractNsPrefix(attQname);
-				String attUri = nsResolver.resolveUri(attPrefix);
-				if(attUri == null) {
-					if(attPrefix.length() > 0) {
-						fatalError("Undeclared namespace prefix: " + attPrefix);
-						return;
-					} else {
-						attUri = "";
+				String attUri;
+				if(attPrefix.length() > 0) { 
+					attUri = nsResolver.resolveUri(attPrefix);
+					if(attUri == null) {
+						if(attPrefix.length() > 0) {
+							fatalError("Undeclared namespace prefix: " + attPrefix);
+							return;
+						} else {
+							attUri = "";
+						}
 					}
+				} else {
+					// by default, attributes are in the empty namespace
+					attUri = "";
 				}
 				nonNsAttributes.add(new Attribute(attLocalName, attUri, attQname, attribute.getValue()));
 			}
@@ -434,7 +456,7 @@
 		
 		// make sure we send a start document event
 		startDocument();
-		
+
 		errorHandler.fatalError(new SAXParseException(message, null));
 	}
 	
diff --git a/src/main/java/org/apache/vysper/xml/sax/impl/XMLTokenizer.java b/src/main/java/org/apache/vysper/xml/sax/impl/XMLTokenizer.java
index 51ea440..a190c55 100644
--- a/src/main/java/org/apache/vysper/xml/sax/impl/XMLTokenizer.java
+++ b/src/main/java/org/apache/vysper/xml/sax/impl/XMLTokenizer.java
@@ -22,7 +22,7 @@
 import java.nio.charset.CharacterCodingException;
 import java.nio.charset.CharsetDecoder;
 
-import org.apache.mina.common.ByteBuffer;
+import org.apache.mina.core.buffer.IoBuffer;
 import org.apache.vysper.charset.CharsetUtil;
 import org.xml.sax.SAXException;
 
@@ -63,7 +63,7 @@
      * @return the new particle or NULL, if the buffer was exhausted before the particle was completed
      * @throws Exception
      */
-    public void parse(ByteBuffer byteBuffer, CharsetDecoder decoder) throws SAXException {
+    public void parse(IoBuffer byteBuffer, CharsetDecoder decoder) throws SAXException {
         lastPosition = byteBuffer.position();
 
         while (byteBuffer.hasRemaining() && state != State.CLOSED) {
@@ -140,13 +140,13 @@
     	return c == '<' || c == '>' || c == '-' || c == '!' || c == '/' || c == '?' || c == '='; 
     }
 
-    private void emit(char token, ByteBuffer byteBuffer) throws SAXException {
+    private void emit(char token, IoBuffer byteBuffer) throws SAXException {
     	listener.token(token, null);
     	
     	lastPosition = byteBuffer.position();
     }
     
-    private void emit(ByteBuffer byteBuffer, CharsetDecoder decoder) throws SAXException {
+    private void emit(IoBuffer byteBuffer, CharsetDecoder decoder) throws SAXException {
     	int endPosition = byteBuffer.position();
     	int oldLimit = byteBuffer.limit();
     	byteBuffer.position(lastPosition);
diff --git a/src/test/java/org/apache/vysper/xml/fragment/StackNamespaceResolverTestCase.java b/src/test/java/org/apache/vysper/xml/fragment/StackNamespaceResolverTestCase.java
index 8707d70..f8cf637 100644
--- a/src/test/java/org/apache/vysper/xml/fragment/StackNamespaceResolverTestCase.java
+++ b/src/test/java/org/apache/vysper/xml/fragment/StackNamespaceResolverTestCase.java
@@ -21,7 +21,7 @@
 
 import org.apache.vysper.xml.fragment.Attribute;
 import org.apache.vysper.xml.fragment.Namespaces;
-import org.apache.vysper.xml.fragment.StackNamespaceResolver;
+import org.apache.vysper.xml.fragment.ResolverNamespaceResolver;
 import org.apache.vysper.xml.fragment.XMLElement;
 import org.apache.vysper.xml.fragment.XMLElementBuilder;
 
@@ -31,7 +31,7 @@
  */
 public class StackNamespaceResolverTestCase extends TestCase {
 
-	private StackNamespaceResolver resolver = new StackNamespaceResolver();
+	private ResolverNamespaceResolver resolver = new ResolverNamespaceResolver();
 
 	public void testPushSingleElement() {
 		XMLElement elm = new XMLElementBuilder("foo")
diff --git a/src/test/java/org/apache/vysper/xml/sax/impl/AbstractAsyncXMLReaderTestCase.java b/src/test/java/org/apache/vysper/xml/sax/impl/AbstractAsyncXMLReaderTestCase.java
index eced69c..7b7a5d3 100644
--- a/src/test/java/org/apache/vysper/xml/sax/impl/AbstractAsyncXMLReaderTestCase.java
+++ b/src/test/java/org/apache/vysper/xml/sax/impl/AbstractAsyncXMLReaderTestCase.java
@@ -27,12 +27,9 @@
 
 import junit.framework.TestCase;
 
-import org.apache.mina.common.ByteBuffer;
+import org.apache.mina.core.buffer.IoBuffer;
 import org.apache.vysper.charset.CharsetUtil;
 import org.apache.vysper.xml.sax.NonBlockingXMLReader;
-import org.apache.vysper.xml.sax.impl.Attribute;
-import org.apache.vysper.xml.sax.impl.DefaultAttributes;
-import org.apache.vysper.xml.sax.impl.DefaultNonBlockingXMLReader;
 import org.apache.vysper.xml.sax.impl.TestHandler.CharacterEvent;
 import org.apache.vysper.xml.sax.impl.TestHandler.EndDocumentEvent;
 import org.apache.vysper.xml.sax.impl.TestHandler.EndElementEvent;
@@ -123,7 +120,7 @@
 		reader.setContentHandler(handler);
 		reader.setErrorHandler(handler);
 
-		reader.parse(ByteBuffer.wrap(xml.getBytes("UTF-8")), CharsetUtil.UTF8_DECODER);
+		reader.parse(IoBuffer.wrap(xml.getBytes("UTF-8")), CharsetUtil.UTF8_DECODER);
 		
 		return handler.getEvents();
 	}
diff --git a/src/test/java/org/apache/vysper/xml/sax/impl/DefaultAsyncXMLReaderTestCase.java b/src/test/java/org/apache/vysper/xml/sax/impl/DefaultAsyncXMLReaderTestCase.java
index 3abc152..b114163 100644
--- a/src/test/java/org/apache/vysper/xml/sax/impl/DefaultAsyncXMLReaderTestCase.java
+++ b/src/test/java/org/apache/vysper/xml/sax/impl/DefaultAsyncXMLReaderTestCase.java
@@ -19,10 +19,9 @@
  */
 package org.apache.vysper.xml.sax.impl;
 
-import org.apache.mina.common.ByteBuffer;
+import org.apache.mina.core.buffer.IoBuffer;
 import org.apache.vysper.charset.CharsetUtil;
 import org.apache.vysper.xml.sax.NonBlockingXMLReader;
-import org.apache.vysper.xml.sax.impl.DefaultNonBlockingXMLReader;
 import org.xml.sax.DTDHandler;
 import org.xml.sax.SAXException;
 import org.xml.sax.SAXNotRecognizedException;
@@ -41,11 +40,11 @@
 		reader.setErrorHandler(handler);
 
 		// causes a fatal error
-		reader.parse(ByteBuffer.wrap("<root></error>".getBytes("UTF-8")), CharsetUtil.UTF8_DECODER);
+		reader.parse(IoBuffer.wrap("<root></error>".getBytes("UTF-8")), CharsetUtil.UTF8_DECODER);
 		
 		try {
 			// not allowed to parse after an error
-			reader.parse(ByteBuffer.wrap("<root>".getBytes("UTF-8")), CharsetUtil.UTF8_DECODER);
+			reader.parse(IoBuffer.wrap("<root>".getBytes("UTF-8")), CharsetUtil.UTF8_DECODER);
 			fail("Must throw SAXException");
 		} catch(SAXException e) {
 			// OK
@@ -60,11 +59,11 @@
 		reader.setErrorHandler(handler);
 
 		// causes a fatal error
-		reader.parse(ByteBuffer.wrap("<root></root>".getBytes("UTF-8")), CharsetUtil.UTF8_DECODER);
+		reader.parse(IoBuffer.wrap("<root></root>".getBytes("UTF-8")), CharsetUtil.UTF8_DECODER);
 		
 		try {
 			// not allowed to parse after end of document
-			reader.parse(ByteBuffer.wrap("<root>".getBytes("UTF-8")), CharsetUtil.UTF8_DECODER);
+			reader.parse(IoBuffer.wrap("<root>".getBytes("UTF-8")), CharsetUtil.UTF8_DECODER);
 			fail("Must throw SAXException");
 		} catch(SAXException e) {
 			// OK
@@ -138,7 +137,7 @@
 	
 	public void testSetFeatureDuringParse() throws Exception {
 		DefaultNonBlockingXMLReader reader = new DefaultNonBlockingXMLReader();
-		reader.parse(ByteBuffer.wrap("<foo />".getBytes("UTF-8")), CharsetUtil.UTF8_DECODER);
+		reader.parse(IoBuffer.wrap("<foo />".getBytes("UTF-8")), CharsetUtil.UTF8_DECODER);
 		try {
 			reader.setFeature("http://xml.org/sax/features/namespaces", true);
 			fail("Must throw SAXNotSupportedException");
diff --git a/src/test/java/org/apache/vysper/xml/sax/impl/ParseNamespacesTestCase.java b/src/test/java/org/apache/vysper/xml/sax/impl/ParseNamespacesTestCase.java
index cf2d1f4..a9020f6 100644
--- a/src/test/java/org/apache/vysper/xml/sax/impl/ParseNamespacesTestCase.java
+++ b/src/test/java/org/apache/vysper/xml/sax/impl/ParseNamespacesTestCase.java
@@ -52,6 +52,17 @@
 		assertFalse(events.hasNext());
 	}
 
+	public void testDefaultedAttribute() throws Exception {
+		Iterator<TestEvent> events = parse("<root att='foo' xmlns='urn:test'></root>").iterator();
+
+		assertStartDocument(events.next());
+		assertStartElement("urn:test", "root", "root", attributes(new Attribute("att", "", "att", "foo")), events.next());
+		assertEndElement("urn:test", "root", "root", events.next());
+		assertEndDocument(events.next());
+		
+		assertFalse(events.hasNext());
+	}
+
 	
 	public void testSimpleQNameElement() throws Exception {
 		Iterator<TestEvent> events = parse("<p:root xmlns:p='urn:test'></p:root>").iterator();
diff --git a/src/test/java/org/apache/vysper/xml/sax/impl/ParseXmlDeclarationTestCase.java b/src/test/java/org/apache/vysper/xml/sax/impl/ParseXmlDeclarationTestCase.java
new file mode 100644
index 0000000..816b830
--- /dev/null
+++ b/src/test/java/org/apache/vysper/xml/sax/impl/ParseXmlDeclarationTestCase.java
@@ -0,0 +1,44 @@
+/*
+ *  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.Iterator;
+
+import org.apache.vysper.xml.sax.impl.TestHandler.TestEvent;
+
+
+/**
+ * @author The Apache MINA Project (dev@mina.apache.org)
+ */
+public class ParseXmlDeclarationTestCase extends AbstractAsyncXMLReaderTestCase {
+
+	public void testEmptyElement() throws Exception {
+		Iterator<TestEvent> events = parse("<?xml version=\"1.0\"?><root />").iterator();
+
+		assertStartDocument(events.next());
+		// no event for the declaration
+		assertStartElement("", "root", "root", events.next());
+		assertEndElement("", "root", "root", events.next());
+		assertEndDocument(events.next());
+		
+		assertNoMoreevents(events);
+	}
+
+}
\ No newline at end of file
diff --git a/src/test/java/org/apache/vysper/xml/sax/impl/XMPPContentHandlerTestCase.java b/src/test/java/org/apache/vysper/xml/sax/impl/XMPPContentHandlerTestCase.java
index 66379c2..1e4836e 100644
--- a/src/test/java/org/apache/vysper/xml/sax/impl/XMPPContentHandlerTestCase.java
+++ b/src/test/java/org/apache/vysper/xml/sax/impl/XMPPContentHandlerTestCase.java
@@ -25,13 +25,12 @@
 
 import junit.framework.TestCase;
 
-import org.apache.mina.common.ByteBuffer;
+import org.apache.mina.core.buffer.IoBuffer;
 import org.apache.vysper.charset.CharsetUtil;
 import org.apache.vysper.xml.decoder.XMPPContentHandler;
 import org.apache.vysper.xml.decoder.XMPPContentHandler.StanzaListener;
 import org.apache.vysper.xml.fragment.XMLElement;
 import org.apache.vysper.xml.sax.NonBlockingXMLReader;
-import org.apache.vysper.xml.sax.impl.DefaultNonBlockingXMLReader;
 
 /**
  * @author The Apache MINA Project (dev@mina.apache.org)
@@ -67,7 +66,7 @@
 	}
 	
 	private void parse(NonBlockingXMLReader reader, String xml) throws Exception {
-		reader.parse(ByteBuffer.wrap(xml.getBytes("UTF-8")), CharsetUtil.UTF8_DECODER);	
+		reader.parse(IoBuffer.wrap(xml.getBytes("UTF-8")), CharsetUtil.UTF8_DECODER);	
 	}
 
 }
\ No newline at end of file
diff --git a/src/test/java/org/apache/vysper/xml/sax/perf/PerfTest.java b/src/test/java/org/apache/vysper/xml/sax/perf/PerfTest.java
index aa06b58..4c3315f 100644
--- a/src/test/java/org/apache/vysper/xml/sax/perf/PerfTest.java
+++ b/src/test/java/org/apache/vysper/xml/sax/perf/PerfTest.java
@@ -19,23 +19,44 @@
  */
 package org.apache.vysper.xml.sax.perf;
 
-import org.apache.mina.common.ByteBuffer;
+import org.apache.mina.core.buffer.IoBuffer;
 import org.apache.vysper.charset.CharsetUtil;
+import org.apache.vysper.xml.decoder.XMPPContentHandler;
+import org.apache.vysper.xml.decoder.XMPPContentHandler.StanzaListener;
+import org.apache.vysper.xml.fragment.XMLElement;
 import org.apache.vysper.xml.sax.impl.DefaultNonBlockingXMLReader;
 
 /**
  * 
  * @author The Apache MINA Project (dev@mina.apache.org)
  */
-public class PerfTest  {
+public class PerfTest   {
 
+	private static class CounterStanzaListener implements StanzaListener {
+
+		public int counter = 0;
+		
+		public void stanza(XMLElement element) {
+			counter++;
+		}
+		
+	}
+	
+	private static final String SINGLE_LEVEL_XML = "<child att='foo' att2='bar'></child>";
+	private static final String NESTED_XML = "<child att='foo' att2='bar'><child2><child3><child4></child4></child3></child2></child>";
+
+	
 	public static void main(String[] args) throws Exception {
 		
-		ByteBuffer opening = ByteBuffer.wrap("<p:root xmlns:p='http://example.com'>".getBytes("UTF-8"));
-		ByteBuffer buffer = ByteBuffer.wrap("<child att='foo' att2='bar' />text".getBytes("UTF-8"));
+		IoBuffer opening = IoBuffer.wrap("<p:root xmlns:p='http://example.com'>".getBytes("UTF-8"));
+		IoBuffer buffer = IoBuffer.wrap(SINGLE_LEVEL_XML.getBytes("UTF-8"));
 		
 		DefaultNonBlockingXMLReader reader = new DefaultNonBlockingXMLReader();
-
+		CounterStanzaListener listener = new CounterStanzaListener();
+		XMPPContentHandler contentHandler = new XMPPContentHandler();
+		contentHandler.setListener(listener);
+		reader.setContentHandler(contentHandler);
+		
 		StopWatch watch = new StopWatch();
 		
 		reader.parse(opening, CharsetUtil.UTF8_DECODER);
@@ -45,6 +66,7 @@
 		}
 		watch.stop();
 
+		System.out.println(listener.counter + " stanzas parsed");
 		System.out.println(watch);
 		
 	}