Author: giger
Date: Sun Oct 30 16:56:45 2011
New Revision: 1195192

URL: http://svn.apache.org/viewvc?rev=1195192&view=rev
Log:
Test and impl fixes for the XMLSecurityStreamWriter

Modified:
    webservices/wss4j/branches/swssf/streaming-xml-security/pom.xml
    
webservices/wss4j/branches/swssf/streaming-xml-security/src/main/java/org/swssf/xmlsec/impl/XMLSecurityStreamWriter.java

Modified: webservices/wss4j/branches/swssf/streaming-xml-security/pom.xml
URL: 
http://svn.apache.org/viewvc/webservices/wss4j/branches/swssf/streaming-xml-security/pom.xml?rev=1195192&r1=1195191&r2=1195192&view=diff
==============================================================================
--- webservices/wss4j/branches/swssf/streaming-xml-security/pom.xml (original)
+++ webservices/wss4j/branches/swssf/streaming-xml-security/pom.xml Sun Oct 30 
16:56:45 2011
@@ -48,7 +48,7 @@
             <groupId>commons-codec</groupId>
             <artifactId>commons-codec</artifactId>
             <version>1.4</version>
-        </dependency>        
+        </dependency>
         <dependency>
             <groupId>log4j</groupId>
             <artifactId>log4j</artifactId>
@@ -62,6 +62,12 @@
             <scope>test</scope>
         </dependency>
         <dependency>
+            <groupId>xmlunit</groupId>
+            <artifactId>xmlunit</artifactId>
+            <version>1.3</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
             <groupId>xalan</groupId>
             <artifactId>xalan</artifactId>
             <version>2.7.1</version>

Modified: 
webservices/wss4j/branches/swssf/streaming-xml-security/src/main/java/org/swssf/xmlsec/impl/XMLSecurityStreamWriter.java
URL: 
http://svn.apache.org/viewvc/webservices/wss4j/branches/swssf/streaming-xml-security/src/main/java/org/swssf/xmlsec/impl/XMLSecurityStreamWriter.java?rev=1195192&r1=1195191&r2=1195192&view=diff
==============================================================================
--- 
webservices/wss4j/branches/swssf/streaming-xml-security/src/main/java/org/swssf/xmlsec/impl/XMLSecurityStreamWriter.java
 (original)
+++ 
webservices/wss4j/branches/swssf/streaming-xml-security/src/main/java/org/swssf/xmlsec/impl/XMLSecurityStreamWriter.java
 Sun Oct 30 16:56:45 2011
@@ -23,13 +23,9 @@ import org.swssf.xmlsec.ext.XMLSecurityE
 
 import javax.xml.namespace.NamespaceContext;
 import javax.xml.namespace.QName;
