View Javadoc
1   /*
2    * Copyright 2005-2010 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.springframework.ws.soap.saaj.support;
18  
19  import java.util.LinkedHashMap;
20  import java.util.Map;
21  import javax.xml.soap.Name;
22  import javax.xml.soap.SOAPElement;
23  import javax.xml.soap.SOAPEnvelope;
24  import javax.xml.soap.SOAPException;
25  
26  import org.springframework.util.Assert;
27  import org.springframework.util.StringUtils;
28  
29  import org.xml.sax.Attributes;
30  import org.xml.sax.ContentHandler;
31  import org.xml.sax.Locator;
32  import org.xml.sax.SAXException;
33  
34  /**
35   * SAX <code>ContentHandler</code> that transforms callback calls to the creation of SAAJ <code>Node</code>s and
36   * <code>SOAPElement</code>s.
37   *
38   * @author Arjen Poutsma
39   * @see javax.xml.soap.Node
40   * @see javax.xml.soap.SOAPElement
41   * @since 1.0.0
42   */
43  public class SaajContentHandler implements ContentHandler {
44  
45      private SOAPElement element;
46  
47      private final SOAPEnvelope envelope;
48  
49      private Map<String, String> namespaces = new LinkedHashMap<String, String>();
50  
51      /**
52       * Constructs a new instance of the <code>SaajContentHandler</code> that creates children of the given
53       * <code>SOAPElement</code>.
54       *
55       * @param element the element to write to
56       */
57      public SaajContentHandler(SOAPElement element) {
58          Assert.notNull(element, "element must not be null");
59          if (element instanceof SOAPEnvelope) {
60              envelope = (SOAPEnvelope) element;
61          }
62          else {
63              envelope = SaajUtils.getEnvelope(element);
64          }
65          this.element = element;
66      }
67  
68      public void characters(char ch[], int start, int length) throws SAXException {
69          try {
70              String text = new String(ch, start, length);
71              element.addTextNode(text);
72          }
73          catch (SOAPException ex) {
74              throw new SAXException(ex);
75          }
76      }
77  
78      public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
79          try {
80              String childPrefix = getPrefix(qName);
81              SOAPElement child = element.addChildElement(localName, childPrefix, uri);
82              for (int i = 0; i < atts.getLength(); i++) {
83                  if (StringUtils.hasLength(atts.getLocalName(i))) {
84                      String attributePrefix = getPrefix(atts.getQName(i));
85                      if (!"xmlns".equals(atts.getLocalName(i)) && !"xmlns".equals(attributePrefix)) {
86                          Name attributeName = envelope.createName(atts.getLocalName(i), attributePrefix, atts.getURI(i));
87                          child.addAttribute(attributeName, atts.getValue(i));
88                      }
89                  }
90              }
91              for (String namespacePrefix : namespaces.keySet()) {
92                  String namespaceUri = namespaces.get(namespacePrefix);
93                  if (!findParentNamespaceDeclaration(child, namespacePrefix, namespaceUri)) {
94                      child.addNamespaceDeclaration(namespacePrefix, namespaceUri);
95                  }
96              }
97              element = child;
98          }
99          catch (SOAPException ex) {
100             throw new SAXException(ex);
101         }
102     }
103 
104     private boolean findParentNamespaceDeclaration(SOAPElement element, String prefix, String namespaceUri) {
105         String result = element.getNamespaceURI(prefix);
106         if (namespaceUri.equals(result)) {
107             return true;
108         }
109         else {
110             try {
111                 SOAPElement parent = element.getParentElement();
112                 if (parent != null) {
113                     return findParentNamespaceDeclaration(parent, prefix, namespaceUri);
114                 }
115             }
116             catch (UnsupportedOperationException ex) {
117                 // ignore
118             }
119             return false;
120         }
121     }
122 
123     public void endElement(String uri, String localName, String qName) throws SAXException {
124         Assert.isTrue(localName.equals(element.getElementName().getLocalName()), "Invalid element on stack");
125         Assert.isTrue(uri.equals(element.getElementName().getURI()), "Invalid element on stack");
126         element = element.getParentElement();
127     }
128 
129     public void startPrefixMapping(String prefix, String uri) throws SAXException {
130         namespaces.put(prefix, uri);
131     }
132 
133     public void endPrefixMapping(String prefix) throws SAXException {
134         namespaces.remove(prefix);
135     }
136 
137     public void setDocumentLocator(Locator locator) {
138     }
139 
140     public void startDocument() throws SAXException {
141     }
142 
143     public void endDocument() throws SAXException {
144     }
145 
146     public void ignorableWhitespace(char ch[], int start, int length) throws SAXException {
147     }
148 
149     public void processingInstruction(String target, String data) throws SAXException {
150     }
151 
152     public void skippedEntity(String name) throws SAXException {
153     }
154 
155     private String getPrefix(String qName) {
156         int idx = qName.indexOf(':');
157         if (idx != -1) {
158             return qName.substring(0, idx);
159         }
160         else {
161             return null;
162         }
163     }
164 }