src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/output/XMLStreamWriterOutput.java

Mon, 28 May 2018 10:36:45 +0800

author
aoqi
date
Mon, 28 May 2018 10:36:45 +0800
changeset 1546
dc8316632248
parent 1443
dffc222439a1
parent 637
9c07ef4934dd
child 1620
6df7b161ae4a
permissions
-rw-r--r--

Merge

     1 /*
     2  * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Oracle in the LICENSE file that accompanied this code.
    10  *
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    14  * version 2 for more details (a copy is included in the LICENSE file that
    15  * accompanied this code).
    16  *
    17  * You should have received a copy of the GNU General Public License version
    18  * 2 along with this work; if not, write to the Free Software Foundation,
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    20  *
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    22  * or visit www.oracle.com if you need additional information or have any
    23  * questions.
    24  */
    26 package com.sun.xml.internal.bind.v2.runtime.output;
    28 import java.io.IOException;
    29 import java.io.Writer;
    30 import java.lang.reflect.Constructor;
    32 import javax.xml.stream.XMLStreamException;
    33 import javax.xml.stream.XMLStreamWriter;
    35 import com.sun.xml.internal.bind.marshaller.CharacterEscapeHandler;
    36 import com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl;
    37 import com.sun.xml.internal.bind.v2.runtime.XMLSerializer;
    39 import org.xml.sax.SAXException;
    41 /**
    42  * {@link XmlOutput} that writes to StAX {@link XMLStreamWriter}.
    43  * <p>
    44  * TODO:
    45  * Finding the optimized FI implementations is a bit hacky and not very
    46  * extensible. Can we use the service provider mechanism in general for
    47  * concrete implementations of XmlOutputAbstractImpl.
    48  *
    49  * @author Kohsuke Kawaguchi
    50  */
    51 public class XMLStreamWriterOutput extends XmlOutputAbstractImpl {
    53     /**
    54      * Creates a new {@link XmlOutput} from a {@link XMLStreamWriter}.
    55      * This method recognizes an FI StAX writer.
    56      */
    57     public static XmlOutput create(XMLStreamWriter out, JAXBContextImpl context, CharacterEscapeHandler escapeHandler) {
    58         // try optimized path
    59         final Class writerClass = out.getClass();
    60         if (writerClass==FI_STAX_WRITER_CLASS) {
    61             try {
    62                 return FI_OUTPUT_CTOR.newInstance(out, context);
    63             } catch (Exception e) {
    64             }
    65         }
    66         if (STAXEX_WRITER_CLASS!=null && STAXEX_WRITER_CLASS.isAssignableFrom(writerClass)) {
    67             try {
    68                 return STAXEX_OUTPUT_CTOR.newInstance(out);
    69             } catch (Exception e) {
    70             }
    71         }
    73         CharacterEscapeHandler xmlStreamEscapeHandler = escapeHandler != null ?
    74                 escapeHandler : NewLineEscapeHandler.theInstance;
    76         // otherwise the normal writer.
    77         return new XMLStreamWriterOutput(out, xmlStreamEscapeHandler);
    78     }
    81     private final XMLStreamWriter out;
    83     private final CharacterEscapeHandler escapeHandler;
    85     private final XmlStreamOutWriterAdapter writerWrapper;
    87     protected final char[] buf = new char[256];
    89     protected XMLStreamWriterOutput(XMLStreamWriter out, CharacterEscapeHandler escapeHandler) {
    90         this.out = out;
    91         this.escapeHandler = escapeHandler;
    92         this.writerWrapper = new XmlStreamOutWriterAdapter(out);
    93     }
    95     // not called if we are generating fragments
    96     @Override
    97     public void startDocument(XMLSerializer serializer, boolean fragment, int[] nsUriIndex2prefixIndex, NamespaceContextImpl nsContext) throws IOException, SAXException, XMLStreamException {
    98         super.startDocument(serializer, fragment,nsUriIndex2prefixIndex,nsContext);
    99         if(!fragment)
   100             out.writeStartDocument();
   101     }
   103     @Override
   104     public void endDocument(boolean fragment) throws IOException, SAXException, XMLStreamException {
   105         if(!fragment) {
   106             out.writeEndDocument();
   107             out.flush();
   108         }
   109         super.endDocument(fragment);
   110     }
   112     public void beginStartTag(int prefix, String localName) throws IOException, XMLStreamException {
   113         out.writeStartElement(
   114             nsContext.getPrefix(prefix),
   115             localName,
   116             nsContext.getNamespaceURI(prefix));
   118         NamespaceContextImpl.Element nse = nsContext.getCurrent();
   119         if(nse.count()>0) {
   120             for( int i=nse.count()-1; i>=0; i-- ) {
   121                 String uri = nse.getNsUri(i);
   122                 if(uri.length()==0 && nse.getBase()==1)
   123                     continue;   // no point in definint xmlns='' on the root
   124                 out.writeNamespace(nse.getPrefix(i),uri);
   125             }
   126         }
   127     }
   129     public void attribute(int prefix, String localName, String value) throws IOException, XMLStreamException {
   130         if(prefix==-1)
   131             out.writeAttribute(localName,value);
   132         else
   133             out.writeAttribute(
   134                     nsContext.getPrefix(prefix),
   135                     nsContext.getNamespaceURI(prefix),
   136                     localName, value);
   137     }
   139     public void endStartTag() throws IOException, SAXException {
   140         // noop
   141     }
   143     public void endTag(int prefix, String localName) throws IOException, SAXException, XMLStreamException {
   144         out.writeEndElement();
   145     }
   147     public void text(String value, boolean needsSeparatingWhitespace) throws IOException, SAXException, XMLStreamException {
   148         if(needsSeparatingWhitespace)
   149             out.writeCharacters(" ");
   150         escapeHandler.escape(value.toCharArray(), 0, value.length(), false, writerWrapper);
   151     }
   153     public void text(Pcdata value, boolean needsSeparatingWhitespace) throws IOException, SAXException, XMLStreamException {
   154         if(needsSeparatingWhitespace)
   155             out.writeCharacters(" ");
   157         int len = value.length();
   158         if(len <buf.length) {
   159             value.writeTo(buf,0);
   160             out.writeCharacters(buf,0,len);
   161         } else {
   162             out.writeCharacters(value.toString());
   163         }
   164     }
   166     /**
   167      * Reference to FI's XMLStreamWriter class, if FI can be loaded.
   168      */
   169     private static final Class FI_STAX_WRITER_CLASS = initFIStAXWriterClass();
   170     private static final Constructor<? extends XmlOutput> FI_OUTPUT_CTOR = initFastInfosetOutputClass();
   172     private static Class initFIStAXWriterClass() {
   173         try {
   174             Class<?> llfisw = Class.forName("com.sun.xml.internal.org.jvnet.fastinfoset.stax.LowLevelFastInfosetStreamWriter");
   175             Class<?> sds = Class.forName("com.sun.xml.internal.fastinfoset.stax.StAXDocumentSerializer");
   176             // Check if StAXDocumentSerializer implements LowLevelFastInfosetStreamWriter
   177             if (llfisw.isAssignableFrom(sds))
   178                 return sds;
   179             else
   180                 return null;
   181         } catch (Throwable e) {
   182             return null;
   183         }
   184     }
   186     private static Constructor<? extends XmlOutput> initFastInfosetOutputClass() {
   187         try {
   188             if (FI_STAX_WRITER_CLASS == null)
   189                 return null;
   190             Class c = Class.forName("com.sun.xml.internal.bind.v2.runtime.output.FastInfosetStreamWriterOutput");
   191             return c.getConstructor(FI_STAX_WRITER_CLASS, JAXBContextImpl.class);
   192         } catch (Throwable e) {
   193             return null;
   194         }
   195     }
   197     //
   198     // StAX-ex
   199     //
   200     private static final Class STAXEX_WRITER_CLASS = initStAXExWriterClass();
   201     private static final Constructor<? extends XmlOutput> STAXEX_OUTPUT_CTOR = initStAXExOutputClass();
   203     private static Class initStAXExWriterClass() {
   204         try {
   205             return Class.forName("com.sun.xml.internal.org.jvnet.staxex.XMLStreamWriterEx");
   206         } catch (Throwable e) {
   207             return null;
   208         }
   209     }
   211     private static Constructor<? extends XmlOutput> initStAXExOutputClass() {
   212         try {
   213             Class c = Class.forName("com.sun.xml.internal.bind.v2.runtime.output.StAXExStreamWriterOutput");
   214             return c.getConstructor(STAXEX_WRITER_CLASS);
   215         } catch (Throwable e) {
   216             return null;
   217         }
   218     }
   221     /**
   222      * Performs character escaping only for new lines.
   223      */
   224     private static class NewLineEscapeHandler implements CharacterEscapeHandler {
   226         public static final NewLineEscapeHandler theInstance = new NewLineEscapeHandler();
   228         @Override
   229         public void escape(char[] ch, int start, int length, boolean isAttVal, Writer out) throws IOException {
   230             int limit = start+length;
   231             int lastEscaped = start;
   233             for (int i = start; i < limit; i++) {
   234                 char c = ch[i];
   235                 if (c == '\r' || c == '\n') {
   236                     if (i != lastEscaped) {
   237                         out.write(ch, lastEscaped, i - lastEscaped);
   238                     }
   239                     lastEscaped = i + 1;
   240                     if (out instanceof XmlStreamOutWriterAdapter) {
   241                         try {
   242                             ((XmlStreamOutWriterAdapter)out).writeEntityRef("#x" + Integer.toHexString(c));
   243                         } catch (XMLStreamException e) {
   244                             throw new IOException("Error writing xml stream", e);
   245                         }
   246                     } else {
   247                         out.write("&#x");
   248                         out.write(Integer.toHexString(c));
   249                         out.write(';');
   250                     }
   251                 }
   252             }
   253             if (lastEscaped != limit) {
   254                 out.write(ch, lastEscaped, length - lastEscaped);
   255             }
   256         }
   257     }
   259     private static final class XmlStreamOutWriterAdapter extends Writer {
   261         private final XMLStreamWriter writer;
   263         private XmlStreamOutWriterAdapter(XMLStreamWriter writer) {
   264             this.writer = writer;
   265         }
   267         @Override
   268         public void write(char[] cbuf, int off, int len) throws IOException {
   269             try {
   270                 writer.writeCharacters(cbuf, off, len);
   271             } catch (XMLStreamException e) {
   272                 throw new IOException("Error writing XML stream", e);
   273             }
   274         }
   276         public void writeEntityRef(String entityReference) throws XMLStreamException {
   277             writer.writeEntityRef(entityReference);
   278         }
   280         @Override
   281         public void flush() throws IOException {
   282             try {
   283                 writer.flush();
   284             } catch (XMLStreamException e) {
   285                 throw new IOException("Error flushing XML stream", e);
   286             }
   287         }
   289         @Override
   290         public void close() throws IOException {
   291             try {
   292                 writer.close();
   293             } catch (XMLStreamException e) {
   294                 throw new IOException("Error closing XML stream", e);
   295             }
   296         }
   297     }
   298 }

mercurial