/* * JBoss, Home of Professional Open Source * Copyright 2007, Red Hat Middleware LLC, and individual contributors * as indicated by the @author tags. * See the copyright.txt in the distribution for a * full listing of individual contributors. * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU Lesser General Public License, v. 2.1. * This program is distributed in the hope that it will be useful, but WITHOUT A * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. * You should have received a copy of the GNU Lesser General Public License, * v.2.1 along with this distribution; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * (C) 2005-2006, * @author JBoss Inc. */ /* * Created on 20-Jan-2005 */ package com.jboss.transaction.txinterop.proxy; import java.io.PrintWriter; import java.io.Writer; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Stack; import org.xml.sax.Attributes; import org.xml.sax.ContentHandler; import org.xml.sax.Locator; import org.xml.sax.SAXException; /** * Sax parser for rewriting the XML via the proxy. * @author kevin */ public class WriterSAXHandler implements ContentHandler { /** * Do we need to end the start tag? */ private boolean endStartTag ; /** * The to address. */ private String toAddress ; /** * The identifier. */ private String identifier ; /** * The string buffer for text element content. */ private StringBuffer characterContent = new StringBuffer() ; /** * The new namespaces. */ private List newNamespaces = new ArrayList() ; /** * The stack of active namespaces. */ private Stack namespaceStack = new Stack() ; /** * The active namespaces. */ private Map activeNamespaces = new HashMap() ; /** * The writer for output. */ private final PrintWriter printWriter ; /** * Construct the SAX handler with the output writer. * @param writer The writer for output. */ public WriterSAXHandler(final Writer writer) { this.printWriter = new PrintWriter(writer) ; } /** * Set the document locator. * @param locator The document locator. */ public void setDocumentLocator(final Locator locator) { } /** * Handle the procesing instruction. * @param target The pi target. * @param data The pi data. * @throws SAXException for any errors. */ public void processingInstruction(final String target, final String data) throws SAXException { } /** * Start the document. * @throws SAXException for any errors. */ public void startDocument() throws SAXException { } /** * End the document. * @throws SAXException for any errors. */ public void endDocument() throws SAXException { printWriter.flush() ; } /** * Start a prefix mapping. * @param prefix The namespace prefix. * @param uri The namespace uri. * @throws SAXException for any errors. */ public void startPrefixMapping(final String prefix, final String uri) throws SAXException { newNamespaces.add(new NamespaceInfo(prefix, uri)) ; } /** * End the prefix mapping. * @param prefix The namespace prefix. * @throws SAXException for any errors. */ public void endPrefixMapping(final String prefix) throws SAXException { } /** * Start an element. * @param uri The uri. * @param localName The local name. * @param qName The qualified name. * @param attributes The element attributes. * @throws SAXException for any errors. */ public void startElement(final String uri, final String localName, final String qName, final Attributes attributes) throws SAXException { checkEndStartTag() ; namespaceStack.push(activeNamespaces) ; final Iterator newNamespacesIter = newNamespaces.iterator() ; final String namespaces ; if (newNamespacesIter.hasNext()) { final HashMap newActiveNamespaces = new HashMap(activeNamespaces) ; final StringBuffer namespacesValue = new StringBuffer() ; do { final NamespaceInfo namespaceInfo = (NamespaceInfo)newNamespacesIter.next() ; final String namespacePrefix = namespaceInfo.getPrefix() ; final String namespaceURI = namespaceInfo.getURI() ; newActiveNamespaces.put(namespaceURI, namespacePrefix) ; namespacesValue.append(" xmlns") ; if ((namespacePrefix != null) && (namespacePrefix.length() > 0)) { namespacesValue.append(':') ; namespacesValue.append(namespacePrefix) ; } namespacesValue.append("=\"") ; namespacesValue.append(namespaceURI) ; namespacesValue.append('"') ; } while(newNamespacesIter.hasNext()) ; newNamespaces.clear() ; activeNamespaces = newActiveNamespaces ; namespaces = namespacesValue.toString() ; } else { namespaces = null ; } printWriter.write('<') ; printWriter.write(getQName(uri, localName, qName)) ; if (namespaces != null) { printWriter.write(namespaces) ; } final int numAttributes = attributes.getLength() ; if (numAttributes > 0) { for(int count = 0 ; count < numAttributes ; count++) { printWriter.write(' ') ; final String attributeQName = getQName(attributes.getURI(count), attributes.getLocalName(count), attributes.getQName(count)) ; printWriter.write(attributeQName) ; printWriter.write("=\"") ; final String value = attributes.getValue(count) ; escapeTextContent(value.toCharArray(), 0, value.length()) ; printWriter.write('"') ; } } endStartTag = true ; } /** * End an element. * @param uri The uri. * @param localName The local name. * @param qName The qualified name. * @throws SAXException for any errors. */ public void endElement(final String uri, final String localName, final String qName) throws SAXException { characterContent.setLength(0) ; if (endStartTag) { printWriter.write("/>") ; } else { printWriter.write("</") ; printWriter.write(qName) ; printWriter.write('>') ; } activeNamespaces = (Map)namespaceStack.pop() ; endStartTag = false ; } /** * Process character text. * @param chars The character array. * @param start The start index. * @param length The length of this section. * @throws SAXException for any errors. */ public void characters(char[] chars, int start, int length) throws SAXException { checkEndStartTag() ; escapeTextContent(chars, start, length) ; } /** * Process ignorable white space. * @param chars The character array. * @param start The start index. * @param length The length of this section. * @throws SAXException for any errors. */ public void ignorableWhitespace(char[] chars, int start, int length) throws SAXException { checkEndStartTag() ; printWriter.write(chars, start, length) ; } /** * Skip an entity. * @throws SAXException for any errors. */ public void skippedEntity(final String name) throws SAXException { } /** * Get the qualified name of the element/attribute. * @param uri The qualifed namespace uri or empty string. * @param localName The qualified local name. * @param qName The qualified name. * @return The qualified name of the element/attribute. */ private String getQName(final String uri, final String localName, final String qName) { if (uri.length() > 0) { final String prefix = (String)activeNamespaces.get(uri) ; if (prefix.length() > 0) { return prefix + ":" + localName ; } else { return localName ; } } else { return qName ; } } /** * Check to see if the end of the start tag has been processed. */ private void checkEndStartTag() { if (endStartTag) { printWriter.write('>') ; endStartTag = false ; } } /** * Escape the contents of a text element. * @param chars The character array. * @param start The start index. * @param length The length of this section. */ private void escapeTextContent(final char[] chars, final int start, final int length) { final int end = start + length ; for(int count = start ; count < end ; count++) { final char ch = chars[count] ; switch(ch) { case '<': printWriter.print("<") ; break ; case '>': printWriter.print(">") ; break ; case '&': printWriter.print("&") ; break ; case '"': printWriter.print(""") ; break ; default: printWriter.print(ch) ; break ; } } } /** * Return the to address from the processing. * @return The to address. */ public String getToAddress() { return toAddress ; } /** * Return the identifier from the processing. * @return The identifier. */ public String getIdentifier() { return identifier ; } private static final class NamespaceInfo { /** * The namespace prefix. */ private final String prefix ; /** * The namespace uri. */ private final String uri ; /** * Construct the namespace information. * @param prefix The namespace prefix. * @param uri The namespace uri. */ NamespaceInfo(final String prefix, final String uri) { this.prefix = prefix ; this.uri = uri ; } /** * Get the namespace prefix. * @return The namespace prefix. */ String getPrefix() { return prefix ; } /** * Get the namespace URI. * @return The namespace URI. */ String getURI() { return uri ; } } }