1 /* 2 * Copyright (c) 1997, 2014, 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 */ 25 26 package com.sun.xml.internal.bind.v2.runtime.output; 27 28 import java.io.IOException; 29 import java.lang.reflect.Constructor; 30 31 import javax.xml.stream.XMLStreamException; 32 import javax.xml.stream.XMLStreamWriter; 33 34 import com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl; 35 import com.sun.xml.internal.bind.v2.runtime.XMLSerializer; 36 37 import com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl; 38 import org.xml.sax.SAXException; 39 40 /** 41 * {@link XmlOutput} that writes to StAX {@link XMLStreamWriter}. 42 * <p> 43 * TODO: 44 * Finding the optimized FI implementations is a bit hacky and not very 45 * extensible. Can we use the service provider mechanism in general for 46 * concrete implementations of XmlOutputAbstractImpl. 47 * 48 * @author Kohsuke Kawaguchi 49 */ 50 public class XMLStreamWriterOutput extends XmlOutputAbstractImpl { 51 52 /** 53 * Creates a new {@link XmlOutput} from a {@link XMLStreamWriter}. 54 * This method recognizes an FI StAX writer. 55 */ 56 public static XmlOutput create(XMLStreamWriter out, JAXBContextImpl context) { 57 // try optimized path 58 final Class writerClass = out.getClass(); 59 if (writerClass==FI_STAX_WRITER_CLASS) { 60 try { 61 return FI_OUTPUT_CTOR.newInstance(out, context); 62 } catch (Exception e) { 63 } 64 } 65 if (STAXEX_WRITER_CLASS!=null && STAXEX_WRITER_CLASS.isAssignableFrom(writerClass)) { 66 try { 67 return STAXEX_OUTPUT_CTOR.newInstance(out); 68 } catch (Exception e) { 69 } 70 } 71 72 // otherwise the normal writer. 73 return new XMLStreamWriterOutput(out); 74 } 75 76 77 private final XMLStreamWriter out; 78 79 protected final char[] buf = new char[256]; 80 81 protected XMLStreamWriterOutput(XMLStreamWriter out) { 82 this.out = out; 83 } 84 85 // not called if we are generating fragments 86 @Override 87 public void startDocument(XMLSerializer serializer, boolean fragment, int[] nsUriIndex2prefixIndex, NamespaceContextImpl nsContext) throws IOException, SAXException, XMLStreamException { 88 super.startDocument(serializer, fragment,nsUriIndex2prefixIndex,nsContext); 89 if(!fragment) 90 out.writeStartDocument(); 91 } 92 93 @Override 94 public void endDocument(boolean fragment) throws IOException, SAXException, XMLStreamException { 95 if(!fragment) { 96 out.writeEndDocument(); 97 out.flush(); 98 } 99 super.endDocument(fragment); 100 } 101 102 public void beginStartTag(int prefix, String localName) throws IOException, XMLStreamException { 103 out.writeStartElement( 104 nsContext.getPrefix(prefix), 105 localName, 106 nsContext.getNamespaceURI(prefix)); 107 108 NamespaceContextImpl.Element nse = nsContext.getCurrent(); 109 if(nse.count()>0) { 110 for( int i=nse.count()-1; i>=0; i-- ) { 111 String uri = nse.getNsUri(i); 112 if(uri.length()==0 && nse.getBase()==1) 113 continue; // no point in definint xmlns='' on the root 114 out.writeNamespace(nse.getPrefix(i),uri); 115 } 116 } 117 } 118 119 public void attribute(int prefix, String localName, String value) throws IOException, XMLStreamException { 120 if(prefix==-1) 121 out.writeAttribute(localName,value); 122 else 123 out.writeAttribute( 124 nsContext.getPrefix(prefix), 125 nsContext.getNamespaceURI(prefix), 126 localName, value); 127 } 128 129 public void endStartTag() throws IOException, SAXException { 130 // noop 131 } 132 133 public void endTag(int prefix, String localName) throws IOException, SAXException, XMLStreamException { 134 out.writeEndElement(); 135 } 136 137 public void text(String value, boolean needsSeparatingWhitespace) throws IOException, SAXException, XMLStreamException { 138 if(needsSeparatingWhitespace) 139 out.writeCharacters(" "); 140 out.writeCharacters(value); 141 } 142 143 public void text(Pcdata value, boolean needsSeparatingWhitespace) throws IOException, SAXException, XMLStreamException { 144 if(needsSeparatingWhitespace) 145 out.writeCharacters(" "); 146 147 int len = value.length(); 148 if(len <buf.length) { 149 value.writeTo(buf,0); 150 out.writeCharacters(buf,0,len); 151 } else { 152 out.writeCharacters(value.toString()); 153 } 154 } 155 156 /** 157 * Reference to FI's XMLStreamWriter class, if FI can be loaded. 158 */ 159 private static final Class FI_STAX_WRITER_CLASS = initFIStAXWriterClass(); 160 private static final Constructor<? extends XmlOutput> FI_OUTPUT_CTOR = initFastInfosetOutputClass(); 161 162 private static Class initFIStAXWriterClass() { 163 try { 164 Class<?> llfisw = Class.forName("com.sun.xml.internal.org.jvnet.fastinfoset.stax.LowLevelFastInfosetStreamWriter"); 165 Class<?> sds = Class.forName("com.sun.xml.internal.fastinfoset.stax.StAXDocumentSerializer"); 166 // Check if StAXDocumentSerializer implements LowLevelFastInfosetStreamWriter 167 if (llfisw.isAssignableFrom(sds)) 168 return sds; 169 else 170 return null; 171 } catch (Throwable e) { 172 return null; 173 } 174 } 175 176 private static Constructor<? extends XmlOutput> initFastInfosetOutputClass() { 177 try { 178 if (FI_STAX_WRITER_CLASS == null) 179 return null; 180 Class c = Class.forName("com.sun.xml.internal.bind.v2.runtime.output.FastInfosetStreamWriterOutput"); 181 return c.getConstructor(FI_STAX_WRITER_CLASS, JAXBContextImpl.class); 182 } catch (Throwable e) { 183 return null; 184 } 185 } 186 187 // 188 // StAX-ex 189 // 190 private static final Class STAXEX_WRITER_CLASS = initStAXExWriterClass(); 191 private static final Constructor<? extends XmlOutput> STAXEX_OUTPUT_CTOR = initStAXExOutputClass(); 192 193 private static Class initStAXExWriterClass() { 194 try { 195 return Class.forName("com.sun.xml.internal.org.jvnet.staxex.XMLStreamWriterEx"); 196 } catch (Throwable e) { 197 return null; 198 } 199 } 200 201 private static Constructor<? extends XmlOutput> initStAXExOutputClass() { 202 try { 203 Class c = Class.forName("com.sun.xml.internal.bind.v2.runtime.output.StAXExStreamWriterOutput"); 204 return c.getConstructor(STAXEX_WRITER_CLASS); 205 } catch (Throwable e) { 206 return null; 207 } 208 } 209 210 }