1 /* Woodstox XML processor
2 *
3 * Copyright (c) 2004- Tatu Saloranta, tatu.saloranta@iki.fi
4 *
5 * Licensed under the License specified in the file LICENSE which is
6 * included with the source code.
7 * You may not use this file except in compliance with the License.
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 package com.ctc.wstx.stax;
17
18 import java.io.*;
19 import java.net.URL;
20
21 import javax.xml.stream.*;
22 import javax.xml.stream.util.XMLEventAllocator;
23 import javax.xml.transform.dom.DOMSource;
24 import javax.xml.transform.sax.SAXSource;
25 import javax.xml.transform.stream.StreamSource;
26
27 import org.xml.sax.InputSource;
28 import org.codehaus.stax2.XMLEventReader2;
29 import org.codehaus.stax2.XMLInputFactory2;
30 import org.codehaus.stax2.XMLStreamReader2;
31 import org.codehaus.stax2.io.Stax2Source;
32 import org.codehaus.stax2.io.Stax2ByteArraySource;
33 import org.codehaus.stax2.ri.Stax2FilteredStreamReader;
34 import org.codehaus.stax2.ri.Stax2ReaderAdapter;
35 import org.codehaus.stax2.ri.evt.Stax2EventReaderAdapter;
36 import org.codehaus.stax2.ri.evt.Stax2FilteredEventReader;
37
38 import com.ctc.wstx.api.ReaderConfig;
39 import com.ctc.wstx.api.WstxInputProperties;
40 import com.ctc.wstx.cfg.InputConfigFlags;
41 import com.ctc.wstx.cfg.XmlConsts;
42 import com.ctc.wstx.dtd.DTDId;
43 import com.ctc.wstx.dtd.DTDSubset;
44 import com.ctc.wstx.dom.WstxDOMWrappingReader;
45 import com.ctc.wstx.evt.DefaultEventAllocator;
46 import com.ctc.wstx.evt.WstxEventReader;
47 import com.ctc.wstx.exc.WstxIOException;
48 import com.ctc.wstx.io.*;
49 import com.ctc.wstx.sr.ValidatingStreamReader;
50 import com.ctc.wstx.sr.ReaderCreator;
51 import com.ctc.wstx.util.DefaultXmlSymbolTable;
52 import com.ctc.wstx.util.SimpleCache;
53 import com.ctc.wstx.util.SymbolTable;
54 import com.ctc.wstx.util.URLUtil;
55
56 /**
57 * Factory for creating various Stax objects (stream/event reader,
58 * writer).
59 *
60 *<p>
61 * Currently supported configuration options fall into two categories. First,
62 * all properties from {@link XMLInputFactory} (such as, say,
63 * {@link XMLInputFactory#IS_NAMESPACE_AWARE}) are at least recognized, and
64 * most are supported. Second, there are additional properties, defined in
65 * constant class {@link WstxInputProperties}, that are supported.
66 * See {@link WstxInputProperties} for further explanation of these 'custom'
67 * properties.
68 *
69 * @author Tatu Saloranta
70 */
71 public class WstxInputFactory
72 extends XMLInputFactory2
73 implements ReaderCreator,
74 InputConfigFlags
75 {
76 /**
77 * Let's limit max size to 3/4 of 16k, since this corresponds
78 * to 64k main hash index. This should not be too low, but could
79 * perhaps be further lowered?
80 */
81 final static int MAX_SYMBOL_TABLE_SIZE = 12000;
82
83 /**
84 * Number of generations should not matter as much as raw
85 * size... but let's still cap it at some number. 500 generations
86 * seems reasonable for flushing (note: does not count uses
87 * where no new symbols were added).
88 */
89 final static int MAX_SYMBOL_TABLE_GENERATIONS = 500;
90
91 /*
92 ///////////////////////////////////////////////////////////////////////
93 // Actual storage of configuration settings
94 ///////////////////////////////////////////////////////////////////////
95 */
96
97 /**
98 * Current configurations for this factory
99 */
100 protected final ReaderConfig mConfig;
101
102 // // // Stax - mandated objects:
103
104 protected XMLEventAllocator mAllocator = null;
105
106 // // // Other configuration objects:
107
108 protected SimpleCache<DTDId,DTDSubset> mDTDCache = null;
109
110 /*
111 ///////////////////////////////////////////////////////////////////////
112 // Objects shared by actual parsers
113 ///////////////////////////////////////////////////////////////////////
114 */
115
116 /**
117 * 'Root' symbol table, used for creating actual symbol table instances,
118 * but never as is.
119 */
120 final static SymbolTable mRootSymbols = DefaultXmlSymbolTable.getInstance();
121 static {
122 /* By default, let's enable intern()ing of names (element, attribute,
123 * prefixes) added to symbol table. This is likely to make some
124 * access (attr by QName) and comparison of element/attr names
125 * more efficient. Although it will add some overhead on adding
126 * new symbols to symbol table that should be rather negligible.
127 *
128 * Also note that always doing intern()ing allows for more efficient
129 * access during DTD validation.
130 */
131 mRootSymbols.setInternStrings(true);
132 }
133
134 /**
135 * Actual current 'parent' symbol table; concrete instances will be
136 * created from this instance using <code>makeChild</code> method
137 */
138 private SymbolTable mSymbols = mRootSymbols;
139
140 /*
141 ///////////////////////////////////////////////////////////////////////
142 // Life-cycle:
143 ///////////////////////////////////////////////////////////////////////
144 */
145
146 public WstxInputFactory() {
147 mConfig = ReaderConfig.createFullDefaults();
148 }
149
150 /**
151 * Method that can be used to ensure that specified symbol is
152 * contained in the shared symbol table. This may occasionally
153 * be useful in pre-populating symbols; although it is unlikely
154 * to be commonly useful.
155 *
156 * @since 4.2.1
157 */
158 public void addSymbol(String symbol)
159 {
160 synchronized (mSymbols) {
161 mSymbols.findSymbol(symbol);
162 }
163 }
164
165 /*
166 ///////////////////////////////////////////////////////////////////////
167 // ReaderCreator implementation
168 ///////////////////////////////////////////////////////////////////////
169 */
170
171 // // // Configuration access methods:
172
173 /**
174 * Method readers created by this factory call, if DTD caching is
175 * enabled, to see if an external DTD (subset) has been parsed
176 * and cached earlier.
177 */
178 @Override
179 public synchronized DTDSubset findCachedDTD(DTDId id)
180 {
181 return (mDTDCache == null) ? null : mDTDCache.find(id);
182 }
183
184 // // // Callbacks for updating shared information
185
186 /**
187 * Method individual parsers call to pass back symbol table that
188 * they updated, which may be useful for other parser to reuse, instead
189 * of previous base symbol table.
190 *<p>
191 * Note: parser is only to call this method, if passed-in symbol
192 * table was modified, ie new entry/ies were added in addition to
193 * whatever was in root table.
194 */
195 @Override
196 public synchronized void updateSymbolTable(SymbolTable t)
197 {
198 SymbolTable curr = mSymbols;
199 /* Let's only add if table was direct descendant; this prevents
200 * siblings from keeping overwriting settings (multiple direct
201 * children have additional symbols added)
202 */
203 if (t.isDirectChildOf(curr)) {
204 /* 07-Apr-2006, TSa: Actually, since huge symbol tables
205 * might become hindrance more than benefit (either in
206 * pathological cases with random names; or with very
207 * long running processes), let's actually limit both
208 * number of generations, and, more imporantly, maximum
209 * size of the symbol table
210 */
211 if (t.size() > MAX_SYMBOL_TABLE_SIZE ||
212 t.version() > MAX_SYMBOL_TABLE_GENERATIONS) {
213 // If so, we'll reset from bare defaults
214 mSymbols = mRootSymbols;
215 //System.err.println("DEBUG: !!!! XXXXX Symbol Table Flush: size: "+t.size()+"; version: "+t.version());
216 } else {
217 mSymbols.mergeChild(t);
218 //System.err.println("Debug: new symbol table: size: "+t.size()+"; version: "+t.version());
219 }
220 }
221 //else System.err.println("Debug: skipping symbol table update");
222 }
223
224 @Override
225 public synchronized void addCachedDTD(DTDId id, DTDSubset extSubset)
226 {
227 if (mDTDCache == null) {
228 mDTDCache = new SimpleCache<DTDId,DTDSubset>(mConfig.getDtdCacheSize());
229 }
230 mDTDCache.add(id, extSubset);
231 }
232
233 /*
234 ///////////////////////////////////////////////////////////////////////
235 // Stax, XMLInputFactory; factory methods
236 ///////////////////////////////////////////////////////////////////////
237 */
238
239 // // // Filtered reader factory methods
240
241 @Override
242 public XMLEventReader createFilteredReader(XMLEventReader reader, EventFilter filter) {
243 return new Stax2FilteredEventReader(Stax2EventReaderAdapter.wrapIfNecessary(reader), filter);
244 }
245
246 @Override
247 public XMLStreamReader createFilteredReader(XMLStreamReader reader, StreamFilter filter)
248 throws XMLStreamException
249 {
250 Stax2FilteredStreamReader fr = new Stax2FilteredStreamReader(reader, filter);
251 /* [WSTX-111] As per Stax 1.0 TCK, apparently the filtered
252 * reader is expected to be automatically forwarded to the first
253 * acceptable event. This is different from the way RI works, but
254 * since specs don't say anything about filtered readers, let's
255 * consider TCK to be "more formal" for now, and implement that
256 * behavior.
257 */
258 if (!filter.accept(fr)) { // START_DOCUMENT ok?
259 // Ok, nope, this should do the trick:
260 fr.next();
261 }
262 return fr;
263 }
264
265 // // // Event reader factory methods
266
267 @Override
268 public XMLEventReader createXMLEventReader(InputStream in)
269 throws XMLStreamException
270 {
271 // false for auto-close, since caller has access to the input stream
272 return new WstxEventReader(createEventAllocator(),
273 createSR(null, in, null, true, false));
274 }
275
276 @Override
277 public XMLEventReader createXMLEventReader(InputStream in, String enc)
278 throws XMLStreamException
279 {
280 // false for auto-close, since caller has access to the input stream
281 return new WstxEventReader(createEventAllocator(),
282 createSR(null, in, enc, true, false));
283 }
284
285 @Override
286 public XMLEventReader createXMLEventReader(Reader r)
287 throws XMLStreamException
288 {
289 // false for auto-close, since caller has access to the input stream
290 return new WstxEventReader(createEventAllocator(),
291 createSR(null, r, true, false));
292 }
293
294 @Override
295 public XMLEventReader createXMLEventReader(javax.xml.transform.Source source)
296 throws XMLStreamException
297 {
298 return new WstxEventReader(createEventAllocator(),
299 createSR(source, true));
300 }
301
302 @Override
303 public XMLEventReader createXMLEventReader(String systemId, InputStream in)
304 throws XMLStreamException
305 {
306 // false for auto-close, since caller has access to the input stream
307 return new WstxEventReader(createEventAllocator(),
308 createSR(SystemId.construct(systemId), in, null, true, false));
309 }
310
311 @Override
312 public XMLEventReader createXMLEventReader(String systemId, Reader r)
313 throws XMLStreamException
314 {
315 // false for auto-close, since caller has access to the reader
316 return new WstxEventReader(createEventAllocator(),
317 createSR(SystemId.construct(systemId), r, true, false));
318 }
319
320 @Override
321 public XMLEventReader createXMLEventReader(XMLStreamReader sr)
322 throws XMLStreamException
323 {
324 return new WstxEventReader(createEventAllocator(), Stax2ReaderAdapter.wrapIfNecessary(sr));
325 }
326
327 // // // Stream reader factory methods
328
329 @Override
330 public XMLStreamReader createXMLStreamReader(InputStream in)
331 throws XMLStreamException
332 {
333 // false for auto-close, since caller has access to the input stream
334 return createSR(null, in, null, false, false);
335 }
336
337 @Override
338 public XMLStreamReader createXMLStreamReader(InputStream in, String enc)
339 throws XMLStreamException
340 {
341 // false for auto-close, since caller has access to the input stream
342 return createSR(null, in, enc, false, false);
343 }
344
345 @Override
346 public XMLStreamReader createXMLStreamReader(Reader r)
347 throws XMLStreamException
348 {
349 // false for auto-close, since caller has access to the reader
350 return createSR(null, r, false, false);
351 }
352
353 @Override
354 public XMLStreamReader createXMLStreamReader(javax.xml.transform.Source src)
355 throws XMLStreamException
356 {
357 // false -> not for event. No definition for auto-close; called method will decide
358 return createSR(src, false);
359 }
360
361 @Override
362 public XMLStreamReader createXMLStreamReader(String systemId, InputStream in)
363 throws XMLStreamException
364 {
365 // false for auto-close, since caller has access to the input stream
366 return createSR(SystemId.construct(systemId), in, null, false, false);
367 }
368
369 @Override
370 public XMLStreamReader createXMLStreamReader(String systemId, Reader r)
371 throws XMLStreamException
372 {
373 // false for auto-close, since caller has access to the Reader
374 return createSR(SystemId.construct(systemId), r, false, false);
375 }
376
377 /*
378 ///////////////////////////////////////////////////////////////////////
379 // Stax, XMLInputFactory; generic accessors/mutators
380 ///////////////////////////////////////////////////////////////////////
381 */
382
383 @Override
384 public Object getProperty(String name)
385 {
386 Object ob = mConfig.getProperty(name);
387
388 if (ob == null) {
389 if (name.equals(XMLInputFactory.ALLOCATOR)) {
390 // Event allocator not available via J2ME subset...
391 return getEventAllocator();
392 }
393 }
394 return ob;
395 }
396
397 @Override
398 public void setProperty(String propName, Object value)
399 {
400 if (!mConfig.setProperty(propName, value)) {
401 if (XMLInputFactory.ALLOCATOR.equals(propName)) {
402 setEventAllocator((XMLEventAllocator) value);
403 }
404 }
405 }
406
407 @Override
408 public XMLEventAllocator getEventAllocator() {
409 return mAllocator;
410 }
411
412 @Override
413 public XMLReporter getXMLReporter() {
414 return mConfig.getXMLReporter();
415 }
416
417 @Override
418 public XMLResolver getXMLResolver() {
419 return mConfig.getXMLResolver();
420 }
421
422 @Override
423 public boolean isPropertySupported(String name) {
424 return mConfig.isPropertySupported(name);
425 }
426
427 @Override
428 public void setEventAllocator(XMLEventAllocator allocator) {
429 mAllocator = allocator;
430 }
431
432 @Override
433 public void setXMLReporter(XMLReporter r) {
434 mConfig.setXMLReporter(r);
435 }
436
437 /**
438 * Note: it's preferable to use Wstx-specific
439 * {@link ReaderConfig#setEntityResolver}
440 * instead, if possible, since this just wraps passed in resolver.
441 */
442 @Override
443 public void setXMLResolver(XMLResolver r) {
444 mConfig.setXMLResolver(r);
445 }
446
447 /*
448 ///////////////////////////////////////////////////////////////////////
449 // Stax2 implementation
450 ///////////////////////////////////////////////////////////////////////
451 */
452
453 // // // Stax2, additional factory methods:
454
455 @Override
456 public XMLEventReader2 createXMLEventReader(URL src)
457 throws XMLStreamException
458 {
459 /* true for auto-close, since caller has no access to the underlying
460 * input stream created from the URL
461 */
462 return new WstxEventReader(createEventAllocator(),
463 createSR(createPrivateConfig(), src, true, true));
464 }
465
466 @Override
467 public XMLEventReader2 createXMLEventReader(File f)
468 throws XMLStreamException
469 {
470 /* true for auto-close, since caller has no access to the underlying
471 * input stream created from the File
472 */
473 return new WstxEventReader(createEventAllocator(),
474 createSR(f, true, true));
475 }
476
477 @Override
478 public XMLStreamReader2 createXMLStreamReader(URL src)
479 throws XMLStreamException
480 {
481 /* true for auto-close, since caller has no access to the underlying
482 * input stream created from the URL
483 */
484 return createSR(createPrivateConfig(), src, false, true);
485 }
486
487 /**
488 * Convenience factory method that allows for parsing a document
489 * stored in the specified file.
490 */
491 @Override
492 public XMLStreamReader2 createXMLStreamReader(File f)
493 throws XMLStreamException
494 {
495 /* true for auto-close, since caller has no access to the underlying
496 * input stream created from the File
497 */
498 return createSR(f, false, true);
499 }
500
501 // // // Stax2 "Profile" mutators
502
503 @Override
504 public void configureForXmlConformance() {
505 mConfig.configureForXmlConformance();
506 }
507
508 @Override
509 public void configureForConvenience() {
510 mConfig.configureForConvenience();
511 }
512
513 @Override
514 public void configureForSpeed() {
515 mConfig.configureForSpeed();
516 }
517
518 @Override
519 public void configureForLowMemUsage() {
520 mConfig.configureForLowMemUsage();
521 }
522
523 @Override
524 public void configureForRoundTripping() {
525 mConfig.configureForRoundTripping();
526 }
527
528 /*
529 ///////////////////////////////////////////////////////////////////////
530 // Woodstox-specific configuration access
531 ///////////////////////////////////////////////////////////////////////
532 */
533
534 public ReaderConfig getConfig() {
535 return mConfig;
536 }
537
538 /*
539 ///////////////////////////////////////////////////////////////////////
540 // Internal methods
541 ///////////////////////////////////////////////////////////////////////
542 */
543
544 /**
545 * Bottleneck method used for creating ALL full stream reader instances
546 * (via other createSR() methods and directly)
547 *
548 * @param forER True, if the reader is being constructed to be used
549 * by an event reader; false if it is not (or the purpose is not known)
550 * @param autoCloseInput Whether the underlying input source should be
551 * actually closed when encountering EOF, or when <code>close()</code>
552 * is called. Will be true for input sources that are automatically
553 * managed by stream reader (input streams created for
554 * {@link java.net.URL} and {@link java.io.File} arguments, or when
555 * configuration settings indicate auto-closing is to be enabled
556 * (the default value is false as per Stax 1.0 specs).
557 */
558 @SuppressWarnings("resource")
559 private XMLStreamReader2 doCreateSR(ReaderConfig cfg, SystemId systemId,
560 InputBootstrapper bs, boolean forER, boolean autoCloseInput)
561 throws XMLStreamException
562 {
563 /* Automatic closing of input: will happen always for some input
564 * types (ones application has no direct access to; but can also
565 * be explicitly enabled.
566 */
567 if (!autoCloseInput) {
568 autoCloseInput = cfg.willAutoCloseInput();
569 }
570
571 Reader r;
572 try {
573 r = bs.bootstrapInput(cfg, true, XmlConsts.XML_V_UNKNOWN);
574 if (bs.declaredXml11()) {
575 cfg.enableXml11(true);
576 }
577 } catch (IOException ie) {
578 throw new WstxIOException(ie);
579 }
580
581 /* null -> no public id available
582 * false -> don't close the reader when scope is closed.
583 */
584 BranchingReaderSource input = InputSourceFactory.constructDocumentSource
585 (cfg, bs, null, systemId, r, autoCloseInput);
586
587 return ValidatingStreamReader.createValidatingStreamReader(input, this, cfg, bs, forER);
588 }
589
590 /**
591 * Method that is eventually called to create a (full) stream read
592 * instance.
593 *<p>
594 * Note: defined as public method because it needs to be called by
595 * SAX implementation.
596 *
597 * @param systemId System id used for this reader (if any)
598 * @param bs Bootstrapper to use for creating actual underlying
599 * physical reader
600 * @param forER Flag to indicate whether it will be used via
601 * Event API (will affect some configuration settings), true if it
602 * will be, false if not (or not known)
603 * @param autoCloseInput Whether the underlying input source should be
604 * actually closed when encountering EOF, or when <code>close()</code>
605 * is called. Will be true for input sources that are automatically
606 * managed by stream reader (input streams created for
607 * {@link java.net.URL} and {@link java.io.File} arguments, or when
608 * configuration settings indicate auto-closing is to be enabled
609 * (the default value is false as per Stax 1.0 specs).
610 */
611 public XMLStreamReader2 createSR(ReaderConfig cfg, String systemId, InputBootstrapper bs,
612 boolean forER, boolean autoCloseInput)
613 throws XMLStreamException
614 {
615 // 16-Aug-2004, TSa: Maybe we have a context?
616 URL src = cfg.getBaseURL();
617
618 // If not, maybe we can derive it from system id?
619 if ((src == null) && (systemId != null && systemId.length() > 0)) {
620 try {
621 src = URLUtil.urlFromSystemId(systemId);
622 } catch (IOException ie) {
623 throw new WstxIOException(ie);
624 }
625 }
626 return doCreateSR(cfg, SystemId.construct(systemId, src), bs, forER, autoCloseInput);
627 }
628
629 public XMLStreamReader2 createSR(ReaderConfig cfg, SystemId systemId, InputBootstrapper bs,
630 boolean forER, boolean autoCloseInput)
631 throws XMLStreamException
632 {
633 return doCreateSR(cfg, systemId, bs, forER, autoCloseInput);
634 }
635
636 @SuppressWarnings("resource")
637 protected XMLStreamReader2 createSR(SystemId systemId, InputStream in, String enc,
638 boolean forER, boolean autoCloseInput)
639 throws XMLStreamException
640 {
641 // sanity check:
642 if (in == null) {
643 throw new IllegalArgumentException("Null InputStream is not a valid argument");
644 }
645 ReaderConfig cfg = createPrivateConfig();
646 if (enc == null || enc.length() == 0) {
647 return createSR(cfg, systemId, StreamBootstrapper.getInstance
648 (null, systemId, in), forER, autoCloseInput);
649 }
650
651 /* !!! 17-Feb-2006, TSa: We don't yet know if it's xml 1.0 or 1.1;
652 * so have to specify 1.0 (which is less restrictive WRT input
653 * streams). Would be better to let bootstrapper deal with it
654 * though:
655 */
656 Reader r = DefaultInputResolver.constructOptimizedReader(cfg, in, false, enc);
657 return createSR(cfg, systemId, ReaderBootstrapper.getInstance
658 (null, systemId, r, enc), forER, autoCloseInput);
659 }
660
661 protected XMLStreamReader2 createSR(ReaderConfig cfg, URL src,
662 boolean forER, boolean autoCloseInput)
663 throws XMLStreamException
664 {
665 final SystemId systemId = SystemId.construct(src);
666 try {
667 return createSR(cfg, systemId, URLUtil.inputStreamFromURL(src),
668 forER, autoCloseInput);
669 } catch (IOException ioe) {
670 throw new WstxIOException(ioe);
671 }
672 }
673
674 private XMLStreamReader2 createSR(ReaderConfig cfg, SystemId systemId,
675 InputStream in, boolean forER, boolean autoCloseInput)
676 throws XMLStreamException
677 {
678 return doCreateSR(cfg, systemId,
679 StreamBootstrapper.getInstance(null, systemId, in),
680 forER, autoCloseInput);
681 }
682
683 protected XMLStreamReader2 createSR(SystemId systemId, Reader r,
684 boolean forER, boolean autoCloseInput)
685 throws XMLStreamException
686 {
687 return createSR(createPrivateConfig(), systemId,
688 ReaderBootstrapper.getInstance
689 (null, systemId, r, null), forER, autoCloseInput);
690 }
691
692 @SuppressWarnings("resource")
693 protected XMLStreamReader2 createSR(File f, boolean forER, boolean autoCloseInput)
694 throws XMLStreamException
695 {
696 ReaderConfig cfg = createPrivateConfig();
697 try {
698 /* 18-Nov-2008, TSa: If P_BASE_URL is set, and File reference is
699 * relative, let's resolve against base...
700 */
701 if (!f.isAbsolute()) {
702 URL base = cfg.getBaseURL();
703 if (base != null) {
704 URL src = new URL(base, f.getPath());
705 return createSR(cfg, SystemId.construct(src), URLUtil.inputStreamFromURL(src),
706 forER, autoCloseInput);
707 }
708 }
709 final SystemId systemId = SystemId.construct(URLUtil.toURL(f));
710 return createSR(cfg, systemId, new FileInputStream(f), forER, autoCloseInput);
711
712 } catch (IOException ie) {
713 throw new WstxIOException(ie);
714 }
715 }
716
717 /**
718 * Another internal factory method, used when dealing with a generic
719 * Source base type. One thing worth noting is that 'auto-closing'
720 * will be enabled if the input source or Reader is constructed (and
721 * thus owned) by Woodstox.
722 *
723 * @param forER True, if the reader is being constructed to be used
724 * by an event reader; false if it is not (or the purpose is not known)
725 */
726 @SuppressWarnings("resource")
727 protected XMLStreamReader2 createSR(javax.xml.transform.Source src,
728 boolean forER)
729 throws XMLStreamException
730 {
731 ReaderConfig cfg = createPrivateConfig();
732 Reader r = null;
733 InputStream in = null;
734 String pubId = null;
735 String sysId = null;
736 String encoding = null;
737 boolean autoCloseInput;
738
739 InputBootstrapper bs = null;
740
741 if (src instanceof Stax2Source) {
742 Stax2Source ss = (Stax2Source) src;
743 sysId = ss.getSystemId();
744 pubId = ss.getPublicId();
745 encoding = ss.getEncoding();
746
747 try {
748 /* 11-Nov-2008, TSa: Let's add optimized handling for byte-block
749 * source
750 */
751 if (src instanceof Stax2ByteArraySource) {
752 Stax2ByteArraySource bas = (Stax2ByteArraySource) src;
753 bs = StreamBootstrapper.getInstance(pubId, SystemId.construct(sysId), bas.getBuffer(), bas.getBufferStart(), bas.getBufferEnd());
754 } else {
755 in = ss.constructInputStream();
756 if (in == null) {
757 r = ss.constructReader();
758 }
759 }
760 } catch (IOException ioe) {
761 throw new WstxIOException(ioe);
762 }
763 /* Caller has no direct access to stream/reader, Woodstox
764 * owns it and thus has to close too
765 */
766 autoCloseInput = true;
767 } else if (src instanceof StreamSource) {
768 StreamSource ss = (StreamSource) src;
769 sysId = ss.getSystemId();
770 pubId = ss.getPublicId();
771 in = ss.getInputStream();
772 if (in == null) {
773 r = ss.getReader();
774 }
775 /* Caller still has access to stream/reader; no need to
776 * force auto-close-input
777 */
778 autoCloseInput = cfg.willAutoCloseInput();
779 } else if (src instanceof SAXSource) {
780 SAXSource ss = (SAXSource) src;
781 /* 28-Jan-2006, TSa: Not a complete implementation, but maybe
782 * even this might help...
783 */
784 sysId = ss.getSystemId();
785 InputSource isrc = ss.getInputSource();
786 if (isrc != null) {
787 encoding = isrc.getEncoding();
788 in = isrc.getByteStream();
789 if (in == null) {
790 r = isrc.getCharacterStream();
791 }
792 }
793 /* Caller still has access to stream/reader; no need to
794 * force auto-close-input
795 */
796 autoCloseInput = cfg.willAutoCloseInput();
797 } else if (src instanceof DOMSource) {
798 DOMSource domSrc = (DOMSource) src;
799 // SymbolTable not used by the DOM-based 'reader':
800 return WstxDOMWrappingReader.createFrom(domSrc, cfg);
801 } else {
802 throw new IllegalArgumentException("Can not instantiate Stax reader for XML source type "+src.getClass()+" (unrecognized type)");
803 }
804 if (bs == null) { // may have already created boostrapper...
805 if (r != null) {
806 bs = ReaderBootstrapper.getInstance(pubId, SystemId.construct(sysId), r, encoding);
807 } else if (in != null) {
808 bs = StreamBootstrapper.getInstance(pubId, SystemId.construct(sysId), in);
809 } else if (sysId != null && sysId.length() > 0) {
810 /* 26-Dec-2008, TSa: If we must construct URL from system id,
811 * it means caller will not have access to resulting
812 * stream, thus we will force auto-closing.
813 */
814 autoCloseInput = true;
815 try {
816 return createSR(cfg, URLUtil.urlFromSystemId(sysId),
817 forER, autoCloseInput);
818 } catch (IOException ioe) {
819 throw new WstxIOException(ioe);
820 }
821 } else {
822 throw new XMLStreamException("Can not create Stax reader for the Source passed -- neither reader, input stream nor system id was accessible; can not use other types of sources (like embedded SAX streams)");
823 }
824 }
825 return createSR(cfg, sysId, bs, forER, autoCloseInput);
826 }
827
828 protected XMLEventAllocator createEventAllocator()
829 {
830 // Explicitly set allocate?
831 if (mAllocator != null) {
832 return mAllocator.newInstance();
833 }
834
835 /* Complete or fast one? Note: standard allocator is designed
836 * in such a way that newInstance() need not be called (calling
837 * it wouldn't do anything, anyway)
838 */
839 return mConfig.willPreserveLocation() ?
840 DefaultEventAllocator.getDefaultInstance()
841 : DefaultEventAllocator.getFastInstance();
842 }
843
844 /**
845 * Method called to construct a copy of the factory's configuration
846 * object, such that two will be unlinked (changes to one are not
847 * reflect in the other).
848 *<p>
849 * Note: only public so that other woodstox components outside of
850 * this package can access it.
851 */
852 public ReaderConfig createPrivateConfig()
853 {
854 return mConfig.createNonShared(mSymbols.makeChild());
855 }
856 }
857