package org.ebayopensource.turmeric.runtime.binding.impl.parser.xml; import java.util.ArrayList; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import javax.xml.namespace.NamespaceContext; import javax.xml.namespace.QName; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; /** * IgnoreRootElementStreamWriter is used to transform the output of source XMLStreamWriter to * a payload that the top level element is skipped in the final payload. Here is a sample code * how to use IgnoreRootElementStreamWriter. * <code> * XMLStreamWriter xmlStreamWriter = new IgnoreRootElementStreamWriter(sourceStreamWriter); * </code> * If sourceStreamWriter outputs * <code> * <s:a xmlns:s="http://www.ebayopensource.org/sample"> * <s:b> * ... * </s:b> * </s: a> * </code> * xmlStreamWriter will output * <code> * <b xmlns:s="http://www.ebayopensource.org/sample"> * </b> * </code> * * if sourceStreamWriter represents an XML payload whose root element has multiple child elements, * Using IgnoreRootElementStreamWriter would results in XMLStreamException of * "Trying to output second root". * * * Limitations: Only services whose request and response contains single element all the time * can enable NoRoot support. The reason is that if there are multiple XML elements inside a * request/response, removed the root element invalidated the xml's single root requirement. * * @author wdeng */ public class IgnoreRootElementStreamWriter implements XMLStreamWriter { private static final Logger s_logger = Logger.getLogger("IgnoreRootElementStreamWriter"); private XMLStreamWriter m_writer; private int m_currentElementLevel = 0; private List<QName> m_namespaceToWrite = new ArrayList<QName>(); public IgnoreRootElementStreamWriter(XMLStreamWriter writer) { m_writer = writer; } @Override public void close() throws XMLStreamException { m_writer.close(); } @Override public void flush() throws XMLStreamException { m_writer.flush(); } @Override public NamespaceContext getNamespaceContext() { if (s_logger.isLoggable(Level.FINEST)) { s_logger.log(Level.FINEST, "getNamespaceContext(): " + m_writer.getNamespaceContext()); } return m_writer.getNamespaceContext(); } @Override public String getPrefix(String arg0) throws XMLStreamException { if (s_logger.isLoggable(Level.FINEST)) { s_logger.log(Level.FINEST, "getPrefix('" + arg0 + "'): " + m_writer.getPrefix(arg0)); } return m_writer.getPrefix(arg0); } @Override public Object getProperty(String arg0) throws IllegalArgumentException { if (s_logger.isLoggable(Level.FINEST)) { s_logger.log(Level.FINEST, "getProperty('" + arg0 + "'): " + m_writer.getProperty(arg0)); } return m_writer.getProperty(arg0); } @Override public void setDefaultNamespace(String arg0) throws XMLStreamException { if (s_logger.isLoggable(Level.FINEST)) { s_logger.log(Level.FINEST, "setDefaultNamespace('" + arg0 + "'): "); } m_writer.setDefaultNamespace(arg0); } @Override public void setNamespaceContext(NamespaceContext arg0) throws XMLStreamException { if (s_logger.isLoggable(Level.FINEST)) { s_logger.log(Level.FINEST, "setNamespaceContext('" + arg0 + "'): "); } m_writer.setNamespaceContext(arg0); } @Override public void setPrefix(String arg0, String arg1) throws XMLStreamException { if (s_logger.isLoggable(Level.FINEST)) { s_logger.log(Level.FINEST, "setPrefix('" + arg0 + "', " + arg1 + "): "); } m_writer.setPrefix(arg0, arg1); } @Override public void writeAttribute(String arg0, String arg1) throws XMLStreamException { if (s_logger.isLoggable(Level.FINEST)) { s_logger.log(Level.FINEST, "writeAttribute('" + arg0 + "', " + arg1 + "): "); } m_writer.writeAttribute(arg0, arg1); } @Override public void writeAttribute(String arg0, String arg1, String arg2) throws XMLStreamException { if (s_logger.isLoggable(Level.FINEST)) { s_logger.log(Level.FINEST, "writeAttribute('" + arg0 + "', " + arg1 + "): "); } m_writer.writeAttribute(arg0, arg1, arg2); } @Override public void writeAttribute(String arg0, String arg1, String arg2, String arg3) throws XMLStreamException { if (s_logger.isLoggable(Level.FINEST)) { s_logger.log(Level.FINEST, "writeAttribute('" + arg0 + "', " + arg1 + ", " + arg2 + "): "); } m_writer.writeAttribute(arg0, arg1, arg2, arg3); } @Override public void writeCData(String arg0) throws XMLStreamException { if (s_logger.isLoggable(Level.FINEST)) { s_logger.log(Level.FINEST, "writeCData('" + arg0 + "'): "); } m_writer.writeCData(arg0); } @Override public void writeCharacters(String arg0) throws XMLStreamException { if (s_logger.isLoggable(Level.FINEST)) { s_logger.log(Level.FINEST, "writeCharacters('" + arg0 + "'): "); } m_writer.writeCharacters(arg0); } @Override public void writeCharacters(char[] arg0, int arg1, int arg2) throws XMLStreamException { if (s_logger.isLoggable(Level.FINEST)) { s_logger.log(Level.FINEST, "writeCharacters('" + new String(arg0) + "', " + arg1 + ", " + arg2 + "): "); } m_writer.writeCharacters(arg0, arg1, arg2); } @Override public void writeComment(String arg0) throws XMLStreamException { if (s_logger.isLoggable(Level.FINEST)) { s_logger.log(Level.FINEST, "writeComment('" + arg0 + "'): "); } m_writer.writeComment(arg0); } @Override public void writeDTD(String arg0) throws XMLStreamException { if (s_logger.isLoggable(Level.FINEST)) { s_logger.log(Level.FINEST, "writeDTD('" + arg0 + "'): "); } m_writer.writeDTD(arg0); } @Override public void writeDefaultNamespace(String arg0) throws XMLStreamException { if (s_logger.isLoggable(Level.FINEST)) { s_logger.log(Level.FINEST, "writeDefaultNamespace('" + arg0 + "'): "); } m_writer.writeDefaultNamespace(arg0); } @Override public void writeEmptyElement(String arg0) throws XMLStreamException { if (s_logger.isLoggable(Level.FINEST)) { s_logger.log(Level.FINEST, "writeEmptyElement('" + arg0 + "'): "); } writeEmptyElement(arg0, null); } @Override public void writeEmptyElement(String arg0, String arg1) throws XMLStreamException { if (s_logger.isLoggable(Level.FINEST)) { s_logger.log(Level.FINEST, "writeEmptyElement('" + arg0 + "', " + arg1 + "): "); } writeEmptyElement(null, arg0, arg1); } @Override public void writeEmptyElement(String arg0, String arg1, String arg2) throws XMLStreamException { if (s_logger.isLoggable(Level.FINEST)) { s_logger.log(Level.FINEST, "writeEmptyElement('" + arg0 + "', " + arg1 + ", " + arg2 + "): "); } m_currentElementLevel++; // Skip writing the start element tag for root element. if (m_currentElementLevel == 1) { return; } m_writer.writeEmptyElement(arg0, arg1, arg2); } @Override public void writeEndDocument() throws XMLStreamException { if (s_logger.isLoggable(Level.FINEST)) { s_logger.log(Level.FINEST, "writeEndDocument(): "); } m_writer.writeEndDocument(); } @Override public void writeEndElement() throws XMLStreamException { if (s_logger.isLoggable(Level.FINEST)) { s_logger.log(Level.FINEST, "writeEndElement(): "); } // Skip the generation of end tag for the root element. if (1 == m_currentElementLevel) { m_currentElementLevel--; return; } m_currentElementLevel--; m_writer.writeEndElement(); } @Override public void writeEntityRef(String arg0) throws XMLStreamException { if (s_logger.isLoggable(Level.FINEST)) { s_logger.log(Level.FINEST, "writeEntityRef('" + arg0 + "'): "); } m_writer.writeEntityRef(arg0); } @Override public void writeNamespace(String arg0, String arg1) throws XMLStreamException { if (s_logger.isLoggable(Level.FINEST)) { s_logger.log(Level.FINEST, "writeNamespace('" + arg0 + "', " + arg1 + "): "); } // If it is processing the root element. save the namespace prefix definition. if (m_currentElementLevel == 1) { m_namespaceToWrite.add(new QName(arg1, "", arg0)); return; } m_writer.writeNamespace(arg0, arg1); } @Override public void writeProcessingInstruction(String arg0) throws XMLStreamException { if (s_logger.isLoggable(Level.FINEST)) { s_logger.log(Level.FINEST, "writeProcessingInstruction('" + arg0 + "'): "); } m_writer.writeProcessingInstruction(arg0); } @Override public void writeProcessingInstruction(String arg0, String arg1) throws XMLStreamException { if (s_logger.isLoggable(Level.FINEST)) { s_logger.log(Level.FINEST, "writeProcessingInstruction('" + arg0 + "', " + arg1 + "): "); } m_writer.writeProcessingInstruction(arg0, arg1); } @Override public void writeStartDocument() throws XMLStreamException { if (s_logger.isLoggable(Level.FINEST)) { s_logger.log(Level.FINEST, "writeStartDocument(): "); } m_writer.writeStartDocument(); } @Override public void writeStartDocument(String arg0) throws XMLStreamException { if (s_logger.isLoggable(Level.FINEST)) { s_logger.log(Level.FINEST, "writeStartDocument('" + arg0 + "'): "); } m_writer.writeStartDocument(arg0); } @Override public void writeStartDocument(String arg0, String arg1) throws XMLStreamException { if (s_logger.isLoggable(Level.FINEST)) { s_logger.log(Level.FINEST, "writeStartDocument('" + arg0 + "', " + arg1 + "): "); } m_writer.writeStartDocument( arg0, arg1); } @Override public void writeStartElement(String arg0) throws XMLStreamException { if (s_logger.isLoggable(Level.FINEST)) { s_logger.log(Level.FINEST, "writeStartElement('" + arg0 + "'): "); } writeStartElement(arg0, null); } @Override public void writeStartElement(String arg0, String arg1) throws XMLStreamException { if (s_logger.isLoggable(Level.FINEST)) { s_logger.log(Level.FINEST, "writeStartElement('" + arg0 + "', " + arg1 + "): "); } writeStartElement(null, arg0, arg1); } @Override public void writeStartElement(String arg0, String arg1, String arg2) throws XMLStreamException { if (s_logger.isLoggable(Level.FINEST)) { s_logger.log(Level.FINEST, "writeStartElement('" + arg0 + "', " + arg1 + ", " + arg2 + "): "); } m_currentElementLevel++; // Skip outputting of start element for root element. if (m_currentElementLevel == 1) { return; } m_writer.writeStartElement(arg0, arg1, arg2); // The first time writing the element under the root element, output all the // namespace prefix that are associated with the root element. if (!m_namespaceToWrite.isEmpty()){ for (QName qName : m_namespaceToWrite) { m_writer.writeNamespace(qName.getPrefix(), qName.getNamespaceURI()); } m_namespaceToWrite = new ArrayList<QName>(); } } }