-import javax.xml.stream.XMLEventFactory;
-import javax.xml.stream.XMLStreamException;
-import javax.xml.stream.XMLStreamWriter;
-import javax.xml.stream.events.Attribute;
-import javax.xml.stream.events.EndElement;
-import javax.xml.stream.events.Namespace;
-import javax.xml.stream.events.XMLEvent;
+import javax.xml.stream.*;
+import javax.xml.stream.events.*;
+import java.io.Writer;
 import java.util.*;
 
 /**
@@ -41,11 +37,86 @@ import java.util.*;
 public class XMLSecurityStreamWriter implements XMLStreamWriter {
 
     private XMLEventFactory xmlEventFactory = XMLEventFactory.newFactory();
-
     private OutputProcessorChain outputProcessorChain;
+    private Deque<QName> startElementStack = new ArrayDeque<QName>();
+    private QName openStartElement = null;
+    private List<Attribute> currentAttributes = new LinkedList<Attribute>();
+    private Deque<Map<String, Namespace>> nsStack;
+    private NamespaceContext namespaceContext;
+    private final NamespaceContext defaultNamespaceContext;
+    private boolean haveToWriteEndElement = false;
 
     public XMLSecurityStreamWriter(OutputProcessorChain outputProcessorChain) {
         this.outputProcessorChain = outputProcessorChain;
+        nsStack = new LinkedList<Map<String, Namespace>>();
+        nsStack.push(new LinkedHashMap<String, Namespace>());
+
+        defaultNamespaceContext = new NamespaceContext() {
+            @Override
+            public String getNamespaceURI(String prefix) {
+                Iterator<Map<String, Namespace>> stackIterator = 
nsStack.iterator();
+                while (stackIterator.hasNext()) {
+                    Map<String, Namespace> next = stackIterator.next();
+                    Iterator<Map.Entry<String, Namespace>> mapIterator = 
next.entrySet().iterator();
+                    while (mapIterator.hasNext()) {
+                        Map.Entry<String, Namespace> entry = 
mapIterator.next();
+                        if (prefix.equals(entry.getKey())) {
+                            return entry.getValue().getNamespaceURI();
+                        }
+                    }
+                }
+                if (namespaceContext != null) {
+                    return namespaceContext.getNamespaceURI(prefix);
+                }
+                return null;
+            }
+
+            @Override
+            public String getPrefix(String namespaceURI) {
+                Iterator<Map<String, Namespace>> stackIterator = 
nsStack.iterator();
+                while (stackIterator.hasNext()) {
+                    Map<String, Namespace> next = stackIterator.next();
+                    Iterator<Map.Entry<String, Namespace>> mapIterator = 
next.entrySet().iterator();
+                    while (mapIterator.hasNext()) {
+                        Map.Entry<String, Namespace> entry = 
mapIterator.next();
+                        if 
(namespaceURI.equals(entry.getValue().getNamespaceURI())) {
+                            return entry.getKey();
+                        }
+                    }
+                }
+                if (namespaceContext != null) {
+                    return namespaceContext.getPrefix(namespaceURI);
+                }
+                return null;
+            }
+
+            @Override
+            public Iterator getPrefixes(String namespaceURI) {
+                List<String> prefixList = new ArrayList<String>();
+                if (namespaceContext != null) {
+                    Iterator<String> iterator = 
namespaceContext.getPrefixes(namespaceURI);
+                    while (iterator.hasNext()) {
+                        String next = iterator.next();
+                        prefixList.add(next);
+                    }
+                }
+                Iterator<Map<String, Namespace>> stackIterator = 
nsStack.descendingIterator();
+                while (stackIterator.hasNext()) {
+                    Map<String, Namespace> next = stackIterator.next();
+                    Iterator<Map.Entry<String, Namespace>> mapIterator = 
next.entrySet().iterator();
+                    while (mapIterator.hasNext()) {
+                        Map.Entry<String, Namespace> entry = 
mapIterator.next();
+                        if (prefixList.contains(entry.getKey())) {
+                            prefixList.remove(entry.getKey());
+                        }
+                        if 
(namespaceURI.equals(entry.getValue().getNamespaceURI())) {
+                            prefixList.add(entry.getKey());
+                        }
+                    }
+                }
+                return Collections.unmodifiableList(prefixList).iterator();
+            }
+        };
     }
 
     private void chainProcessEvent(XMLEvent xmlEvent) throws 
XMLStreamException {
@@ -54,45 +125,47 @@ public class XMLSecurityStreamWriter imp
             outputProcessorChain.processEvent(xmlEvent);
         } catch (XMLSecurityException e) {
             throw new XMLStreamException(e);
+        } catch (XMLStreamException e) {
+            String msg = e.getMessage();
+            if (msg != null && msg.contains("Trying to declare prefix xmlns 
(illegal as per NS 1.1 #4)")) {
+                throw new XMLStreamException("If you hit this exception this 
most probably means" +
+                        "you are using the 
javax.xml.transform.stax.StAXResult. Don't use " +
+                        "it. It is buggy as hell.", e);
+            }
+            //NB1: net.java.dev.stax-utils also doesn work: [Fatal Error] 
:4:425: Attribute "xmlns" was already specified for element ...
+            //NB2: The spring version also doesn't work...
+            //it seems it is not trivial to write a StAXResult because I 
couldn't find a implementation which passes the testcases...hmm
+            throw e;
         }
     }
 
-    private Deque<QName> startElementStack = new ArrayDeque<QName>();
-    private QName openStartElement = null;
-    private List<Attribute> currentAttributes = new LinkedList<Attribute>();
-    private List<Namespace> currentNamespaces = new LinkedList<Namespace>();
-
     private void outputOpenStartElement() throws XMLStreamException {
         if (openStartElement != null) {
-            
chainProcessEvent(xmlEventFactory.createStartElement(openStartElement, 
currentAttributes.iterator(), currentNamespaces.iterator()));
+            
chainProcessEvent(xmlEventFactory.createStartElement(openStartElement, 
currentAttributes.iterator(), nsStack.peek().values().iterator()));
             currentAttributes.clear();
-            currentNamespaces.clear();
             openStartElement = null;
         }
+        if (haveToWriteEndElement) {
+            haveToWriteEndElement = false;
+            writeEndElement();
+        }
+        nsStack.push(new LinkedHashMap<String, Namespace>());
     }
 
     public void writeStartElement(String localName) throws XMLStreamException {
         outputOpenStartElement();
-        QName qName;
-        if (localName.contains(":")) {
-            String[] splittedName = localName.split(":");
-            qName = new QName(null, splittedName[1], splittedName[0]);
-        } else {
-            qName = new QName(localName);
-        }
+        QName qName = new QName(localName);
         startElementStack.push(qName);
         openStartElement = qName;
     }
 
     public void writeStartElement(String namespaceURI, String localName) 
throws XMLStreamException {
         outputOpenStartElement();
-        QName qName;
-        if (localName.contains(":")) {
-            String[] splittedName = localName.split(":");
-            qName = new QName(null, splittedName[1], splittedName[0]);
-        } else {
-            qName = new QName(namespaceURI, localName);
+        String prefix = getNamespaceContext().getPrefix(namespaceURI);
+        if (prefix == null) {
+            throw new XMLStreamException("Unbound namespace URI '" + 
namespaceURI + "'");
         }
+        QName qName = new QName(namespaceURI, localName, prefix);
         startElementStack.push(qName);
         openStartElement = qName;
     }
@@ -105,43 +178,42 @@ public class XMLSecurityStreamWriter imp
     }
 
     public void writeEmptyElement(String namespaceURI, String localName) 
throws XMLStreamException {
-        outputOpenStartElement();
-        chainProcessEvent(xmlEventFactory.createStartElement(null, 
namespaceURI, localName));
-        chainProcessEvent(xmlEventFactory.createEndElement(null, namespaceURI, 
localName));
+        writeStartElement(namespaceURI, localName);
+        haveToWriteEndElement = true;
     }
 
     public void writeEmptyElement(String prefix, String localName, String 
namespaceURI) throws XMLStreamException {
-        outputOpenStartElement();
-        chainProcessEvent(xmlEventFactory.createStartElement(prefix, 
namespaceURI, localName));
-        chainProcessEvent(xmlEventFactory.createEndElement(prefix, 
namespaceURI, localName));
+        writeStartElement(prefix, localName, namespaceURI);
+        haveToWriteEndElement = true;
     }
 
     public void writeEmptyElement(String localName) throws XMLStreamException {
-        outputOpenStartElement();
-        chainProcessEvent(xmlEventFactory.createStartElement(null, null, 
localName));
-        chainProcessEvent(xmlEventFactory.createEndElement(null, null, 
localName));
+        writeStartElement(localName);
+        haveToWriteEndElement = true;
     }
 
     public void writeEndElement() throws XMLStreamException {
         outputOpenStartElement();
-
         List<Namespace> namespaceList = new LinkedList<Namespace>();
         QName element = startElementStack.pop();
         namespaceList.add(xmlEventFactory.createNamespace(element.getPrefix(), 
element.getNamespaceURI()));
         EndElement endElement = xmlEventFactory.createEndElement(element, 
namespaceList.iterator());
         chainProcessEvent(endElement);
+        nsStack.pop();
     }
 
     public void writeEndDocument() throws XMLStreamException {
         outputOpenStartElement();
         Iterator<QName> startElements = startElementStack.iterator();
         while (startElements.hasNext()) {
-            
chainProcessEvent(xmlEventFactory.createEndElement(startElementStack.pop(), 
null));
+            
chainProcessEvent(xmlEventFactory.createEndElement(startElements.next(), null));
         }
+        chainProcessEvent(xmlEventFactory.createEndDocument());
     }
 
     public void close() throws XMLStreamException {
         try {
+            writeEndDocument();
             outputProcessorChain.reset();
             outputProcessorChain.doFinal();
         } catch (XMLSecurityException e) {
@@ -161,16 +233,15 @@ public class XMLSecurityStreamWriter imp
     }
 
     public void writeAttribute(String namespaceURI, String localName, String 
value) throws XMLStreamException {
-        //todo: null is not correct!
-        currentAttributes.add(xmlEventFactory.createAttribute(null, 
namespaceURI, localName, value));
+        
currentAttributes.add(xmlEventFactory.createAttribute(getNamespaceContext().getPrefix(namespaceURI),
 namespaceURI, localName, value));
     }
 
     public void writeNamespace(String prefix, String namespaceURI) throws 
XMLStreamException {
-        currentNamespaces.add(xmlEventFactory.createNamespace(prefix, 
namespaceURI));
+        nsStack.peek().put(prefix, xmlEventFactory.createNamespace(prefix, 
namespaceURI));
     }
 
     public void writeDefaultNamespace(String namespaceURI) throws 
XMLStreamException {
-        currentNamespaces.add(xmlEventFactory.createNamespace(namespaceURI));
+        nsStack.peek().put("", xmlEventFactory.createNamespace(namespaceURI));
     }
 
     public void writeComment(String data) throws XMLStreamException {
@@ -180,7 +251,6 @@ public class XMLSecurityStreamWriter imp
 
     public void writeProcessingInstruction(String target) throws 
XMLStreamException {
         outputOpenStartElement();
-        //todo null correct?
         chainProcessEvent(xmlEventFactory.createProcessingInstruction(target, 
null));
     }
 
@@ -199,10 +269,118 @@ public class XMLSecurityStreamWriter imp
         chainProcessEvent(xmlEventFactory.createDTD(dtd));
     }
 
-    public void writeEntityRef(String name) throws XMLStreamException {
+    public void writeEntityRef(final String name) throws XMLStreamException {
         outputOpenStartElement();
-        //todo null not correct
-        chainProcessEvent(xmlEventFactory.createEntityReference(name, null));
+        chainProcessEvent(xmlEventFactory.createEntityReference(name, new 
EntityDeclaration() {
+            @Override
+            public String getPublicId() {
+                return null;
+            }
+
+            @Override
+            public String getSystemId() {
+                return null;
+            }
+
+            @Override
+            public String getName() {
+                return name;
+            }
+
+            @Override
+            public String getNotationName() {
+                return null;
+            }
+
+            @Override
+            public String getReplacementText() {
+                return null;
+            }
+
+            @Override
+            public String getBaseURI() {
+                return null;
+            }
+
+            @Override
+            public int getEventType() {
+                return XMLStreamConstants.ENTITY_REFERENCE;
+            }
+
+            @Override
+            public Location getLocation() {
+                return null;
+            }
+
+            @Override
+            public boolean isStartElement() {
+                return false;
+            }
+
+            @Override
+            public boolean isAttribute() {
+                return false;
+            }
+
+            @Override
+            public boolean isNamespace() {
+                return false;
+            }
+
+            @Override
+            public boolean isEndElement() {
+                return false;
+            }
+
+            @Override
+            public boolean isEntityReference() {
+                return true;
+            }
+
+            @Override
+            public boolean isProcessingInstruction() {
+                return false;
+            }
+
+            @Override
+            public boolean isCharacters() {
+                return false;
+            }
+
+            @Override
+            public boolean isStartDocument() {
+                return false;
+            }
+
+            @Override
+            public boolean isEndDocument() {
+                return false;
+            }
+
+            @Override
+            public StartElement asStartElement() {
+                return null;
+            }
+
+            @Override
+            public EndElement asEndElement() {
+                return null;
+            }
+
+            @Override
+            public Characters asCharacters() {
+                return null;
+            }
+
+            @Override
+            public QName getSchemaType() {
+                return null;
+            }
+
+            @Override
+            public void writeAsEncodedUnicode(Writer writer) throws 
XMLStreamException {
+            }
+        }));
     }
 
     public void writeStartDocument() throws XMLStreamException {
@@ -228,27 +406,34 @@ public class XMLSecurityStreamWriter imp
     }
 
     public String getPrefix(String uri) throws XMLStreamException {
-        //todo
-        return null;
+        return defaultNamespaceContext.getPrefix(uri);
     }
 
     public void setPrefix(String prefix, String uri) throws XMLStreamException 
{
-        //todo
+        nsStack.peek().put(prefix, xmlEventFactory.createNamespace(prefix, 
uri));
+        if (openStartElement != null) {
+            if (openStartElement.getNamespaceURI().equals(uri)) {
+                openStartElement = new 
QName(openStartElement.getNamespaceURI(), openStartElement.getLocalPart(), 
prefix);
+            }
+        }
     }
 
     public void setDefaultNamespace(String uri) throws XMLStreamException {
-        //todo
+        nsStack.peek().put("", xmlEventFactory.createNamespace("", uri));
     }
 
     public void setNamespaceContext(NamespaceContext context) throws 
XMLStreamException {
-        //todo
+        if (context == null) {
+            throw new NullPointerException("context must not be null");
+        }
+        this.namespaceContext = context;
     }
 
     public NamespaceContext getNamespaceContext() {
-        return null;
+        return defaultNamespaceContext;
     }
 
     public Object getProperty(String name) throws IllegalArgumentException {
-        return null;
+        throw new IllegalArgumentException("Properties not supported");
     }
 }


Reply via email to