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 26package com.sun.xml.internal.ws.message.jaxb; 27 28import com.sun.xml.internal.ws.api.SOAPVersion; 29import com.sun.xml.internal.ws.api.message.Message; 30import com.sun.xml.internal.ws.api.message.MessageHeaders; 31import com.sun.xml.internal.ws.encoding.SOAPBindingCodec; 32import com.sun.xml.internal.ws.message.AbstractMessageImpl; 33import com.sun.xml.internal.ws.message.PayloadElementSniffer; 34import com.sun.xml.internal.ws.spi.db.BindingContext; 35import com.sun.xml.internal.ws.spi.db.XMLBridge; 36import com.sun.xml.internal.org.jvnet.staxex.util.MtomStreamWriter; 37import com.sun.xml.internal.ws.streaming.XMLStreamWriterUtil; 38import org.xml.sax.ContentHandler; 39import org.xml.sax.ErrorHandler; 40import org.xml.sax.SAXException; 41 42import javax.xml.bind.JAXBContext; 43import javax.xml.bind.JAXBException; 44import javax.xml.bind.Marshaller; 45import javax.xml.bind.attachment.AttachmentMarshaller; 46import javax.xml.namespace.QName; 47import javax.xml.stream.XMLStreamException; 48import javax.xml.stream.XMLStreamReader; 49import javax.xml.stream.XMLStreamWriter; 50import javax.xml.transform.Source; 51import javax.xml.ws.WebServiceException; 52import 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 */ 62public 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 copyFrom(that); 91 } 92 93 public JAXBDispatchMessage(JAXBContext rawContext, Object jaxbObject, SOAPVersion soapVersion) { 94 super(soapVersion); 95 this.bridge = null; 96 this.rawContext = rawContext; 97 this.jaxbObject = jaxbObject; 98 } 99 100 public JAXBDispatchMessage(BindingContext context, Object jaxbObject, SOAPVersion soapVersion) { 101 super(soapVersion); 102 this.bridge = context.createFragmentBridge(); 103 this.rawContext = null; 104 this.jaxbObject = jaxbObject; 105 } 106 107 @Override 108 protected void writePayloadTo(ContentHandler contentHandler, ErrorHandler errorHandler, boolean fragment) throws SAXException { 109 throw new UnsupportedOperationException(); 110 } 111 112 @Override 113 public boolean hasHeaders() { 114 return false; 115 } 116 117 @Override 118 public MessageHeaders getHeaders() { 119 return null; 120 } 121 122 @Override 123 public String getPayloadLocalPart() { 124 if (payloadQName == null) { 125 readPayloadElement(); 126 } 127 return payloadQName.getLocalPart(); 128 } 129 130 @Override 131 public String getPayloadNamespaceURI() { 132 if (payloadQName == null) { 133 readPayloadElement(); 134 } 135 return payloadQName.getNamespaceURI(); 136 } 137 138 private void readPayloadElement() { 139 PayloadElementSniffer sniffer = new PayloadElementSniffer(); 140 try { 141 if (rawContext != null) { 142 Marshaller m = rawContext.createMarshaller(); 143 m.setProperty("jaxb.fragment", Boolean.FALSE); 144 m.marshal(jaxbObject, sniffer); 145 } else { 146 bridge.marshal(jaxbObject, sniffer, null); 147 } 148 149 } catch (JAXBException e) { 150 // if it's due to us aborting the processing after the first element, 151 // we can safely ignore this exception. 152 // 153 // if it's due to error in the object, the same error will be reported 154 // when the readHeader() method is used, so we don't have to report 155 // an error right now. 156 payloadQName = sniffer.getPayloadQName(); 157 } 158 } 159 160 @Override 161 public boolean hasPayload() { 162 return true; 163 } 164 165 @Override 166 public Source readPayloadAsSource() { 167 throw new UnsupportedOperationException(); 168 } 169 170 @Override 171 public XMLStreamReader readPayload() throws XMLStreamException { 172 throw new UnsupportedOperationException(); 173 } 174 175 @Override 176 public void writePayloadTo(XMLStreamWriter sw) throws XMLStreamException { 177 throw new UnsupportedOperationException(); 178 } 179 180 @Override 181 public Message copy() { 182 return new JAXBDispatchMessage(this).copyFrom(this); 183 } 184 185 @Override 186 @SuppressWarnings("unchecked") 187 public void writeTo(XMLStreamWriter sw) throws XMLStreamException { 188 try { 189 // MtomCodec sets its own AttachmentMarshaller 190 AttachmentMarshaller am = (sw instanceof MtomStreamWriter) 191 ? ((MtomStreamWriter) sw).getAttachmentMarshaller() 192 : new AttachmentMarshallerImpl(attachmentSet); 193 194 // Get the encoding of the writer 195 String encoding = XMLStreamWriterUtil.getEncoding(sw); 196 197 // Get output stream and use JAXB UTF-8 writer 198 OutputStream os = bridge.supportOutputStream() ? XMLStreamWriterUtil.getOutputStream(sw) : null; 199 if (rawContext != null) { 200 Marshaller m = rawContext.createMarshaller(); 201 m.setProperty("jaxb.fragment", Boolean.FALSE); 202 m.setAttachmentMarshaller(am); 203 if (os != null) { 204 m.marshal(jaxbObject, os); 205 } else { 206 m.marshal(jaxbObject, sw); 207 } 208 209 } else { 210 211 if (os != null && encoding != null && encoding.equalsIgnoreCase(SOAPBindingCodec.UTF8_ENCODING)) { 212 bridge.marshal(jaxbObject, os, sw.getNamespaceContext(), am); 213 } else { 214 bridge.marshal(jaxbObject, sw, am); 215 } 216 } 217 //cleanup() is not needed since JAXB doesn't keep ref to AttachmentMarshaller 218 } catch (JAXBException e) { 219 // bug 6449684, spec 4.3.4 220 throw new WebServiceException(e); 221 } 222 } 223} 224