src/share/classes/com/sun/xml/internal/messaging/saaj/util/transform/EfficientStreamingTransformer.java

Mon, 04 May 2009 21:10:41 -0700

author
tbell
date
Mon, 04 May 2009 21:10:41 -0700
changeset 50
42dfec6871f6
parent 45
31822b475baa
child 78
860b95cc8d1d
permissions
-rw-r--r--

6658158: Mutable statics in SAAJ (findbugs)
6658163: txw2.DatatypeWriter.BUILDIN is a mutable static (findbugs)
Reviewed-by: darcy

duke@1 1 /*
tbell@45 2 * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved.
duke@1 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
duke@1 4 *
duke@1 5 * This code is free software; you can redistribute it and/or modify it
duke@1 6 * under the terms of the GNU General Public License version 2 only, as
duke@1 7 * published by the Free Software Foundation. Sun designates this
duke@1 8 * particular file as subject to the "Classpath" exception as provided
duke@1 9 * by Sun in the LICENSE file that accompanied this code.
duke@1 10 *
duke@1 11 * This code is distributed in the hope that it will be useful, but WITHOUT
duke@1 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
duke@1 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
duke@1 14 * version 2 for more details (a copy is included in the LICENSE file that
duke@1 15 * accompanied this code).
duke@1 16 *
duke@1 17 * You should have received a copy of the GNU General Public License version
duke@1 18 * 2 along with this work; if not, write to the Free Software Foundation,
duke@1 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
duke@1 20 *
duke@1 21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
duke@1 22 * CA 95054 USA or visit www.sun.com if you need additional information or
duke@1 23 * have any questions.
duke@1 24 */
duke@1 25
tbell@45 26
duke@1 27 /*
duke@1 28 * EfficientStreamingTransformer.java
duke@1 29 *
duke@1 30 * Created on July 29, 2002, 3:49 PM
duke@1 31 */
duke@1 32
duke@1 33 package com.sun.xml.internal.messaging.saaj.util.transform;
duke@1 34
duke@1 35 import java.io.*;
duke@1 36
duke@1 37 import javax.xml.parsers.DocumentBuilder;
duke@1 38 import javax.xml.parsers.DocumentBuilderFactory;
duke@1 39
duke@1 40 import javax.xml.transform.*;
duke@1 41 import javax.xml.transform.dom.DOMSource;
duke@1 42 import javax.xml.transform.dom.DOMResult;
duke@1 43 import javax.xml.transform.stream.StreamResult;
duke@1 44 import javax.xml.transform.stream.StreamSource;
duke@1 45
duke@1 46 import org.w3c.dom.Document;
duke@1 47
duke@1 48 import com.sun.xml.internal.messaging.saaj.util.XMLDeclarationParser;
duke@1 49 import com.sun.xml.internal.messaging.saaj.util.FastInfosetReflection;
duke@1 50
duke@1 51 /**
duke@1 52 * This class is a proxy for a Transformer object with optimizations
duke@1 53 * for certain cases. If source and result are of type stream, then
duke@1 54 * bytes are simply copied whenever possible (note that this assumes
duke@1 55 * that the input is well formed). In addition, it provides support for
duke@1 56 * FI using native DOM parsers and serializers.
duke@1 57 *
duke@1 58 * @author Panos Kougiouris panos@acm.org
duke@1 59 * @author Santiago.PericasGeertsen@sun.com
duke@1 60 *
duke@1 61 */
duke@1 62 public class EfficientStreamingTransformer
duke@1 63 extends javax.xml.transform.Transformer {
duke@1 64
tbell@50 65 //static final String version;
tbell@50 66 //static final String vendor;
duke@1 67
tbell@50 68 protected static final TransformerFactory transformerFactory = TransformerFactory.newInstance();
duke@1 69
tbell@50 70 //removing support for Java 1.4 and 1.3 : CR6658158
tbell@50 71 /*static {
tbell@50 72 version = System.getProperty("java.vm.version");
tbell@50 73 vendor = System.getProperty("java.vm.vendor");
tbell@50 74 if (vendor.startsWith("Sun") &&
tbell@50 75 (version.startsWith("1.4") || version.startsWith("1.3"))) {
tbell@50 76 transformerFactory =
tbell@50 77 new com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl();
tbell@50 78 }
tbell@50 79 }
tbell@50 80 */
duke@1 81
duke@1 82 /**
duke@1 83 * TransformerFactory instance.
duke@1 84 */
duke@1 85
duke@1 86 /**
duke@1 87 * Underlying XSLT transformer.
duke@1 88 */
duke@1 89 private Transformer m_realTransformer = null;
duke@1 90
duke@1 91 /**
duke@1 92 * Undelying FI DOM parser.
duke@1 93 */
duke@1 94 private Object m_fiDOMDocumentParser = null;
duke@1 95
duke@1 96 /**
duke@1 97 * Underlying FI DOM serializer.
duke@1 98 */
duke@1 99 private Object m_fiDOMDocumentSerializer = null;
duke@1 100
duke@1 101 private EfficientStreamingTransformer() {
duke@1 102 }
duke@1 103
duke@1 104 private void materialize() throws TransformerException {
duke@1 105 if (m_realTransformer == null) {
duke@1 106 m_realTransformer = transformerFactory.newTransformer();
duke@1 107 }
duke@1 108 }
duke@1 109
duke@1 110 public void clearParameters() {
duke@1 111 if (m_realTransformer != null)
duke@1 112 m_realTransformer.clearParameters();
duke@1 113 }
duke@1 114
duke@1 115 public javax.xml.transform.ErrorListener getErrorListener() {
duke@1 116 try {
duke@1 117 materialize();
duke@1 118 return m_realTransformer.getErrorListener();
duke@1 119 } catch (TransformerException e) {
duke@1 120 // will be caught later
duke@1 121 }
duke@1 122 return null;
duke@1 123 }
duke@1 124
duke@1 125 public java.util.Properties getOutputProperties() {
duke@1 126 try {
duke@1 127 materialize();
duke@1 128 return m_realTransformer.getOutputProperties();
duke@1 129 } catch (TransformerException e) {
duke@1 130 // will be caught later
duke@1 131 }
duke@1 132 return null;
duke@1 133 }
duke@1 134
duke@1 135 public String getOutputProperty(String str)
duke@1 136 throws java.lang.IllegalArgumentException {
duke@1 137 try {
duke@1 138 materialize();
duke@1 139 return m_realTransformer.getOutputProperty(str);
duke@1 140 } catch (TransformerException e) {
duke@1 141 // will be caught later
duke@1 142 }
duke@1 143 return null;
duke@1 144 }
duke@1 145
duke@1 146 public Object getParameter(String str) {
duke@1 147 try {
duke@1 148 materialize();
duke@1 149 return m_realTransformer.getParameter(str);
duke@1 150 } catch (TransformerException e) {
duke@1 151 // will be caught later
duke@1 152 }
duke@1 153 return null;
duke@1 154 }
duke@1 155
duke@1 156 public javax.xml.transform.URIResolver getURIResolver() {
duke@1 157 try {
duke@1 158 materialize();
duke@1 159 return m_realTransformer.getURIResolver();
duke@1 160 } catch (TransformerException e) {
duke@1 161 // will be caught later
duke@1 162 }
duke@1 163 return null;
duke@1 164 }
duke@1 165
duke@1 166 public void setErrorListener(
duke@1 167 javax.xml.transform.ErrorListener errorListener)
duke@1 168 throws java.lang.IllegalArgumentException {
duke@1 169 try {
duke@1 170 materialize();
duke@1 171 m_realTransformer.setErrorListener(errorListener);
duke@1 172 } catch (TransformerException e) {
duke@1 173 // will be caught later
duke@1 174 }
duke@1 175 }
duke@1 176
duke@1 177 public void setOutputProperties(java.util.Properties properties)
duke@1 178 throws java.lang.IllegalArgumentException {
duke@1 179 try {
duke@1 180 materialize();
duke@1 181 m_realTransformer.setOutputProperties(properties);
duke@1 182 } catch (TransformerException e) {
duke@1 183 // will be caught later
duke@1 184 }
duke@1 185 }
duke@1 186
duke@1 187 public void setOutputProperty(String str, String str1)
duke@1 188 throws java.lang.IllegalArgumentException {
duke@1 189 try {
duke@1 190 materialize();
duke@1 191 m_realTransformer.setOutputProperty(str, str1);
duke@1 192 } catch (TransformerException e) {
duke@1 193 // will be caught later
duke@1 194 }
duke@1 195 }
duke@1 196
duke@1 197 public void setParameter(String str, Object obj) {
duke@1 198 try {
duke@1 199 materialize();
duke@1 200 m_realTransformer.setParameter(str, obj);
duke@1 201 } catch (TransformerException e) {
duke@1 202 // will be caught later
duke@1 203 }
duke@1 204 }
duke@1 205
duke@1 206 public void setURIResolver(javax.xml.transform.URIResolver uRIResolver) {
duke@1 207 try {
duke@1 208 materialize();
duke@1 209 m_realTransformer.setURIResolver(uRIResolver);
duke@1 210 } catch (TransformerException e) {
duke@1 211 // will be caught later
duke@1 212 }
duke@1 213 }
duke@1 214
duke@1 215 private InputStream getInputStreamFromSource(StreamSource s)
duke@1 216 throws TransformerException {
duke@1 217
duke@1 218 InputStream stream = s.getInputStream();
duke@1 219 if (stream != null)
duke@1 220 return stream;
duke@1 221
duke@1 222 if (s.getReader() != null)
duke@1 223 return null;
duke@1 224
duke@1 225 String systemId = s.getSystemId();
duke@1 226 if (systemId != null) {
duke@1 227 try {
duke@1 228 String fileURL = systemId;
duke@1 229
duke@1 230 if (systemId.startsWith("file:///"))
duke@1 231 {
duke@1 232 /*
duke@1 233 systemId is:
duke@1 234 file:///<drive>:/some/path/file.xml
duke@1 235 or
duke@1 236 file:///some/path/file.xml
duke@1 237 */
duke@1 238
duke@1 239 String absolutePath = systemId.substring(7);
duke@1 240 /*
duke@1 241 /<drive>:/some/path/file.xml
duke@1 242 or
duke@1 243 /some/path/file.xml
duke@1 244 */
duke@1 245
duke@1 246 boolean hasDriveDesignator = absolutePath.indexOf(":") > 0;
duke@1 247 if (hasDriveDesignator) {
duke@1 248 String driveDesignatedPath = absolutePath.substring(1);
duke@1 249 /*
duke@1 250 <drive>:/some/path/file.xml */
duke@1 251 fileURL = driveDesignatedPath;
duke@1 252 }
duke@1 253 else {
duke@1 254 /*
duke@1 255 /some/path/file.xml */
duke@1 256 fileURL = absolutePath;
duke@1 257 }
duke@1 258 }
duke@1 259 return new FileInputStream(fileURL);
duke@1 260 } catch (IOException e) {
duke@1 261 throw new TransformerException(e.toString());
duke@1 262 }
duke@1 263 }
duke@1 264
duke@1 265 throw new TransformerException("Unexpected StreamSource object");
duke@1 266 }
duke@1 267
duke@1 268 //------------------------------------------------------------------------
duke@1 269
duke@1 270 public void transform(
duke@1 271 javax.xml.transform.Source source,
duke@1 272 javax.xml.transform.Result result)
duke@1 273 throws javax.xml.transform.TransformerException
duke@1 274 {
duke@1 275 // StreamSource -> StreamResult
duke@1 276 if ((source instanceof StreamSource)
duke@1 277 && (result instanceof StreamResult)) {
duke@1 278 try {
duke@1 279 StreamSource streamSource = (StreamSource) source;
duke@1 280 InputStream is = getInputStreamFromSource(streamSource);
duke@1 281
duke@1 282 OutputStream os = ((StreamResult) result).getOutputStream();
duke@1 283 if (os == null)
duke@1 284 // TODO: We might want to fix this if it were to be used beyond
duke@1 285 // XmlDataContentHandler that we know uses only OutputStream
duke@1 286 throw new TransformerException("Unexpected StreamResult object contains null OutputStream");
duke@1 287
duke@1 288 if (is != null) {
duke@1 289 if (is.markSupported())
duke@1 290 is.mark(Integer.MAX_VALUE);
duke@1 291 int num;
duke@1 292 byte[] b = new byte[8192];
duke@1 293 while ((num = is.read(b)) != -1) {
duke@1 294 os.write(b, 0, num);
duke@1 295 }
duke@1 296 if (is.markSupported())
duke@1 297 is.reset();
duke@1 298 return;
duke@1 299 }
duke@1 300
duke@1 301 Reader reader = streamSource.getReader();
duke@1 302 if (reader != null) {
duke@1 303
duke@1 304 if (reader.markSupported())
duke@1 305 reader.mark(Integer.MAX_VALUE);
duke@1 306
duke@1 307 PushbackReader pushbackReader = new PushbackReader(reader, 4096);
duke@1 308 //some size to unread <?xml ....?>
duke@1 309 XMLDeclarationParser ev =
duke@1 310 new XMLDeclarationParser(pushbackReader);
duke@1 311 try {
duke@1 312 ev.parse();
duke@1 313 } catch (Exception ex) {
duke@1 314 throw new TransformerException(
duke@1 315 "Unable to run the JAXP transformer on a stream "
duke@1 316 + ex.getMessage());
duke@1 317 }
duke@1 318 Writer writer =
duke@1 319 new OutputStreamWriter(os /*, ev.getEncoding()*/);
duke@1 320 ev.writeTo(writer); // doesn't write any, if no header
duke@1 321
duke@1 322 int num;
duke@1 323 char[] ac = new char[8192];
duke@1 324 while ((num = pushbackReader.read(ac)) != -1) {
duke@1 325 writer.write(ac, 0, num);
duke@1 326 }
duke@1 327 writer.flush();
duke@1 328
duke@1 329 if (reader.markSupported())
duke@1 330 reader.reset();
duke@1 331 return;
duke@1 332 }
duke@1 333 } catch (IOException e) {
duke@1 334 e.printStackTrace();
duke@1 335 throw new TransformerException(e.toString());
duke@1 336 }
duke@1 337
duke@1 338 throw new TransformerException("Unexpected StreamSource object");
duke@1 339 }
duke@1 340 // FastInfosetSource -> DOMResult
duke@1 341 else if (FastInfosetReflection.isFastInfosetSource(source)
duke@1 342 && (result instanceof DOMResult))
duke@1 343 {
duke@1 344 try {
duke@1 345 // Use reflection to avoid a static dep with FI
duke@1 346 if (m_fiDOMDocumentParser == null) {
duke@1 347 m_fiDOMDocumentParser = FastInfosetReflection.DOMDocumentParser_new();
duke@1 348 }
duke@1 349
duke@1 350 // m_fiDOMDocumentParser.parse(document, source.getInputStream())
duke@1 351 FastInfosetReflection.DOMDocumentParser_parse(
duke@1 352 m_fiDOMDocumentParser,
duke@1 353 (Document) ((DOMResult) result).getNode(),
duke@1 354 FastInfosetReflection.FastInfosetSource_getInputStream(source));
duke@1 355
duke@1 356 // We're done!
duke@1 357 return;
duke@1 358 }
duke@1 359 catch (Exception e) {
duke@1 360 throw new TransformerException(e);
duke@1 361 }
duke@1 362 }
duke@1 363 // DOMSource -> FastInfosetResult
duke@1 364 else if ((source instanceof DOMSource)
duke@1 365 && FastInfosetReflection.isFastInfosetResult(result))
duke@1 366 {
duke@1 367 try {
duke@1 368 // Use reflection to avoid a static dep with FI
duke@1 369 if (m_fiDOMDocumentSerializer == null) {
duke@1 370 m_fiDOMDocumentSerializer = FastInfosetReflection.DOMDocumentSerializer_new();
duke@1 371 }
duke@1 372
duke@1 373 // m_fiDOMDocumentSerializer.setOutputStream(result.getOutputStream())
duke@1 374 FastInfosetReflection.DOMDocumentSerializer_setOutputStream(
duke@1 375 m_fiDOMDocumentSerializer,
duke@1 376 FastInfosetReflection.FastInfosetResult_getOutputStream(result));
duke@1 377
duke@1 378 // m_fiDOMDocumentSerializer.serialize(node)
duke@1 379 FastInfosetReflection.DOMDocumentSerializer_serialize(
duke@1 380 m_fiDOMDocumentSerializer,
duke@1 381 ((DOMSource) source).getNode());
duke@1 382
duke@1 383 // We're done!
duke@1 384 return;
duke@1 385 }
duke@1 386 catch (Exception e) {
duke@1 387 throw new TransformerException(e);
duke@1 388 }
duke@1 389 }
duke@1 390
duke@1 391 // All other cases -- use transformer object
duke@1 392
duke@1 393 materialize();
duke@1 394 m_realTransformer.transform(source, result);
duke@1 395 }
duke@1 396
duke@1 397 /**
duke@1 398 * Threadlocal to hold a Transformer instance for this thread.
duke@1 399 */
duke@1 400 private static ThreadLocal effTransformer = new ThreadLocal();
duke@1 401
duke@1 402 /**
duke@1 403 * Return Transformer instance for this thread, allocating a new one if
duke@1 404 * necessary. Note that this method does not clear global parameters,
duke@1 405 * properties or any other data set on a previously used transformer.
duke@1 406 */
duke@1 407 public static Transformer newTransformer() {
duke@1 408 Transformer tt = (Transformer) effTransformer.get();
duke@1 409 if (tt == null) {
duke@1 410 effTransformer.set(tt = new EfficientStreamingTransformer());
duke@1 411 }
duke@1 412 return tt;
duke@1 413 }
duke@1 414
duke@1 415 }

mercurial