src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/unmarshaller/StAXStreamConnector.java

changeset 0
373ffda63c9a
child 637
9c07ef4934dd
equal deleted inserted replaced
-1:000000000000 0:373ffda63c9a
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.unmarshaller;
27
28 import java.lang.reflect.Constructor;
29
30 import javax.xml.stream.Location;
31 import javax.xml.stream.XMLStreamConstants;
32 import javax.xml.stream.XMLStreamException;
33 import javax.xml.stream.XMLStreamReader;
34
35 import com.sun.xml.internal.bind.WhiteSpaceProcessor;
36
37 import org.xml.sax.Attributes;
38 import org.xml.sax.SAXException;
39
40 /**
41 * Reads XML from StAX {@link XMLStreamReader} and
42 * feeds events to {@link XmlVisitor}.
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 StAXConnector.
48 *
49 * @author Ryan.Shoemaker@Sun.COM
50 * @author Kohsuke Kawaguchi
51 * @version JAXB 2.0
52 */
53 class StAXStreamConnector extends StAXConnector {
54
55 /**
56 * Creates a {@link StAXConnector} from {@link XMLStreamReader}.
57 *
58 * This method checks if the parser is FI parser and acts accordingly.
59 */
60 public static StAXConnector create(XMLStreamReader reader, XmlVisitor visitor) {
61 // try optimized codepath
62 final Class readerClass = reader.getClass();
63 if (FI_STAX_READER_CLASS != null && FI_STAX_READER_CLASS.isAssignableFrom(readerClass) && FI_CONNECTOR_CTOR!=null) {
64 try {
65 return FI_CONNECTOR_CTOR.newInstance(reader,visitor);
66 } catch (Exception t) {
67 }
68 }
69
70 // Quick hack until SJSXP fixes 6270116
71 boolean isZephyr = readerClass.getName().equals("com.sun.xml.internal.stream.XMLReaderImpl");
72 if (getBoolProp(reader,"org.codehaus.stax2.internNames") &&
73 getBoolProp(reader,"org.codehaus.stax2.internNsUris"))
74 ; // no need for interning
75 else
76 if (isZephyr)
77 ; // no need for interning
78 else
79 if (checkImplementaionNameOfSjsxp(reader))
80 ; // no need for interning.
81 else
82 visitor = new InterningXmlVisitor(visitor);
83
84 if (STAX_EX_READER_CLASS!=null && STAX_EX_READER_CLASS.isAssignableFrom(readerClass)) {
85 try {
86 return STAX_EX_CONNECTOR_CTOR.newInstance(reader,visitor);
87 } catch (Exception t) {
88 }
89 }
90
91 return new StAXStreamConnector(reader,visitor);
92 }
93
94 private static boolean checkImplementaionNameOfSjsxp(XMLStreamReader reader) {
95 try {
96 Object name = reader.getProperty("http://java.sun.com/xml/stream/properties/implementation-name");
97 return name!=null && name.equals("sjsxp");
98 } catch (Exception e) {
99 // be defensive against broken StAX parsers since javadoc is not clear
100 // about when an error happens
101 return false;
102 }
103 }
104
105 private static boolean getBoolProp(XMLStreamReader r, String n) {
106 try {
107 Object o = r.getProperty(n);
108 if(o instanceof Boolean) return (Boolean)o;
109 return false;
110 } catch (Exception e) {
111 // be defensive against broken StAX parsers since javadoc is not clear
112 // about when an error happens
113 return false;
114 }
115 }
116
117
118 // StAX event source
119 private final XMLStreamReader staxStreamReader;
120
121 /**
122 * SAX may fire consecutive characters event, but we don't allow it.
123 * so use this buffer to perform buffering.
124 */
125 protected final StringBuilder buffer = new StringBuilder();
126
127 /**
128 * Set to true if the text() event is reported, and therefore
129 * the following text() event should be suppressed.
130 */
131 protected boolean textReported = false;
132
133 protected StAXStreamConnector(XMLStreamReader staxStreamReader, XmlVisitor visitor) {
134 super(visitor);
135 this.staxStreamReader = staxStreamReader;
136 }
137
138 public void bridge() throws XMLStreamException {
139
140 try {
141 // remembers the nest level of elements to know when we are done.
142 int depth=0;
143
144 // if the parser is at the start tag, proceed to the first element
145 int event = staxStreamReader.getEventType();
146 if(event == XMLStreamConstants.START_DOCUMENT) {
147 // nextTag doesn't correctly handle DTDs
148 while( !staxStreamReader.isStartElement() )
149 event = staxStreamReader.next();
150 }
151
152
153 if( event!=XMLStreamConstants.START_ELEMENT)
154 throw new IllegalStateException("The current event is not START_ELEMENT\n but " + event);
155
156 handleStartDocument(staxStreamReader.getNamespaceContext());
157
158 OUTER:
159 while(true) {
160 // These are all of the events listed in the javadoc for
161 // XMLEvent.
162 // The spec only really describes 11 of them.
163 switch (event) {
164 case XMLStreamConstants.START_ELEMENT :
165 handleStartElement();
166 depth++;
167 break;
168 case XMLStreamConstants.END_ELEMENT :
169 depth--;
170 handleEndElement();
171 if(depth==0) break OUTER;
172 break;
173 case XMLStreamConstants.CHARACTERS :
174 case XMLStreamConstants.CDATA :
175 case XMLStreamConstants.SPACE :
176 handleCharacters();
177 break;
178 // otherwise simply ignore
179 }
180
181 event=staxStreamReader.next();
182 }
183
184 staxStreamReader.next(); // move beyond the end tag.
185
186 handleEndDocument();
187 } catch (SAXException e) {
188 throw new XMLStreamException(e);
189 }
190 }
191
192 protected Location getCurrentLocation() {
193 return staxStreamReader.getLocation();
194 }
195
196 protected String getCurrentQName() {
197 return getQName(staxStreamReader.getPrefix(),staxStreamReader.getLocalName());
198 }
199
200 private void handleEndElement() throws SAXException {
201 processText(false);
202
203 // fire endElement
204 tagName.uri = fixNull(staxStreamReader.getNamespaceURI());
205 tagName.local = staxStreamReader.getLocalName();
206 visitor.endElement(tagName);
207
208 // end namespace bindings
209 int nsCount = staxStreamReader.getNamespaceCount();
210 for (int i = nsCount - 1; i >= 0; i--) {
211 visitor.endPrefixMapping(fixNull(staxStreamReader.getNamespacePrefix(i)));
212 }
213 }
214
215 private void handleStartElement() throws SAXException {
216 processText(true);
217
218 // start namespace bindings
219 int nsCount = staxStreamReader.getNamespaceCount();
220 for (int i = 0; i < nsCount; i++) {
221 visitor.startPrefixMapping(
222 fixNull(staxStreamReader.getNamespacePrefix(i)),
223 fixNull(staxStreamReader.getNamespaceURI(i)));
224 }
225
226 // fire startElement
227 tagName.uri = fixNull(staxStreamReader.getNamespaceURI());
228 tagName.local = staxStreamReader.getLocalName();
229 tagName.atts = attributes;
230
231 visitor.startElement(tagName);
232 }
233
234 /**
235 * Proxy of {@link Attributes} that read from {@link XMLStreamReader}.
236 */
237 private final Attributes attributes = new Attributes() {
238 public int getLength() {
239 return staxStreamReader.getAttributeCount();
240 }
241
242 public String getURI(int index) {
243 String uri = staxStreamReader.getAttributeNamespace(index);
244 if(uri==null) return "";
245 return uri;
246 }
247
248 public String getLocalName(int index) {
249 return staxStreamReader.getAttributeLocalName(index);
250 }
251
252 public String getQName(int index) {
253 String prefix = staxStreamReader.getAttributePrefix(index);
254 if(prefix==null || prefix.length()==0)
255 return getLocalName(index);
256 else
257 return prefix + ':' + getLocalName(index);
258 }
259
260 public String getType(int index) {
261 return staxStreamReader.getAttributeType(index);
262 }
263
264 public String getValue(int index) {
265 return staxStreamReader.getAttributeValue(index);
266 }
267
268 public int getIndex(String uri, String localName) {
269 for( int i=getLength()-1; i>=0; i-- )
270 if( localName.equals(getLocalName(i)) && uri.equals(getURI(i)))
271 return i;
272 return -1;
273 }
274
275 // this method sholdn't be used that often (if at all)
276 // so it's OK to be slow.
277 public int getIndex(String qName) {
278 for( int i=getLength()-1; i>=0; i-- ) {
279 if(qName.equals(getQName(i)))
280 return i;
281 }
282 return -1;
283 }
284
285 public String getType(String uri, String localName) {
286 int index = getIndex(uri,localName);
287 if(index<0) return null;
288 return getType(index);
289 }
290
291 public String getType(String qName) {
292 int index = getIndex(qName);
293 if(index<0) return null;
294 return getType(index);
295 }
296
297 public String getValue(String uri, String localName) {
298 int index = getIndex(uri,localName);
299 if(index<0) return null;
300 return getValue(index);
301 }
302
303 public String getValue(String qName) {
304 int index = getIndex(qName);
305 if(index<0) return null;
306 return getValue(index);
307 }
308 };
309
310 protected void handleCharacters() throws XMLStreamException, SAXException {
311 if( predictor.expectText() )
312 buffer.append(
313 staxStreamReader.getTextCharacters(),
314 staxStreamReader.getTextStart(),
315 staxStreamReader.getTextLength() );
316 }
317
318 private void processText( boolean ignorable ) throws SAXException {
319 if( predictor.expectText() && (!ignorable || !WhiteSpaceProcessor.isWhiteSpace(buffer))) {
320 if(textReported) {
321 textReported = false;
322 } else {
323 visitor.text(buffer);
324 }
325 }
326 buffer.setLength(0);
327 }
328
329
330
331 /**
332 * Reference to FI's StAXReader class, if FI can be loaded.
333 */
334 private static final Class FI_STAX_READER_CLASS = initFIStAXReaderClass();
335 private static final Constructor<? extends StAXConnector> FI_CONNECTOR_CTOR = initFastInfosetConnectorClass();
336
337 private static Class initFIStAXReaderClass() {
338 try {
339 Class<?> fisr = Class.forName("com.sun.xml.internal.org.jvnet.fastinfoset.stax.FastInfosetStreamReader");
340 Class<?> sdp = Class.forName("com.sun.xml.internal.fastinfoset.stax.StAXDocumentParser");
341 // Check if StAXDocumentParser implements FastInfosetStreamReader
342 if (fisr.isAssignableFrom(sdp))
343 return sdp;
344 else
345 return null;
346 } catch (Throwable e) {
347 return null;
348 }
349 }
350
351 private static Constructor<? extends StAXConnector> initFastInfosetConnectorClass() {
352 try {
353 if (FI_STAX_READER_CLASS == null)
354 return null;
355
356 Class c = Class.forName(
357 "com.sun.xml.internal.bind.v2.runtime.unmarshaller.FastInfosetConnector");
358 return c.getConstructor(FI_STAX_READER_CLASS,XmlVisitor.class);
359 } catch (Throwable e) {
360 return null;
361 }
362 }
363
364 //
365 // reference to StAXEx classes
366 //
367 private static final Class STAX_EX_READER_CLASS = initStAXExReader();
368 private static final Constructor<? extends StAXConnector> STAX_EX_CONNECTOR_CTOR = initStAXExConnector();
369
370 private static Class initStAXExReader() {
371 try {
372 return Class.forName("com.sun.xml.internal.org.jvnet.staxex.XMLStreamReaderEx");
373 } catch (Throwable e) {
374 return null;
375 }
376 }
377
378 private static Constructor<? extends StAXConnector> initStAXExConnector() {
379 try {
380 Class c = Class.forName("com.sun.xml.internal.bind.v2.runtime.unmarshaller.StAXExConnector");
381 return c.getConstructor(STAX_EX_READER_CLASS,XmlVisitor.class);
382 } catch (Throwable e) {
383 return null;
384 }
385 }
386
387 }

mercurial