/* Woodstox XML processor
 *
 * Copyright (c) 2004- Tatu Saloranta, tatu.saloranta@iki.fi
 *
 * Licensed under the License specified in the file LICENSE which is
 * included with the source code.
 * You may not use this file except in compliance with the License.
 *
 * 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 com.ctc.wstx.stax;

import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;

import javax.xml.stream.XMLEventWriter;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import javax.xml.transform.Result;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.stream.StreamResult;

import org.codehaus.stax2.XMLOutputFactory2;
import org.codehaus.stax2.XMLStreamWriter2;
import org.codehaus.stax2.io.Stax2Result;
import org.codehaus.stax2.ri.Stax2EventWriterImpl;
import org.codehaus.stax2.ri.Stax2WriterAdapter;

import com.ctc.wstx.api.WriterConfig;
import com.ctc.wstx.api.WstxOutputProperties;
import com.ctc.wstx.cfg.OutputConfigFlags;
import com.ctc.wstx.dom.WstxDOMWrappingWriter;
import com.ctc.wstx.exc.WstxIOException;
import com.ctc.wstx.io.CharsetNames;
import com.ctc.wstx.io.UTF8Writer;
import com.ctc.wstx.sw.AsciiXmlWriter;
import com.ctc.wstx.sw.BufferingXmlWriter;
import com.ctc.wstx.sw.ISOLatin1XmlWriter;
import com.ctc.wstx.sw.NonNsStreamWriter;
import com.ctc.wstx.sw.RepairingNsStreamWriter;
import com.ctc.wstx.sw.SimpleNsStreamWriter;
import com.ctc.wstx.sw.XmlWriter;
import com.ctc.wstx.util.URLUtil;

Implementation of XMLOutputFactory for Wstx.

TODO:

  • Implement outputter that creates SAX events (DOM-backed writer exists as of Woodstox 3.2)
/** * Implementation of {@link XMLOutputFactory} for Wstx. *<p> * TODO: *<ul> * <li>Implement outputter that creates SAX events (DOM-backed * writer exists as of Woodstox 3.2) * </li> *</ul> */
public class WstxOutputFactory extends XMLOutputFactory2 implements OutputConfigFlags { /* /////////////////////////////////////////////////////////// // Actual storage of configuration settings /////////////////////////////////////////////////////////// */ protected final WriterConfig mConfig; /* /////////////////////////////////////////////////////////// // Life-cycle /////////////////////////////////////////////////////////// */ public WstxOutputFactory() { mConfig = WriterConfig.createFullDefaults(); } /* /////////////////////////////////////////////////////////// // XMLOutputFactory API /////////////////////////////////////////////////////////// */ @Override public XMLEventWriter createXMLEventWriter(OutputStream out) throws XMLStreamException { return createXMLEventWriter(out, null); } @Override public XMLEventWriter createXMLEventWriter(OutputStream out, String enc) throws XMLStreamException { if (out == null) { throw new IllegalArgumentException("Null OutputStream is not a valid argument"); } return new Stax2EventWriterImpl(createSW(out, null, enc, false)); } @Override public XMLEventWriter createXMLEventWriter(javax.xml.transform.Result result) throws XMLStreamException { return new Stax2EventWriterImpl(createSW(result)); } @Override public XMLEventWriter createXMLEventWriter(Writer w) throws XMLStreamException { if (w == null) { throw new IllegalArgumentException("Null Writer is not a valid argument"); } return new Stax2EventWriterImpl(createSW(null, w, null, false)); } @Override public XMLStreamWriter createXMLStreamWriter(OutputStream out) throws XMLStreamException { return createXMLStreamWriter(out, null); } @Override public XMLStreamWriter createXMLStreamWriter(OutputStream out, String enc) throws XMLStreamException { if (out == null) { throw new IllegalArgumentException("Null OutputStream is not a valid argument"); } return createSW(out, null, enc, false); } @Override public XMLStreamWriter createXMLStreamWriter(javax.xml.transform.Result result) throws XMLStreamException { return createSW(result); } @Override public XMLStreamWriter createXMLStreamWriter(Writer w) throws XMLStreamException { if (w == null) { throw new IllegalArgumentException("Null Writer is not a valid argument"); } return createSW(null, w, null, false); } @Override public Object getProperty(String name) { return mConfig.getProperty(name); } @Override public boolean isPropertySupported(String name) { return mConfig.isPropertySupported(name); } @Override public void setProperty(String name, Object value) { mConfig.setProperty(name, value); } /* /////////////////////////////////////////////////////////// // Stax2 extensions /////////////////////////////////////////////////////////// */ // // // Stax2 additional (encoding-aware) factory methods @Override public XMLEventWriter createXMLEventWriter(Writer w, String enc) throws XMLStreamException { return new Stax2EventWriterImpl(createSW(null, w, enc, false)); } @Override public XMLEventWriter createXMLEventWriter(XMLStreamWriter sw) throws XMLStreamException { XMLStreamWriter2 sw2 = Stax2WriterAdapter.wrapIfNecessary(sw); return new Stax2EventWriterImpl(sw2); } @Override public XMLStreamWriter2 createXMLStreamWriter(Writer w, String enc) throws XMLStreamException { return createSW(null, w, enc, false); } // // // Stax2 "Profile" mutators @Override public void configureForXmlConformance() { mConfig.configureForXmlConformance(); } @Override public void configureForRobustness() { mConfig.configureForRobustness(); } @Override public void configureForSpeed() { mConfig.configureForSpeed(); } /* /////////////////////////////////////////////////////////// // Woodstox-specific configuration access /////////////////////////////////////////////////////////// */ public WriterConfig getConfig() { return mConfig; } /* /////////////////////////////////////////////////////////// // Internal methods: /////////////////////////////////////////////////////////// */
Bottleneck factory method used internally; needs to take care of passing proper settings to stream writer.
Params:
  • requireAutoClose – Whether this result will always require auto-close be enabled (true); or only if application has requested it (false)
/** * Bottleneck factory method used internally; needs to take care of passing * proper settings to stream writer. * * @param requireAutoClose Whether this result will always require * auto-close be enabled (true); or only if application has * requested it (false) */
@SuppressWarnings("resource") private XMLStreamWriter2 createSW(OutputStream out, Writer w, String enc, boolean requireAutoClose) throws XMLStreamException { /* Need to ensure that the configuration object is not shared * any more; otherwise later changes via factory could be * visible half-way through output... */ WriterConfig cfg = mConfig.createNonShared(); XmlWriter xw; boolean autoCloseOutput = requireAutoClose || mConfig.willAutoCloseOutput(); if (w == null) { if (enc == null) { enc = WstxOutputProperties.DEFAULT_OUTPUT_ENCODING; } else { /* Canonical ones are interned, so we may have * normalized encoding already... */ if (enc != CharsetNames.CS_UTF8 && enc != CharsetNames.CS_ISO_LATIN1 && enc != CharsetNames.CS_US_ASCII) { enc = CharsetNames.normalize(enc); } } try { if (enc == CharsetNames.CS_UTF8) { w = new UTF8Writer(cfg, out, autoCloseOutput); xw = new BufferingXmlWriter(w, cfg, enc, autoCloseOutput, out, 16); } else if (enc == CharsetNames.CS_ISO_LATIN1) { xw = new ISOLatin1XmlWriter(out, cfg, autoCloseOutput); } else if (enc == CharsetNames.CS_US_ASCII) { xw = new AsciiXmlWriter(out, cfg, autoCloseOutput); } else { w = new OutputStreamWriter(out, enc); xw = new BufferingXmlWriter(w, cfg, enc, autoCloseOutput, out, -1); } } catch (IOException ex) { throw new XMLStreamException(ex); } } else { // we may still be able to figure out the encoding: if (enc == null) { enc = CharsetNames.findEncodingFor(w); } try { xw = new BufferingXmlWriter(w, cfg, enc, autoCloseOutput, null, -1); } catch (IOException ex) { throw new XMLStreamException(ex); } } return createSW(enc, cfg, xw); }
Called by createSW(OutputStream, Writer, String, boolean) after all of the nessesary configuration logic is complete.
/** * Called by {@link #createSW(OutputStream, Writer, String, boolean)} after all of the nessesary configuration * logic is complete. */
protected XMLStreamWriter2 createSW(String enc, WriterConfig cfg, XmlWriter xw) { if (cfg.willSupportNamespaces()) { if (cfg.automaticNamespacesEnabled()) { return new RepairingNsStreamWriter(xw, enc, cfg); } return new SimpleNsStreamWriter(xw, enc, cfg); } return new NonNsStreamWriter(xw, enc, cfg); } @SuppressWarnings("resource") private XMLStreamWriter2 createSW(Result res) throws XMLStreamException { OutputStream out = null; Writer w = null; String encoding = null; boolean requireAutoClose; String sysId = null; if (res instanceof Stax2Result) { Stax2Result sr = (Stax2Result) res; try { out = sr.constructOutputStream(); if (out == null) { w = sr.constructWriter(); } } catch (IOException ioe) { throw new WstxIOException(ioe); } // yes, it's required since caller has no access to stream/writer: requireAutoClose = true; } else if (res instanceof StreamResult) { StreamResult sr = (StreamResult) res; out = sr.getOutputStream(); sysId = sr.getSystemId(); if (out == null) { w = sr.getWriter(); } /* Caller owns it, only auto-close if requested to do so: * (except that for system-id-only, it'll still be required, * see code below) */ requireAutoClose = false; } else if (res instanceof SAXResult) { SAXResult sr = (SAXResult) res; sysId = sr.getSystemId(); if (sysId == null || sysId.length() == 0) { throw new XMLStreamException("Can not create a stream writer for a SAXResult that does not have System Id (support for using SAX input source not implemented)"); } requireAutoClose = true; } else if (res instanceof DOMResult) { return WstxDOMWrappingWriter.createFrom(mConfig.createNonShared(), (DOMResult) res); } else { throw new IllegalArgumentException("Can not instantiate a writer for XML result type "+res.getClass()+" (unrecognized type)"); } if (out != null) { return createSW(out, null, encoding, requireAutoClose); } if (w != null) { return createSW(null, w, encoding, requireAutoClose); } if (sysId != null && sysId.length() > 0) { /* 26-Dec-2008, TSa: If we must construct URL from system id, * it means caller will not have access to resulting * stream, thus we will force auto-closing. */ requireAutoClose = true; try { out = URLUtil.outputStreamFromURL(URLUtil.urlFromSystemId(sysId)); } catch (IOException ioe) { throw new WstxIOException(ioe); } return createSW(out, null, encoding, requireAutoClose); } throw new XMLStreamException("Can not create Stax writer for passed-in Result -- neither writer, output stream or system id was accessible"); } }