Tue, 09 Apr 2013 14:51:13 +0100
8010393: Update JAX-WS RI to 2.2.9-b12941
Reviewed-by: alanb, erikj
Contributed-by: miroslav.kos@oracle.com, martin.grebac@oracle.com
1 /*
2 * Copyright (c) 1997, 2012, 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 */
26 package com.sun.xml.internal.ws.api.streaming;
28 import com.sun.istack.internal.NotNull;
29 import com.sun.istack.internal.Nullable;
30 import com.sun.xml.internal.ws.encoding.HasEncoding;
31 import com.sun.xml.internal.ws.encoding.SOAPBindingCodec;
32 import com.sun.xml.internal.ws.streaming.XMLReaderException;
33 import com.sun.xml.internal.ws.util.xml.XMLStreamWriterFilter;
35 import javax.xml.stream.XMLOutputFactory;
36 import javax.xml.stream.XMLStreamException;
37 import javax.xml.stream.XMLStreamReader;
38 import javax.xml.stream.XMLStreamWriter;
39 import javax.xml.transform.stream.StreamResult;
40 import javax.xml.ws.WebServiceException;
41 import java.io.OutputStream;
42 import java.io.StringWriter;
43 import java.lang.reflect.InvocationTargetException;
44 import java.lang.reflect.Method;
45 import java.util.logging.Logger;
47 /**
48 * Factory for {@link XMLStreamWriter}.
49 *
50 * <p>
51 * This wraps {@link XMLOutputFactory} and allows us to reuse {@link XMLStreamWriter} instances
52 * when appropriate.
53 *
54 * @author Kohsuke Kawaguchi
55 */
56 public abstract class XMLStreamWriterFactory {
58 private static final Logger LOGGER = Logger.getLogger(XMLStreamWriterFactory.class.getName());
60 /**
61 * Singleton instance.
62 */
63 private static volatile @NotNull XMLStreamWriterFactory theInstance;
66 static {
67 XMLOutputFactory xof = null;
68 if (Boolean.getBoolean(XMLStreamWriterFactory.class.getName()+".woodstox")) {
69 try {
70 xof = (XMLOutputFactory)Class.forName("com.ctc.wstx.stax.WstxOutputFactory").newInstance();
71 } catch (Exception e) {
72 // Ignore and fallback to default XMLOutputFactory
73 }
74 }
75 if (xof == null) {
76 xof = XMLOutputFactory.newInstance();
77 }
79 XMLStreamWriterFactory f=null;
81 // this system property can be used to disable the pooling altogether,
82 // in case someone hits an issue with pooling in the production system.
83 if(!Boolean.getBoolean(XMLStreamWriterFactory.class.getName()+".noPool"))
84 f = Zephyr.newInstance(xof);
85 if(f==null) {
86 // is this Woodstox?
87 if(xof.getClass().getName().equals("com.ctc.wstx.stax.WstxOutputFactory"))
88 f = new NoLock(xof);
89 }
90 if (f == null)
91 f = new Default(xof);
93 theInstance = f;
94 LOGGER.fine("XMLStreamWriterFactory instance is = "+theInstance);
95 }
97 /**
98 * See {@link #create(OutputStream)} for the contract.
99 * This method may be invoked concurrently.
100 */
101 public abstract XMLStreamWriter doCreate(OutputStream out);
103 /**
104 * See {@link #create(OutputStream,String)} for the contract.
105 * This method may be invoked concurrently.
106 */
107 public abstract XMLStreamWriter doCreate(OutputStream out, String encoding);
109 /**
110 * See {@link #recycle(XMLStreamWriter)} for the contract.
111 * This method may be invoked concurrently.
112 */
113 public abstract void doRecycle(XMLStreamWriter r);
115 /**
116 * Should be invoked when the code finished using an {@link XMLStreamWriter}.
117 *
118 * <p>
119 * If the recycled instance implements {@link RecycleAware},
120 * {@link RecycleAware#onRecycled()} will be invoked to let the instance
121 * know that it's being recycled.
122 *
123 * <p>
124 * It is not a hard requirement to call this method on every {@link XMLStreamReader}
125 * instance. Not doing so just reduces the performance by throwing away
126 * possibly reusable instances. So the caller should always consider the effort
127 * it takes to recycle vs the possible performance gain by doing so.
128 *
129 * <p>
130 * This method may be invked by multiple threads concurrently.
131 *
132 * @param r
133 * The {@link XMLStreamReader} instance that the caller finished using.
134 * This could be any {@link XMLStreamReader} implementation, not just
135 * the ones that were created from this factory. So the implementation
136 * of this class needs to be aware of that.
137 */
138 public static void recycle(XMLStreamWriter r) {
139 get().doRecycle(r);
140 }
142 /**
143 * Interface that can be implemented by {@link XMLStreamWriter} to
144 * be notified when it's recycled.
145 *
146 * <p>
147 * This provides a filtering {@link XMLStreamWriter} an opportunity to
148 * recycle its inner {@link XMLStreamWriter}.
149 */
150 public interface RecycleAware {
151 void onRecycled();
152 }
154 /**
155 * Gets the singleton instance.
156 */
157 public static @NotNull XMLStreamWriterFactory get() {
158 return theInstance;
159 }
161 /**
162 * Overrides the singleton {@link XMLStreamWriterFactory} instance that
163 * the JAX-WS RI uses.
164 *
165 * @param f
166 * must not be null.
167 */
168 public static void set(@NotNull XMLStreamWriterFactory f) {
169 if(f==null) throw new IllegalArgumentException();
170 theInstance = f;
171 }
173 /**
174 * Short-cut for {@link #create(OutputStream, String)} with UTF-8.
175 */
176 public static XMLStreamWriter create(OutputStream out) {
177 return get().doCreate(out);
178 }
180 public static XMLStreamWriter create(OutputStream out, String encoding) {
181 return get().doCreate(out, encoding);
182 }
184 /**
185 * @deprecated
186 * Use {@link #create(OutputStream)}
187 */
188 public static XMLStreamWriter createXMLStreamWriter(OutputStream out) {
189 return create(out);
190 }
192 /**
193 * @deprecated
194 * Use {@link #create(OutputStream, String)}
195 */
196 public static XMLStreamWriter createXMLStreamWriter(OutputStream out, String encoding) {
197 return create(out, encoding);
198 }
200 /**
201 * @deprecated
202 * Use {@link #create(OutputStream, String)}. The boolean flag was unused anyway.
203 */
204 public static XMLStreamWriter createXMLStreamWriter(OutputStream out, String encoding, boolean declare) {
205 return create(out,encoding);
206 }
208 /**
209 * Default {@link XMLStreamWriterFactory} implementation
210 * that can work with any {@link XMLOutputFactory}.
211 *
212 * <p>
213 * {@link XMLOutputFactory} is not required to be thread-safe, so the
214 * create method on this implementation is synchronized.
215 */
216 public static final class Default extends XMLStreamWriterFactory {
217 private final XMLOutputFactory xof;
219 public Default(XMLOutputFactory xof) {
220 this.xof = xof;
221 }
223 public XMLStreamWriter doCreate(OutputStream out) {
224 return doCreate(out,"UTF-8");
225 }
227 public synchronized XMLStreamWriter doCreate(OutputStream out, String encoding) {
228 try {
229 XMLStreamWriter writer = xof.createXMLStreamWriter(out,encoding);
230 return new HasEncodingWriter(writer, encoding);
231 } catch (XMLStreamException e) {
232 throw new XMLReaderException("stax.cantCreate",e);
233 }
234 }
236 public void doRecycle(XMLStreamWriter r) {
237 // no recycling
238 }
239 }
241 /**
242 * {@link XMLStreamWriterFactory} implementation for Sun's StaX implementation.
243 *
244 * <p>
245 * This implementation supports instance reuse.
246 */
247 public static final class Zephyr extends XMLStreamWriterFactory {
248 private final XMLOutputFactory xof;
249 private final ThreadLocal<XMLStreamWriter> pool = new ThreadLocal<XMLStreamWriter>();
250 private final Method resetMethod;
251 private final Method setOutputMethod;
252 private final Class zephyrClass;
254 public static XMLStreamWriterFactory newInstance(XMLOutputFactory xof) {
255 try {
256 Class<?> clazz = xof.createXMLStreamWriter(new StringWriter()).getClass();
258 if(!clazz.getName().startsWith("com.sun.xml.internal.stream."))
259 return null; // nope
261 return new Zephyr(xof,clazz);
262 } catch (XMLStreamException e) {
263 return null; // impossible
264 } catch (NoSuchMethodException e) {
265 return null; // this xof wasn't Zephyr
266 }
267 }
269 private Zephyr(XMLOutputFactory xof, Class clazz) throws NoSuchMethodException {
270 this.xof = xof;
272 zephyrClass = clazz;
273 setOutputMethod = clazz.getMethod("setOutput", StreamResult.class, String.class);
274 resetMethod = clazz.getMethod("reset");
275 }
277 /**
278 * Fetchs an instance from the pool if available, otherwise null.
279 */
280 private @Nullable XMLStreamWriter fetch() {
281 XMLStreamWriter sr = pool.get();
282 if(sr==null) return null;
283 pool.set(null);
284 return sr;
285 }
287 public XMLStreamWriter doCreate(OutputStream out) {
288 return doCreate(out,"UTF-8");
289 }
291 public XMLStreamWriter doCreate(OutputStream out, String encoding) {
292 XMLStreamWriter xsw = fetch();
293 if(xsw!=null) {
294 // try to reuse
295 try {
296 resetMethod.invoke(xsw);
297 setOutputMethod.invoke(xsw,new StreamResult(out),encoding);
298 } catch (IllegalAccessException e) {
299 throw new XMLReaderException("stax.cantCreate",e);
300 } catch (InvocationTargetException e) {
301 throw new XMLReaderException("stax.cantCreate",e);
302 }
303 } else {
304 // create a new instance
305 try {
306 xsw = xof.createXMLStreamWriter(out,encoding);
307 } catch (XMLStreamException e) {
308 throw new XMLReaderException("stax.cantCreate",e);
309 }
310 }
311 return new HasEncodingWriter(xsw, encoding);
312 }
314 public void doRecycle(XMLStreamWriter r) {
315 if (r instanceof HasEncodingWriter) {
316 r = ((HasEncodingWriter)r).getWriter();
317 }
318 if(zephyrClass.isInstance(r)) {
319 // this flushes the underlying stream, so it might cause chunking issue
320 try {
321 r.close();
322 } catch (XMLStreamException e) {
323 throw new WebServiceException(e);
324 }
325 pool.set(r);
326 }
327 if(r instanceof RecycleAware)
328 ((RecycleAware)r).onRecycled();
329 }
330 }
332 /**
333 *
334 * For {@link javax.xml.stream.XMLOutputFactory} is thread safe.
335 */
336 public static final class NoLock extends XMLStreamWriterFactory {
337 private final XMLOutputFactory xof;
339 public NoLock(XMLOutputFactory xof) {
340 this.xof = xof;
341 }
343 public XMLStreamWriter doCreate(OutputStream out) {
344 return doCreate(out, SOAPBindingCodec.UTF8_ENCODING);
345 }
347 public XMLStreamWriter doCreate(OutputStream out, String encoding) {
348 try {
349 XMLStreamWriter writer = xof.createXMLStreamWriter(out,encoding);
350 return new HasEncodingWriter(writer, encoding);
351 } catch (XMLStreamException e) {
352 throw new XMLReaderException("stax.cantCreate",e);
353 }
354 }
356 public void doRecycle(XMLStreamWriter r) {
357 // no recycling
358 }
360 }
362 private static class HasEncodingWriter extends XMLStreamWriterFilter implements HasEncoding {
363 private final String encoding;
365 HasEncodingWriter(XMLStreamWriter writer, String encoding) {
366 super(writer);
367 this.encoding = encoding;
368 }
370 public String getEncoding() {
371 return encoding;
372 }
374 XMLStreamWriter getWriter() {
375 return writer;
376 }
377 }
378 }