1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/unmarshaller/StAXStreamConnector.java Wed Apr 27 01:27:09 2016 +0800 1.3 @@ -0,0 +1,387 @@ 1.4 +/* 1.5 + * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. Oracle designates this 1.11 + * particular file as subject to the "Classpath" exception as provided 1.12 + * by Oracle in the LICENSE file that accompanied this code. 1.13 + * 1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.17 + * version 2 for more details (a copy is included in the LICENSE file that 1.18 + * accompanied this code). 1.19 + * 1.20 + * You should have received a copy of the GNU General Public License version 1.21 + * 2 along with this work; if not, write to the Free Software Foundation, 1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.23 + * 1.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 1.25 + * or visit www.oracle.com if you need additional information or have any 1.26 + * questions. 1.27 + */ 1.28 + 1.29 +package com.sun.xml.internal.bind.v2.runtime.unmarshaller; 1.30 + 1.31 +import java.lang.reflect.Constructor; 1.32 + 1.33 +import javax.xml.stream.Location; 1.34 +import javax.xml.stream.XMLStreamConstants; 1.35 +import javax.xml.stream.XMLStreamException; 1.36 +import javax.xml.stream.XMLStreamReader; 1.37 + 1.38 +import com.sun.xml.internal.bind.WhiteSpaceProcessor; 1.39 + 1.40 +import org.xml.sax.Attributes; 1.41 +import org.xml.sax.SAXException; 1.42 + 1.43 +/** 1.44 + * Reads XML from StAX {@link XMLStreamReader} and 1.45 + * feeds events to {@link XmlVisitor}. 1.46 + * <p> 1.47 + * TODO: 1.48 + * Finding the optimized FI implementations is a bit hacky and not very 1.49 + * extensible. Can we use the service provider mechanism in general for 1.50 + * concrete implementations of StAXConnector. 1.51 + * 1.52 + * @author Ryan.Shoemaker@Sun.COM 1.53 + * @author Kohsuke Kawaguchi 1.54 + * @version JAXB 2.0 1.55 + */ 1.56 +class StAXStreamConnector extends StAXConnector { 1.57 + 1.58 + /** 1.59 + * Creates a {@link StAXConnector} from {@link XMLStreamReader}. 1.60 + * 1.61 + * This method checks if the parser is FI parser and acts accordingly. 1.62 + */ 1.63 + public static StAXConnector create(XMLStreamReader reader, XmlVisitor visitor) { 1.64 + // try optimized codepath 1.65 + final Class readerClass = reader.getClass(); 1.66 + if (FI_STAX_READER_CLASS != null && FI_STAX_READER_CLASS.isAssignableFrom(readerClass) && FI_CONNECTOR_CTOR!=null) { 1.67 + try { 1.68 + return FI_CONNECTOR_CTOR.newInstance(reader,visitor); 1.69 + } catch (Exception t) { 1.70 + } 1.71 + } 1.72 + 1.73 + // Quick hack until SJSXP fixes 6270116 1.74 + boolean isZephyr = readerClass.getName().equals("com.sun.xml.internal.stream.XMLReaderImpl"); 1.75 + if (getBoolProp(reader,"org.codehaus.stax2.internNames") && 1.76 + getBoolProp(reader,"org.codehaus.stax2.internNsUris")) 1.77 + ; // no need for interning 1.78 + else 1.79 + if (isZephyr) 1.80 + ; // no need for interning 1.81 + else 1.82 + if (checkImplementaionNameOfSjsxp(reader)) 1.83 + ; // no need for interning. 1.84 + else 1.85 + visitor = new InterningXmlVisitor(visitor); 1.86 + 1.87 + if (STAX_EX_READER_CLASS!=null && STAX_EX_READER_CLASS.isAssignableFrom(readerClass)) { 1.88 + try { 1.89 + return STAX_EX_CONNECTOR_CTOR.newInstance(reader,visitor); 1.90 + } catch (Exception t) { 1.91 + } 1.92 + } 1.93 + 1.94 + return new StAXStreamConnector(reader,visitor); 1.95 + } 1.96 + 1.97 + private static boolean checkImplementaionNameOfSjsxp(XMLStreamReader reader) { 1.98 + try { 1.99 + Object name = reader.getProperty("http://java.sun.com/xml/stream/properties/implementation-name"); 1.100 + return name!=null && name.equals("sjsxp"); 1.101 + } catch (Exception e) { 1.102 + // be defensive against broken StAX parsers since javadoc is not clear 1.103 + // about when an error happens 1.104 + return false; 1.105 + } 1.106 + } 1.107 + 1.108 + private static boolean getBoolProp(XMLStreamReader r, String n) { 1.109 + try { 1.110 + Object o = r.getProperty(n); 1.111 + if(o instanceof Boolean) return (Boolean)o; 1.112 + return false; 1.113 + } catch (Exception e) { 1.114 + // be defensive against broken StAX parsers since javadoc is not clear 1.115 + // about when an error happens 1.116 + return false; 1.117 + } 1.118 + } 1.119 + 1.120 + 1.121 + // StAX event source 1.122 + private final XMLStreamReader staxStreamReader; 1.123 + 1.124 + /** 1.125 + * SAX may fire consecutive characters event, but we don't allow it. 1.126 + * so use this buffer to perform buffering. 1.127 + */ 1.128 + protected final StringBuilder buffer = new StringBuilder(); 1.129 + 1.130 + /** 1.131 + * Set to true if the text() event is reported, and therefore 1.132 + * the following text() event should be suppressed. 1.133 + */ 1.134 + protected boolean textReported = false; 1.135 + 1.136 + protected StAXStreamConnector(XMLStreamReader staxStreamReader, XmlVisitor visitor) { 1.137 + super(visitor); 1.138 + this.staxStreamReader = staxStreamReader; 1.139 + } 1.140 + 1.141 + public void bridge() throws XMLStreamException { 1.142 + 1.143 + try { 1.144 + // remembers the nest level of elements to know when we are done. 1.145 + int depth=0; 1.146 + 1.147 + // if the parser is at the start tag, proceed to the first element 1.148 + int event = staxStreamReader.getEventType(); 1.149 + if(event == XMLStreamConstants.START_DOCUMENT) { 1.150 + // nextTag doesn't correctly handle DTDs 1.151 + while( !staxStreamReader.isStartElement() ) 1.152 + event = staxStreamReader.next(); 1.153 + } 1.154 + 1.155 + 1.156 + if( event!=XMLStreamConstants.START_ELEMENT) 1.157 + throw new IllegalStateException("The current event is not START_ELEMENT\n but " + event); 1.158 + 1.159 + handleStartDocument(staxStreamReader.getNamespaceContext()); 1.160 + 1.161 + OUTER: 1.162 + while(true) { 1.163 + // These are all of the events listed in the javadoc for 1.164 + // XMLEvent. 1.165 + // The spec only really describes 11 of them. 1.166 + switch (event) { 1.167 + case XMLStreamConstants.START_ELEMENT : 1.168 + handleStartElement(); 1.169 + depth++; 1.170 + break; 1.171 + case XMLStreamConstants.END_ELEMENT : 1.172 + depth--; 1.173 + handleEndElement(); 1.174 + if(depth==0) break OUTER; 1.175 + break; 1.176 + case XMLStreamConstants.CHARACTERS : 1.177 + case XMLStreamConstants.CDATA : 1.178 + case XMLStreamConstants.SPACE : 1.179 + handleCharacters(); 1.180 + break; 1.181 + // otherwise simply ignore 1.182 + } 1.183 + 1.184 + event=staxStreamReader.next(); 1.185 + } 1.186 + 1.187 + staxStreamReader.next(); // move beyond the end tag. 1.188 + 1.189 + handleEndDocument(); 1.190 + } catch (SAXException e) { 1.191 + throw new XMLStreamException(e); 1.192 + } 1.193 + } 1.194 + 1.195 + protected Location getCurrentLocation() { 1.196 + return staxStreamReader.getLocation(); 1.197 + } 1.198 + 1.199 + protected String getCurrentQName() { 1.200 + return getQName(staxStreamReader.getPrefix(),staxStreamReader.getLocalName()); 1.201 + } 1.202 + 1.203 + private void handleEndElement() throws SAXException { 1.204 + processText(false); 1.205 + 1.206 + // fire endElement 1.207 + tagName.uri = fixNull(staxStreamReader.getNamespaceURI()); 1.208 + tagName.local = staxStreamReader.getLocalName(); 1.209 + visitor.endElement(tagName); 1.210 + 1.211 + // end namespace bindings 1.212 + int nsCount = staxStreamReader.getNamespaceCount(); 1.213 + for (int i = nsCount - 1; i >= 0; i--) { 1.214 + visitor.endPrefixMapping(fixNull(staxStreamReader.getNamespacePrefix(i))); 1.215 + } 1.216 + } 1.217 + 1.218 + private void handleStartElement() throws SAXException { 1.219 + processText(true); 1.220 + 1.221 + // start namespace bindings 1.222 + int nsCount = staxStreamReader.getNamespaceCount(); 1.223 + for (int i = 0; i < nsCount; i++) { 1.224 + visitor.startPrefixMapping( 1.225 + fixNull(staxStreamReader.getNamespacePrefix(i)), 1.226 + fixNull(staxStreamReader.getNamespaceURI(i))); 1.227 + } 1.228 + 1.229 + // fire startElement 1.230 + tagName.uri = fixNull(staxStreamReader.getNamespaceURI()); 1.231 + tagName.local = staxStreamReader.getLocalName(); 1.232 + tagName.atts = attributes; 1.233 + 1.234 + visitor.startElement(tagName); 1.235 + } 1.236 + 1.237 + /** 1.238 + * Proxy of {@link Attributes} that read from {@link XMLStreamReader}. 1.239 + */ 1.240 + private final Attributes attributes = new Attributes() { 1.241 + public int getLength() { 1.242 + return staxStreamReader.getAttributeCount(); 1.243 + } 1.244 + 1.245 + public String getURI(int index) { 1.246 + String uri = staxStreamReader.getAttributeNamespace(index); 1.247 + if(uri==null) return ""; 1.248 + return uri; 1.249 + } 1.250 + 1.251 + public String getLocalName(int index) { 1.252 + return staxStreamReader.getAttributeLocalName(index); 1.253 + } 1.254 + 1.255 + public String getQName(int index) { 1.256 + String prefix = staxStreamReader.getAttributePrefix(index); 1.257 + if(prefix==null || prefix.length()==0) 1.258 + return getLocalName(index); 1.259 + else 1.260 + return prefix + ':' + getLocalName(index); 1.261 + } 1.262 + 1.263 + public String getType(int index) { 1.264 + return staxStreamReader.getAttributeType(index); 1.265 + } 1.266 + 1.267 + public String getValue(int index) { 1.268 + return staxStreamReader.getAttributeValue(index); 1.269 + } 1.270 + 1.271 + public int getIndex(String uri, String localName) { 1.272 + for( int i=getLength()-1; i>=0; i-- ) 1.273 + if( localName.equals(getLocalName(i)) && uri.equals(getURI(i))) 1.274 + return i; 1.275 + return -1; 1.276 + } 1.277 + 1.278 + // this method sholdn't be used that often (if at all) 1.279 + // so it's OK to be slow. 1.280 + public int getIndex(String qName) { 1.281 + for( int i=getLength()-1; i>=0; i-- ) { 1.282 + if(qName.equals(getQName(i))) 1.283 + return i; 1.284 + } 1.285 + return -1; 1.286 + } 1.287 + 1.288 + public String getType(String uri, String localName) { 1.289 + int index = getIndex(uri,localName); 1.290 + if(index<0) return null; 1.291 + return getType(index); 1.292 + } 1.293 + 1.294 + public String getType(String qName) { 1.295 + int index = getIndex(qName); 1.296 + if(index<0) return null; 1.297 + return getType(index); 1.298 + } 1.299 + 1.300 + public String getValue(String uri, String localName) { 1.301 + int index = getIndex(uri,localName); 1.302 + if(index<0) return null; 1.303 + return getValue(index); 1.304 + } 1.305 + 1.306 + public String getValue(String qName) { 1.307 + int index = getIndex(qName); 1.308 + if(index<0) return null; 1.309 + return getValue(index); 1.310 + } 1.311 + }; 1.312 + 1.313 + protected void handleCharacters() throws XMLStreamException, SAXException { 1.314 + if( predictor.expectText() ) 1.315 + buffer.append( 1.316 + staxStreamReader.getTextCharacters(), 1.317 + staxStreamReader.getTextStart(), 1.318 + staxStreamReader.getTextLength() ); 1.319 + } 1.320 + 1.321 + private void processText( boolean ignorable ) throws SAXException { 1.322 + if( predictor.expectText() && (!ignorable || !WhiteSpaceProcessor.isWhiteSpace(buffer))) { 1.323 + if(textReported) { 1.324 + textReported = false; 1.325 + } else { 1.326 + visitor.text(buffer); 1.327 + } 1.328 + } 1.329 + buffer.setLength(0); 1.330 + } 1.331 + 1.332 + 1.333 + 1.334 + /** 1.335 + * Reference to FI's StAXReader class, if FI can be loaded. 1.336 + */ 1.337 + private static final Class FI_STAX_READER_CLASS = initFIStAXReaderClass(); 1.338 + private static final Constructor<? extends StAXConnector> FI_CONNECTOR_CTOR = initFastInfosetConnectorClass(); 1.339 + 1.340 + private static Class initFIStAXReaderClass() { 1.341 + try { 1.342 + Class<?> fisr = Class.forName("com.sun.xml.internal.org.jvnet.fastinfoset.stax.FastInfosetStreamReader"); 1.343 + Class<?> sdp = Class.forName("com.sun.xml.internal.fastinfoset.stax.StAXDocumentParser"); 1.344 + // Check if StAXDocumentParser implements FastInfosetStreamReader 1.345 + if (fisr.isAssignableFrom(sdp)) 1.346 + return sdp; 1.347 + else 1.348 + return null; 1.349 + } catch (Throwable e) { 1.350 + return null; 1.351 + } 1.352 + } 1.353 + 1.354 + private static Constructor<? extends StAXConnector> initFastInfosetConnectorClass() { 1.355 + try { 1.356 + if (FI_STAX_READER_CLASS == null) 1.357 + return null; 1.358 + 1.359 + Class c = Class.forName( 1.360 + "com.sun.xml.internal.bind.v2.runtime.unmarshaller.FastInfosetConnector"); 1.361 + return c.getConstructor(FI_STAX_READER_CLASS,XmlVisitor.class); 1.362 + } catch (Throwable e) { 1.363 + return null; 1.364 + } 1.365 + } 1.366 + 1.367 + // 1.368 + // reference to StAXEx classes 1.369 + // 1.370 + private static final Class STAX_EX_READER_CLASS = initStAXExReader(); 1.371 + private static final Constructor<? extends StAXConnector> STAX_EX_CONNECTOR_CTOR = initStAXExConnector(); 1.372 + 1.373 + private static Class initStAXExReader() { 1.374 + try { 1.375 + return Class.forName("com.sun.xml.internal.org.jvnet.staxex.XMLStreamReaderEx"); 1.376 + } catch (Throwable e) { 1.377 + return null; 1.378 + } 1.379 + } 1.380 + 1.381 + private static Constructor<? extends StAXConnector> initStAXExConnector() { 1.382 + try { 1.383 + Class c = Class.forName("com.sun.xml.internal.bind.v2.runtime.unmarshaller.StAXExConnector"); 1.384 + return c.getConstructor(STAX_EX_READER_CLASS,XmlVisitor.class); 1.385 + } catch (Throwable e) { 1.386 + return null; 1.387 + } 1.388 + } 1.389 + 1.390 +}