/*
 * Copyright (c) 2006- 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.fasterxml.aalto.stax;

import java.io.*;

import javax.xml.stream.*;
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.fasterxml.aalto.dom.DOMWriterImpl;
import com.fasterxml.aalto.impl.IoStreamException;
import com.fasterxml.aalto.impl.StreamExceptionBase;
import com.fasterxml.aalto.out.*;
import com.fasterxml.aalto.util.CharsetNames;
import com.fasterxml.aalto.util.URLUtil;
import com.fasterxml.aalto.util.XmlConsts;

Basic implementation of XMLOutputFactory.
Author:Tatu Saloranta
/** * Basic implementation of {@link XMLOutputFactory}. * * @author Tatu Saloranta */
public final class OutputFactoryImpl extends XMLOutputFactory2 { /* /********************************************************************** /* Actual storage of configuration settings /********************************************************************** */ protected final WriterConfig _config; /* /********************************************************************** /* Life-cycle /********************************************************************** */ public OutputFactoryImpl() { _config = new WriterConfig(); } /* /********************************************************************** /* XMLOutputFactory API /********************************************************************** */ @Override public XMLEventWriter createXMLEventWriter(OutputStream out) throws XMLStreamException { return createXMLEventWriter(out, null); } @Override public XMLEventWriter createXMLEventWriter(OutputStream out, String enc) throws XMLStreamException { 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 { 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 { 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 { return createSW(null, w, null, false); } @Override public Object getProperty(String name) { // true -> is mandatory, unrecognized will throw IllegalArgumentException return _config.getProperty(name, true); } @Override public boolean isPropertySupported(String name) { return _config.isPropertySupported(name); } @Override public void setProperty(String name, Object value) { _config.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() { _config.configureForXmlConformance(); } @Override public void configureForRobustness() { _config.configureForRobustness(); } @Override public void configureForSpeed() { _config.configureForSpeed(); } /* /********************************************************************** /* Internal methods: /********************************************************************** */
Bottleneck factory method used internally; needs to take care of passing proper settings to stream writer.
Params:
  • autoCloseOutput – Whether writer should automatically close the output stream or Writer, when close() is called on stream writer.
/** * Bottleneck factory method used internally; needs to take care of passing * proper settings to stream writer. * * @param autoCloseOutput Whether writer should automatically close the * output stream or Writer, when close() is called on stream writer. */
private XMLStreamWriter2 createSW(OutputStream out, Writer w, String enc, boolean forceAutoClose) 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 = _config.createNonShared(); if (forceAutoClose) { cfg.doAutoCloseOutput(true); } XmlWriter xw; WNameTable symbols; if (w == null) { if (enc == null) { enc = XmlConsts.STAX_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); } } cfg.setActualEncodingIfNotSet(enc); try { if (enc == CharsetNames.CS_UTF8) { // !!! TEST-only: /* w = new com.fasterxml.aalto.io.UTF8Writer(cfg, out, autoCloseOutput); xw = new CharXmlWriter(cfg, w); */ xw = new Utf8XmlWriter(cfg, out); symbols = _config.getUtf8Symbols(xw); } else if (enc == CharsetNames.CS_ISO_LATIN1) { xw = new Latin1XmlWriter(cfg, out); symbols = _config.getLatin1Symbols(xw); } else if (enc == CharsetNames.CS_US_ASCII) { xw = new AsciiXmlWriter(cfg, out); symbols = _config.getAsciiSymbols(xw); } else { w = new OutputStreamWriter(out, enc); xw = new CharXmlWriter(cfg, w); symbols = _config.getCharSymbols(xw); } } catch (IOException ioe) { throw new XMLStreamException(ioe); } /* try { if (enc == CharsetNames.CS_UTF8) { w = new UTF8Writer(cfg, out, autoCloseOutput); xw = new BufferingXmlWriter(w, cfg, enc, true); } else if (enc == CharsetNames.CS_ISO_LATIN1) { xw = new ISOLatin1XmlWriter(out, cfg, autoCloseOutput); } else if (enc == CharsetNames.CS_US_ASCII) { xw = new ISOLatin1XmlWriter(out, cfg, autoCloseOutput); } else { w = new OutputStreamWriter(out, enc); xw = new BufferingXmlWriter(w, cfg, enc, autoCloseOutput); } } 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); } if (enc != null) { cfg.setActualEncodingIfNotSet(enc); } xw = new CharXmlWriter(cfg, w); symbols = _config.getCharSymbols(xw); } if (cfg.willRepairNamespaces()) { return new RepairingStreamWriter(cfg, xw, symbols); } return new NonRepairingStreamWriter(cfg, xw, symbols); } private XMLStreamWriter2 createSW(Result res) throws XMLStreamException { OutputStream out = null; Writer w = null; String encoding = null; boolean autoclose; 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 StreamExceptionBase(ioe); } autoclose = true; } else if (res instanceof StreamResult) { StreamResult sr = (StreamResult) res; sysId = sr.getSystemId(); out = sr.getOutputStream(); if (out == null) { w = sr.getWriter(); } autoclose = false; // caller still owns it, no automatic close } else if (res instanceof SAXResult) { SAXResult sr = (SAXResult) res; sysId = sr.getSystemId(); if (sysId == null || sysId.length() == 0) { throw new StreamExceptionBase("Can not create a stream writer for a SAXResult that does not have System Id (support for using SAX input source not implemented)"); } autoclose = true; } else if (res instanceof DOMResult) { return DOMWriterImpl.createFrom(_config.createNonShared(), (DOMResult) res); } else { throw new IllegalArgumentException("Can not create XMLStreamWriter for Result type "+res.getClass()+" (unrecognized type)"); } if (out != null) { return createSW(out, null, encoding, autoclose); } if (w != null) { return createSW(null, w, encoding, autoclose); } if (sysId != null && sysId.length() > 0) { /* 26-Dec-2008, tatu: If we must construct URL from system id, * it means caller will not have access to resulting * stream, thus we will force auto-closing. */ autoclose = true; try { out = URLUtil.outputStreamFromURL(URLUtil.urlFromSystemId(sysId)); } catch (IOException ioe) { throw new IoStreamException(ioe); } return createSW(out, null, encoding, autoclose); } throw new StreamExceptionBase("Can not create XMLStreamWriter for passed-in Result -- neither writer, output stream nor system id (to create one) was accessible"); } }