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.ws.commons.xmlutil; 27 28 import com.sun.istack.internal.NotNull; 29 import com.sun.istack.internal.logging.Logger; 30 import com.sun.xml.internal.ws.api.message.Message; 31 import com.sun.xml.internal.ws.api.message.Messages; 32 import com.sun.xml.internal.ws.api.message.Packet; 33 import com.sun.xml.internal.ws.util.xml.XmlUtil; 34 35 import javax.xml.stream.*; 36 import javax.xml.xpath.XPathFactoryConfigurationException; 37 import java.io.*; 38 import java.lang.reflect.Constructor; 39 import java.util.concurrent.atomic.AtomicBoolean; 40 import java.util.logging.Level; 41 42 /** 43 * Utility class that provides conversion of different XML representations 44 * from/to various other formats 45 * 46 * @author Marek Potociar 47 */ 48 public final class Converter { 49 50 public static final String UTF_8 = "UTF-8"; 51 52 private Converter() { 53 // prevents instantiation 54 } 55 private static final Logger LOGGER = Logger.getLogger(Converter.class); 56 private static final ContextClassloaderLocal<XMLOutputFactory> xmlOutputFactory = new ContextClassloaderLocal<XMLOutputFactory>() { 57 @Override 58 protected XMLOutputFactory initialValue() throws Exception { 59 return XMLOutputFactory.newInstance(); 60 } 61 }; 62 private static final AtomicBoolean logMissingStaxUtilsWarning = new AtomicBoolean(false); 63 64 /** 65 * Converts a throwable to String 66 * 67 * @param throwable 68 * @return String representation of throwable 69 */ 70 public static String toString(Throwable throwable) { 71 if (throwable == null) { 72 return "[ No exception ]"; 73 } 74 75 StringWriter stringOut = new StringWriter(); 76 throwable.printStackTrace(new PrintWriter(stringOut)); 77 78 return stringOut.toString(); 79 } 80 81 public static String toString(Packet packet) { 82 if (packet == null) { 83 return "[ Null packet ]"; 84 } else if (packet.getMessage() == null) { 85 return "[ Empty packet ]"; 86 } 87 88 return toString(packet.getMessage()); 89 } 90 91 public static String toStringNoIndent(Packet packet) { 92 if (packet == null) { 93 return "[ Null packet ]"; 94 } else if (packet.getMessage() == null) { 95 return "[ Empty packet ]"; 96 } 97 98 return toStringNoIndent(packet.getMessage()); 99 } 100 101 public static String toString(Message message) { 102 return toString(message, true); 103 } 104 105 public static String toStringNoIndent(Message message) { 106 return toString(message, false); 107 } 108 109 private static String toString(Message message, boolean createIndenter) { 110 if (message == null) { 111 return "[ Null message ]"; 112 } 113 StringWriter stringOut = null; 114 try { 115 stringOut = new StringWriter(); 116 XMLStreamWriter writer = null; 117 try { 118 writer = xmlOutputFactory.get().createXMLStreamWriter(stringOut); 119 if (createIndenter) { 120 writer = createIndenter(writer); 121 } 122 message.copy().writeTo(writer); 123 } catch (Exception e) { // WSIT-1596 - Message Dumping should not affect other processing 124 LOGGER.log(Level.WARNING, "Unexpected exception occured while dumping message", e); 125 } finally { 126 if (writer != null) { 127 try { 128 writer.close(); 129 } catch (XMLStreamException ignored) { 130 LOGGER.fine("Unexpected exception occured while closing XMLStreamWriter", ignored); 131 } 132 } 133 } 134 return stringOut.toString(); 135 } finally { 136 if (stringOut != null) { 137 try { 138 stringOut.close(); 139 } catch (IOException ex) { 140 LOGGER.finest("An exception occured when trying to close StringWriter", ex); 141 } 142 } 143 } 144 } 145 146 public static byte[] toBytes(Message message, String encoding) throws XMLStreamException { 147 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 148 149 try { 150 if (message != null) { 151 XMLStreamWriter xsw = xmlOutputFactory.get().createXMLStreamWriter(baos, encoding); 152 try { 153 message.writeTo(xsw); 154 } finally { 155 try { 156 xsw.close(); 157 } catch (XMLStreamException ex) { 158 LOGGER.warning("Unexpected exception occured while closing XMLStreamWriter", ex); 159 } 160 } 161 } 162 163 return baos.toByteArray(); 164 } finally { 165 try { 166 baos.close(); 167 } catch (IOException ex) { 168 LOGGER.warning("Unexpected exception occured while closing ByteArrayOutputStream", ex); 169 } 170 } 171 } 172 173 /** 174 * Converts JAX-WS RI message represented as input stream back to Message 175 * object. 176 * 177 * @param dataStream message data stream 178 * @param encoding message data stream encoding 179 * 180 * @return {@link com.sun.xml.internal.ws.api.message.Message} object created from the data stream 181 */ 182 public static Message toMessage(@NotNull InputStream dataStream, String encoding) throws XMLStreamException { 183 XMLStreamReader xsr = XmlUtil.newXMLInputFactory(true).createXMLStreamReader(dataStream, encoding); 184 return Messages.create(xsr); 185 } 186 187 public static String messageDataToString(final byte[] data, final String encoding) { 188 try { 189 return toString(toMessage(new ByteArrayInputStream(data), encoding)); 190 // closing ByteArrayInputStream has no effect, so ignoring the redundant call 191 } catch (XMLStreamException ex) { 192 LOGGER.warning("Unexpected exception occured while converting message data to string", ex); 193 return "[ Message Data Conversion Failed ]"; 194 } 195 } 196 197 /** 198 * Wraps {@link javax.xml.stream.XMLStreamWriter} by an indentation engine if possible. 199 * 200 * <p> 201 * We can do this only when we have <tt>stax-utils.jar</tt> in the class path. 202 */ 203 private static XMLStreamWriter createIndenter(XMLStreamWriter writer) { 204 try { 205 Class<?> clazz = Converter.class.getClassLoader().loadClass("javanet.staxutils.IndentingXMLStreamWriter"); 206 Constructor<?> c = clazz.getConstructor(XMLStreamWriter.class); 207 writer = XMLStreamWriter.class.cast(c.newInstance(writer)); 208 } catch (Exception ex) { 209 // if stax-utils.jar is not in the classpath, this will fail 210 // so, we'll just have to do without indentation 211 if (logMissingStaxUtilsWarning.compareAndSet(false, true)) { 212 LOGGER.log(Level.WARNING, "Put stax-utils.jar to the classpath to indent the dump output", ex); 213 } 214 } 215 return writer; 216 } 217 }