1 /* 2 * Copyright (c) 1997, 2013, 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.message.jaxb; 27 28 import com.sun.xml.internal.ws.api.SOAPVersion; 29 import com.sun.xml.internal.ws.api.message.Message; 30 import com.sun.xml.internal.ws.api.message.MessageHeaders; 31 import com.sun.xml.internal.ws.encoding.SOAPBindingCodec; 32 import com.sun.xml.internal.ws.message.AbstractMessageImpl; 33 import com.sun.xml.internal.ws.message.PayloadElementSniffer; 34 import com.sun.xml.internal.ws.spi.db.BindingContext; 35 import com.sun.xml.internal.ws.spi.db.XMLBridge; 36 import com.sun.xml.internal.ws.streaming.MtomStreamWriter; 37 import com.sun.xml.internal.ws.streaming.XMLStreamWriterUtil; 38 import org.xml.sax.ContentHandler; 39 import org.xml.sax.ErrorHandler; 40 import org.xml.sax.SAXException; 41 42 import javax.xml.bind.JAXBContext; 43 import javax.xml.bind.JAXBException; 44 import javax.xml.bind.Marshaller; 45 import javax.xml.bind.attachment.AttachmentMarshaller; 46 import javax.xml.namespace.QName; 47 import javax.xml.stream.XMLStreamException; 48 import javax.xml.stream.XMLStreamReader; 49 import javax.xml.stream.XMLStreamWriter; 50 import javax.xml.transform.Source; 51 import javax.xml.ws.WebServiceException; 52 import java.io.OutputStream; 53 54 /** 55 * {@link Message} backed by a JAXB bean; this implementation is used when client uses 56 * Dispatch mechanism in JAXB/MESSAGE mode; difference from {@link JAXBMessage} is 57 * that {@code jaxbObject} holds whole SOAP message including SOAP envelope; 58 * it's the client who is responsible for preparing message content. 59 * 60 * @author Miroslav Kos (miroslav.kos at oracle.com) 61 */ 62 public class JAXBDispatchMessage extends AbstractMessageImpl { 63 64 private final Object jaxbObject; 65 66 private final XMLBridge bridge; 67 68 /** 69 * For the use case of a user-supplied JAXB context that is not 70 * a known JAXB type, as when creating a Disaptch object with a 71 * JAXB object parameter, we will marshal and unmarshal directly with 72 * the context object, as there is no Bond available. In this case, 73 * swaRef is not supported. 74 */ 75 private final JAXBContext rawContext; 76 77 /** 78 * Lazily sniffed payload element name 79 */ 80 private QName payloadQName; 81 82 /** 83 * Copy constructor. 84 */ 85 private JAXBDispatchMessage(JAXBDispatchMessage that) { 86 super(that); 87 jaxbObject = that.jaxbObject; 88 rawContext = that.rawContext; 89 bridge = that.bridge; 90 } 91 92 public JAXBDispatchMessage(JAXBContext rawContext, Object jaxbObject, SOAPVersion soapVersion) { 93 super(soapVersion); 94 this.bridge = null; 95 this.rawContext = rawContext; 96 this.jaxbObject = jaxbObject; 97 } 98 99 public JAXBDispatchMessage(BindingContext context, Object jaxbObject, SOAPVersion soapVersion) { 100 super(soapVersion); 101 this.bridge = context.createFragmentBridge(); 102 this.rawContext = null; 103 this.jaxbObject = jaxbObject; 104 } 105 106 @Override 107 protected void writePayloadTo(ContentHandler contentHandler, ErrorHandler errorHandler, boolean fragment) throws SAXException { 108 throw new UnsupportedOperationException(); 109 } 110 111 @Override 112 public boolean hasHeaders() { 113 return false; 114 } 115 116 @Override 117 public MessageHeaders getHeaders() { 118 return null; 119 } 120 121 @Override 122 public String getPayloadLocalPart() { 123 if (payloadQName == null) { 124 readPayloadElement(); 125 } 126 return payloadQName.getLocalPart(); 127 } 128 129 @Override 130 public String getPayloadNamespaceURI() { 131 if (payloadQName == null) { 132 readPayloadElement(); 133 } 134 return payloadQName.getNamespaceURI(); 135 } 136 137 private void readPayloadElement() { 138 PayloadElementSniffer sniffer = new PayloadElementSniffer(); 139 try { 140 if (rawContext != null) { 141 Marshaller m = rawContext.createMarshaller(); 142 m.setProperty("jaxb.fragment", Boolean.FALSE); 143 m.marshal(jaxbObject, sniffer); 144 } else { 145 bridge.marshal(jaxbObject, sniffer, null); 146 } 147 148 } catch (JAXBException e) { 149 // if it's due to us aborting the processing after the first element, 150 // we can safely ignore this exception. 151 // 152 // if it's due to error in the object, the same error will be reported 153 // when the readHeader() method is used, so we don't have to report 154 // an error right now. 155 payloadQName = sniffer.getPayloadQName(); 156 } 157 } 158 159 @Override 160 public boolean hasPayload() { 161 return true; 162 } 163 164 @Override 165 public Source readPayloadAsSource() { 166 throw new UnsupportedOperationException(); 167 } 168 169 @Override 170 public XMLStreamReader readPayload() throws XMLStreamException { 171 throw new UnsupportedOperationException(); 172 } 173 174 @Override 175 public void writePayloadTo(XMLStreamWriter sw) throws XMLStreamException { 176 throw new UnsupportedOperationException(); 177 } 178 179 @Override 180 public Message copy() { 181 return new JAXBDispatchMessage(this); 182 } 183 184 @Override 185 @SuppressWarnings("unchecked") 186 public void writeTo(XMLStreamWriter sw) throws XMLStreamException { 187 try { 188 // MtomCodec sets its own AttachmentMarshaller 189 AttachmentMarshaller am = (sw instanceof MtomStreamWriter) 190 ? ((MtomStreamWriter) sw).getAttachmentMarshaller() 191 : new AttachmentMarshallerImpl(attachmentSet); 192 193 // Get the encoding of the writer 194 String encoding = XMLStreamWriterUtil.getEncoding(sw); 195 196 // Get output stream and use JAXB UTF-8 writer 197 OutputStream os = bridge.supportOutputStream() ? XMLStreamWriterUtil.getOutputStream(sw) : null; 198 if (rawContext != null) { 199 Marshaller m = rawContext.createMarshaller(); 200 m.setProperty("jaxb.fragment", Boolean.FALSE); 201 m.setAttachmentMarshaller(am); 202 if (os != null) { 203 m.marshal(jaxbObject, os); 204 } else { 205 m.marshal(jaxbObject, sw); 206 } 207 208 } else { 209 210 if (os != null && encoding != null && encoding.equalsIgnoreCase(SOAPBindingCodec.UTF8_ENCODING)) { 211 bridge.marshal(jaxbObject, os, sw.getNamespaceContext(), am); 212 } else { 213 bridge.marshal(jaxbObject, sw, am); 214 } 215 } 216 //cleanup() is not needed since JAXB doesn't keep ref to AttachmentMarshaller 217 } catch (JAXBException e) { 218 // bug 6449684, spec 4.3.4 219 throw new WebServiceException(e); 220 } 221 } 222 }