ohair@286: /* aefimov@1609: * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. ohair@286: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ohair@286: * ohair@286: * This code is free software; you can redistribute it and/or modify it ohair@286: * under the terms of the GNU General Public License version 2 only, as ohair@286: * published by the Free Software Foundation. Oracle designates this ohair@286: * particular file as subject to the "Classpath" exception as provided ohair@286: * by Oracle in the LICENSE file that accompanied this code. ohair@286: * ohair@286: * This code is distributed in the hope that it will be useful, but WITHOUT ohair@286: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ohair@286: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ohair@286: * version 2 for more details (a copy is included in the LICENSE file that ohair@286: * accompanied this code). ohair@286: * ohair@286: * You should have received a copy of the GNU General Public License version ohair@286: * 2 along with this work; if not, write to the Free Software Foundation, ohair@286: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ohair@286: * ohair@286: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ohair@286: * or visit www.oracle.com if you need additional information or have any ohair@286: * questions. ohair@286: */ ohair@286: ohair@286: package com.sun.xml.internal.bind.v2.runtime.output; ohair@286: ohair@286: import java.io.IOException; aefimov@1443: import java.io.Writer; ohair@286: import java.lang.reflect.Constructor; ohair@286: ohair@286: import javax.xml.stream.XMLStreamException; ohair@286: import javax.xml.stream.XMLStreamWriter; ohair@286: aefimov@1443: import com.sun.xml.internal.bind.marshaller.CharacterEscapeHandler; aefimov@1609: import com.sun.xml.internal.bind.marshaller.NoEscapeHandler; ohair@286: import com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl; ohair@286: import com.sun.xml.internal.bind.v2.runtime.XMLSerializer; ohair@286: ohair@286: import org.xml.sax.SAXException; ohair@286: ohair@286: /** ohair@286: * {@link XmlOutput} that writes to StAX {@link XMLStreamWriter}. ohair@286: *
ohair@286: * TODO:
ohair@286: * Finding the optimized FI implementations is a bit hacky and not very
ohair@286: * extensible. Can we use the service provider mechanism in general for
ohair@286: * concrete implementations of XmlOutputAbstractImpl.
ohair@286: *
ohair@286: * @author Kohsuke Kawaguchi
ohair@286: */
ohair@286: public class XMLStreamWriterOutput extends XmlOutputAbstractImpl {
ohair@286:
ohair@286: /**
ohair@286: * Creates a new {@link XmlOutput} from a {@link XMLStreamWriter}.
ohair@286: * This method recognizes an FI StAX writer.
ohair@286: */
aefimov@1443: public static XmlOutput create(XMLStreamWriter out, JAXBContextImpl context, CharacterEscapeHandler escapeHandler) {
ohair@286: // try optimized path
ohair@286: final Class writerClass = out.getClass();
ohair@286: if (writerClass==FI_STAX_WRITER_CLASS) {
ohair@286: try {
ohair@286: return FI_OUTPUT_CTOR.newInstance(out, context);
ohair@286: } catch (Exception e) {
ohair@286: }
ohair@286: }
ohair@286: if (STAXEX_WRITER_CLASS!=null && STAXEX_WRITER_CLASS.isAssignableFrom(writerClass)) {
ohair@286: try {
ohair@286: return STAXEX_OUTPUT_CTOR.newInstance(out);
ohair@286: } catch (Exception e) {
ohair@286: }
ohair@286: }
ohair@286:
aefimov@1443: CharacterEscapeHandler xmlStreamEscapeHandler = escapeHandler != null ?
aefimov@1609: escapeHandler : NoEscapeHandler.theInstance;
aefimov@1443:
ohair@286: // otherwise the normal writer.
aefimov@1443: return new XMLStreamWriterOutput(out, xmlStreamEscapeHandler);
ohair@286: }
ohair@286:
ohair@286:
ohair@286: private final XMLStreamWriter out;
ohair@286:
aefimov@1443: private final CharacterEscapeHandler escapeHandler;
aefimov@1443:
aefimov@1443: private final XmlStreamOutWriterAdapter writerWrapper;
aefimov@1443:
ohair@286: protected final char[] buf = new char[256];
ohair@286:
aefimov@1443: protected XMLStreamWriterOutput(XMLStreamWriter out, CharacterEscapeHandler escapeHandler) {
ohair@286: this.out = out;
aefimov@1443: this.escapeHandler = escapeHandler;
aefimov@1443: this.writerWrapper = new XmlStreamOutWriterAdapter(out);
ohair@286: }
ohair@286:
ohair@286: // not called if we are generating fragments
ohair@286: @Override
ohair@286: public void startDocument(XMLSerializer serializer, boolean fragment, int[] nsUriIndex2prefixIndex, NamespaceContextImpl nsContext) throws IOException, SAXException, XMLStreamException {
ohair@286: super.startDocument(serializer, fragment,nsUriIndex2prefixIndex,nsContext);
ohair@286: if(!fragment)
ohair@286: out.writeStartDocument();
ohair@286: }
ohair@286:
ohair@286: @Override
ohair@286: public void endDocument(boolean fragment) throws IOException, SAXException, XMLStreamException {
ohair@286: if(!fragment) {
ohair@286: out.writeEndDocument();
ohair@286: out.flush();
ohair@286: }
ohair@286: super.endDocument(fragment);
ohair@286: }
ohair@286:
ohair@286: public void beginStartTag(int prefix, String localName) throws IOException, XMLStreamException {
ohair@286: out.writeStartElement(
ohair@286: nsContext.getPrefix(prefix),
ohair@286: localName,
ohair@286: nsContext.getNamespaceURI(prefix));
ohair@286:
ohair@286: NamespaceContextImpl.Element nse = nsContext.getCurrent();
ohair@286: if(nse.count()>0) {
ohair@286: for( int i=nse.count()-1; i>=0; i-- ) {
ohair@286: String uri = nse.getNsUri(i);
ohair@286: if(uri.length()==0 && nse.getBase()==1)
ohair@286: continue; // no point in definint xmlns='' on the root
ohair@286: out.writeNamespace(nse.getPrefix(i),uri);
ohair@286: }
ohair@286: }
ohair@286: }
ohair@286:
ohair@286: public void attribute(int prefix, String localName, String value) throws IOException, XMLStreamException {
ohair@286: if(prefix==-1)
ohair@286: out.writeAttribute(localName,value);
ohair@286: else
ohair@286: out.writeAttribute(
ohair@286: nsContext.getPrefix(prefix),
ohair@286: nsContext.getNamespaceURI(prefix),
ohair@286: localName, value);
ohair@286: }
ohair@286:
ohair@286: public void endStartTag() throws IOException, SAXException {
ohair@286: // noop
ohair@286: }
ohair@286:
ohair@286: public void endTag(int prefix, String localName) throws IOException, SAXException, XMLStreamException {
ohair@286: out.writeEndElement();
ohair@286: }
ohair@286:
ohair@286: public void text(String value, boolean needsSeparatingWhitespace) throws IOException, SAXException, XMLStreamException {
ohair@286: if(needsSeparatingWhitespace)
ohair@286: out.writeCharacters(" ");
aefimov@1443: escapeHandler.escape(value.toCharArray(), 0, value.length(), false, writerWrapper);
ohair@286: }
ohair@286:
ohair@286: public void text(Pcdata value, boolean needsSeparatingWhitespace) throws IOException, SAXException, XMLStreamException {
ohair@286: if(needsSeparatingWhitespace)
ohair@286: out.writeCharacters(" ");
ohair@286:
ohair@286: int len = value.length();
ohair@286: if(len