-
-
Notifications
You must be signed in to change notification settings - Fork 81
/
WstxOutputFactory.java
389 lines (347 loc) · 12.8 KB
/
WstxOutputFactory.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
/* Woodstox XML processor
*
* Copyright (c) 2004- Tatu Saloranta, tatu.saloranta@iki.fi
*
* Licensed under the License specified in the file LICENSE which is
* included with the source code.
* You may not use this file except in compliance with the License.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.ctc.wstx.stax;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import javax.xml.stream.XMLEventWriter;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import javax.xml.transform.Result;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.stream.StreamResult;
import aQute.bnd.annotation.spi.ServiceProvider;
import org.codehaus.stax2.XMLOutputFactory2;
import org.codehaus.stax2.XMLStreamWriter2;
import org.codehaus.stax2.io.Stax2Result;
import org.codehaus.stax2.ri.Stax2EventWriterImpl;
import org.codehaus.stax2.ri.Stax2WriterAdapter;
import com.ctc.wstx.api.WriterConfig;
import com.ctc.wstx.api.WstxOutputProperties;
import com.ctc.wstx.cfg.OutputConfigFlags;
import com.ctc.wstx.dom.WstxDOMWrappingWriter;
import com.ctc.wstx.exc.WstxIOException;
import com.ctc.wstx.io.CharsetNames;
import com.ctc.wstx.io.UTF8Writer;
import com.ctc.wstx.sw.AsciiXmlWriter;
import com.ctc.wstx.sw.BufferingXmlWriter;
import com.ctc.wstx.sw.ISOLatin1XmlWriter;
import com.ctc.wstx.sw.NonNsStreamWriter;
import com.ctc.wstx.sw.RepairingNsStreamWriter;
import com.ctc.wstx.sw.SimpleNsStreamWriter;
import com.ctc.wstx.sw.XmlWriter;
import com.ctc.wstx.util.URLUtil;
/**
* Implementation of {@link XMLOutputFactory} for Wstx.
*<p>
* TODO:
*<ul>
* <li>Implement outputter that creates SAX events (DOM-backed
* writer exists as of Woodstox 3.2)
* </li>
*</ul>
*/
@ServiceProvider(XMLOutputFactory.class)
public class WstxOutputFactory
extends XMLOutputFactory2
implements OutputConfigFlags
{
/*
///////////////////////////////////////////////////////////
// Actual storage of configuration settings
///////////////////////////////////////////////////////////
*/
protected final WriterConfig mConfig;
/*
///////////////////////////////////////////////////////////
// Life-cycle
///////////////////////////////////////////////////////////
*/
public WstxOutputFactory() {
mConfig = WriterConfig.createFullDefaults();
}
/*
///////////////////////////////////////////////////////////
// XMLOutputFactory API
///////////////////////////////////////////////////////////
*/
@Override
public XMLEventWriter createXMLEventWriter(OutputStream out)
throws XMLStreamException
{
return createXMLEventWriter(out, null);
}
@Override
public XMLEventWriter createXMLEventWriter(OutputStream out, String enc)
throws XMLStreamException
{
if (out == null) {
throw new IllegalArgumentException("Null OutputStream is not a valid argument");
}
return new Stax2EventWriterImpl(createSW(out, null, enc, false));
}
@Override
public XMLEventWriter createXMLEventWriter(javax.xml.transform.Result result)
throws XMLStreamException
{
return new Stax2EventWriterImpl(createSW(result));
}
@Override
public XMLEventWriter createXMLEventWriter(Writer w)
throws XMLStreamException
{
if (w == null) {
throw new IllegalArgumentException("Null Writer is not a valid argument");
}
return new Stax2EventWriterImpl(createSW(null, w, null, false));
}
@Override
public XMLStreamWriter createXMLStreamWriter(OutputStream out)
throws XMLStreamException
{
return createXMLStreamWriter(out, null);
}
@Override
public XMLStreamWriter createXMLStreamWriter(OutputStream out, String enc)
throws XMLStreamException
{
if (out == null) {
throw new IllegalArgumentException("Null OutputStream is not a valid argument");
}
return createSW(out, null, enc, false);
}
@Override
public XMLStreamWriter createXMLStreamWriter(javax.xml.transform.Result result)
throws XMLStreamException
{
return createSW(result);
}
@Override
public XMLStreamWriter createXMLStreamWriter(Writer w)
throws XMLStreamException
{
if (w == null) {
throw new IllegalArgumentException("Null Writer is not a valid argument");
}
return createSW(null, w, null, false);
}
@Override
public Object getProperty(String name) {
return mConfig.getProperty(name);
}
@Override
public boolean isPropertySupported(String name) {
return mConfig.isPropertySupported(name);
}
@Override
public void setProperty(String name, Object value)
{
mConfig.setProperty(name, value);
}
/*
///////////////////////////////////////////////////////////
// Stax2 extensions
///////////////////////////////////////////////////////////
*/
// // // Stax2 additional (encoding-aware) factory methods
@Override
public XMLEventWriter createXMLEventWriter(Writer w, String enc)
throws XMLStreamException
{
return new Stax2EventWriterImpl(createSW(null, w, enc, false));
}
@Override
public XMLEventWriter createXMLEventWriter(XMLStreamWriter sw)
throws XMLStreamException
{
XMLStreamWriter2 sw2 = Stax2WriterAdapter.wrapIfNecessary(sw);
return new Stax2EventWriterImpl(sw2);
}
@Override
public XMLStreamWriter2 createXMLStreamWriter(Writer w, String enc)
throws XMLStreamException
{
return createSW(null, w, enc, false);
}
// // // Stax2 "Profile" mutators
@Override
public void configureForXmlConformance() {
mConfig.configureForXmlConformance();
}
@Override
public void configureForRobustness() {
mConfig.configureForRobustness();
}
@Override
public void configureForSpeed() {
mConfig.configureForSpeed();
}
/*
///////////////////////////////////////////////////////////
// Woodstox-specific configuration access
///////////////////////////////////////////////////////////
*/
public WriterConfig getConfig() {
return mConfig;
}
/*
///////////////////////////////////////////////////////////
// Internal methods:
///////////////////////////////////////////////////////////
*/
/**
* Bottleneck factory method used internally; needs to take care of passing
* proper settings to stream writer.
*
* @param requireAutoClose Whether this result will always require
* auto-close be enabled (true); or only if application has
* requested it (false)
*/
@SuppressWarnings("resource")
private XMLStreamWriter2 createSW(OutputStream out, Writer w, String enc,
boolean requireAutoClose)
throws XMLStreamException
{
/* Need to ensure that the configuration object is not shared
* any more; otherwise later changes via factory could be
* visible half-way through output...
*/
WriterConfig cfg = mConfig.createNonShared();
XmlWriter xw;
boolean autoCloseOutput = requireAutoClose || mConfig.willAutoCloseOutput();
if (w == null) {
if (enc == null) {
enc = WstxOutputProperties.DEFAULT_OUTPUT_ENCODING;
} else {
/* Canonical ones are interned, so we may have
* normalized encoding already...
*/
if (enc != CharsetNames.CS_UTF8
&& enc != CharsetNames.CS_ISO_LATIN1
&& enc != CharsetNames.CS_US_ASCII) {
enc = CharsetNames.normalize(enc);
}
}
try {
if (enc == CharsetNames.CS_UTF8) {
w = new UTF8Writer(cfg, out, autoCloseOutput);
xw = new BufferingXmlWriter(w, cfg, enc, autoCloseOutput, out, 16);
} else if (enc == CharsetNames.CS_ISO_LATIN1) {
xw = new ISOLatin1XmlWriter(out, cfg, autoCloseOutput);
} else if (enc == CharsetNames.CS_US_ASCII) {
xw = new AsciiXmlWriter(out, cfg, autoCloseOutput);
} else {
w = new OutputStreamWriter(out, enc);
xw = new BufferingXmlWriter(w, cfg, enc, autoCloseOutput, out, -1);
}
} catch (IOException ex) {
throw new XMLStreamException(ex);
}
} else {
// we may still be able to figure out the encoding:
if (enc == null) {
enc = CharsetNames.findEncodingFor(w);
}
try {
xw = new BufferingXmlWriter(w, cfg, enc, autoCloseOutput, null, -1);
} catch (IOException ex) {
throw new XMLStreamException(ex);
}
}
return createSW(enc, cfg, xw);
}
/**
* Called by {code createSW(OutputStream, Writer, String, boolean)} after all of the
* necessary configuration logic is complete.
*/
protected XMLStreamWriter2 createSW(String enc, WriterConfig cfg, XmlWriter xw) {
if (cfg.willSupportNamespaces()) {
if (cfg.automaticNamespacesEnabled()) {
return new RepairingNsStreamWriter(xw, enc, cfg);
}
return new SimpleNsStreamWriter(xw, enc, cfg);
}
return new NonNsStreamWriter(xw, enc, cfg);
}
@SuppressWarnings("resource")
private XMLStreamWriter2 createSW(Result res)
throws XMLStreamException
{
OutputStream out = null;
Writer w = null;
String encoding = null;
boolean requireAutoClose;
String sysId = null;
if (res instanceof Stax2Result) {
Stax2Result sr = (Stax2Result) res;
try {
out = sr.constructOutputStream();
if (out == null) {
w = sr.constructWriter();
}
} catch (IOException ioe) {
throw new WstxIOException(ioe);
}
// yes, it's required since caller has no access to stream/writer:
requireAutoClose = true;
} else if (res instanceof StreamResult) {
StreamResult sr = (StreamResult) res;
out = sr.getOutputStream();
sysId = sr.getSystemId();
if (out == null) {
w = sr.getWriter();
}
/* Caller owns it, only auto-close if requested to do so:
* (except that for system-id-only, it'll still be required,
* see code below)
*/
requireAutoClose = false;
} else if (res instanceof SAXResult) {
SAXResult sr = (SAXResult) res;
sysId = sr.getSystemId();
if (sysId == null || sysId.length() == 0) {
throw new XMLStreamException("Can not create a stream writer for a SAXResult that does not have System Id (support for using SAX input source not implemented)");
}
requireAutoClose = true;
} else if (res instanceof DOMResult) {
return WstxDOMWrappingWriter.createFrom(mConfig.createNonShared(), (DOMResult) res);
} else {
throw new IllegalArgumentException("Can not instantiate a writer for XML result type "+res.getClass()+" (unrecognized type)");
}
if (out != null) {
return createSW(out, null, encoding, requireAutoClose);
}
if (w != null) {
return createSW(null, w, encoding, requireAutoClose);
}
if (sysId != null && sysId.length() > 0) {
/* 26-Dec-2008, TSa: If we must construct URL from system id,
* it means caller will not have access to resulting
* stream, thus we will force auto-closing.
*/
requireAutoClose = true;
try {
out = URLUtil.outputStreamFromURL(URLUtil.urlFromSystemId(sysId));
} catch (IOException ioe) {
throw new WstxIOException(ioe);
}
return createSW(out, null, encoding, requireAutoClose);
}
throw new XMLStreamException("Can not create Stax writer for passed-in Result -- neither writer, output stream or system id was accessible");
}
}