Wed, 12 Jun 2013 14:47:09 +0100
8013021: Rebase 8005432 & 8003542 against the latest jdk8/jaxws
8003542: Improve processing of MTOM attachments
8005432: Update access to JAX-WS
Reviewed-by: mullan
ohair@286 | 1 | /* |
alanb@368 | 2 | * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. |
ohair@286 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
ohair@286 | 4 | * |
ohair@286 | 5 | * This code is free software; you can redistribute it and/or modify it |
ohair@286 | 6 | * under the terms of the GNU General Public License version 2 only, as |
ohair@286 | 7 | * published by the Free Software Foundation. Oracle designates this |
ohair@286 | 8 | * particular file as subject to the "Classpath" exception as provided |
ohair@286 | 9 | * by Oracle in the LICENSE file that accompanied this code. |
ohair@286 | 10 | * |
ohair@286 | 11 | * This code is distributed in the hope that it will be useful, but WITHOUT |
ohair@286 | 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
ohair@286 | 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
ohair@286 | 14 | * version 2 for more details (a copy is included in the LICENSE file that |
ohair@286 | 15 | * accompanied this code). |
ohair@286 | 16 | * |
ohair@286 | 17 | * You should have received a copy of the GNU General Public License version |
ohair@286 | 18 | * 2 along with this work; if not, write to the Free Software Foundation, |
ohair@286 | 19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
ohair@286 | 20 | * |
ohair@286 | 21 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
ohair@286 | 22 | * or visit www.oracle.com if you need additional information or have any |
ohair@286 | 23 | * questions. |
ohair@286 | 24 | */ |
ohair@286 | 25 | |
ohair@286 | 26 | package com.sun.xml.internal.ws.api.message; |
ohair@286 | 27 | |
alanb@368 | 28 | import com.oracle.webservices.internal.api.message.ContentType; |
alanb@368 | 29 | import com.oracle.webservices.internal.api.message.PropertySet; |
ohair@286 | 30 | import com.sun.istack.internal.NotNull; |
ohair@286 | 31 | import com.sun.istack.internal.Nullable; |
ohair@286 | 32 | import com.sun.xml.internal.bind.marshaller.SAX2DOMEx; |
ohair@286 | 33 | import com.sun.xml.internal.ws.addressing.WsaPropertyBag; |
alanb@368 | 34 | import com.sun.xml.internal.ws.addressing.WsaServerTube; |
ohair@286 | 35 | import com.sun.xml.internal.ws.addressing.WsaTubeHelper; |
alanb@368 | 36 | import com.sun.xml.internal.ws.api.Component; |
alanb@368 | 37 | import com.sun.xml.internal.ws.api.EndpointAddress; |
alanb@368 | 38 | import com.sun.xml.internal.ws.api.SOAPVersion; |
alanb@368 | 39 | import com.sun.xml.internal.ws.api.WSBinding; |
ohair@286 | 40 | import com.sun.xml.internal.ws.api.addressing.AddressingVersion; |
ohair@286 | 41 | import com.sun.xml.internal.ws.api.addressing.WSEndpointReference; |
ohair@286 | 42 | import com.sun.xml.internal.ws.api.model.JavaMethod; |
ohair@286 | 43 | import com.sun.xml.internal.ws.api.model.SEIModel; |
alanb@368 | 44 | import com.sun.xml.internal.ws.api.model.WSDLOperationMapping; |
ohair@286 | 45 | import com.sun.xml.internal.ws.api.model.wsdl.WSDLOperation; |
ohair@286 | 46 | import com.sun.xml.internal.ws.api.model.wsdl.WSDLPort; |
ohair@286 | 47 | import com.sun.xml.internal.ws.api.pipe.Codec; |
ohair@286 | 48 | import com.sun.xml.internal.ws.api.pipe.Tube; |
ohair@286 | 49 | import com.sun.xml.internal.ws.api.server.Adapter; |
ohair@286 | 50 | import com.sun.xml.internal.ws.api.server.TransportBackChannel; |
ohair@286 | 51 | import com.sun.xml.internal.ws.api.server.WSEndpoint; |
ohair@286 | 52 | import com.sun.xml.internal.ws.api.server.WebServiceContextDelegate; |
ohair@286 | 53 | import com.sun.xml.internal.ws.api.streaming.XMLStreamWriterFactory; |
ohair@286 | 54 | import com.sun.xml.internal.ws.client.*; |
ohair@286 | 55 | import com.sun.xml.internal.ws.developer.JAXWSProperties; |
alanb@368 | 56 | import com.sun.xml.internal.ws.encoding.MtomCodec; |
ohair@286 | 57 | import com.sun.xml.internal.ws.message.RelatesToHeader; |
ohair@286 | 58 | import com.sun.xml.internal.ws.message.StringHeader; |
ohair@286 | 59 | import com.sun.xml.internal.ws.util.DOMUtil; |
ohair@286 | 60 | import com.sun.xml.internal.ws.util.xml.XmlUtil; |
ohair@286 | 61 | import com.sun.xml.internal.ws.wsdl.DispatchException; |
ohair@286 | 62 | import com.sun.xml.internal.ws.wsdl.OperationDispatcher; |
alanb@368 | 63 | import com.sun.xml.internal.ws.resources.AddressingMessages; |
ohair@286 | 64 | |
alanb@368 | 65 | |
ohair@286 | 66 | import org.w3c.dom.Document; |
ohair@286 | 67 | import org.w3c.dom.Element; |
ohair@286 | 68 | import org.xml.sax.SAXException; |
ohair@286 | 69 | |
ohair@286 | 70 | import javax.xml.namespace.QName; |
ohair@286 | 71 | import javax.xml.soap.SOAPException; |
ohair@286 | 72 | import javax.xml.soap.SOAPMessage; |
ohair@286 | 73 | import javax.xml.stream.XMLStreamWriter; |
alanb@368 | 74 | import javax.xml.stream.XMLStreamException; |
ohair@286 | 75 | import javax.xml.ws.BindingProvider; |
ohair@286 | 76 | import javax.xml.ws.Dispatch; |
ohair@286 | 77 | import javax.xml.ws.WebServiceContext; |
ohair@286 | 78 | import javax.xml.ws.WebServiceException; |
ohair@286 | 79 | import javax.xml.ws.handler.LogicalMessageContext; |
ohair@286 | 80 | import javax.xml.ws.handler.MessageContext; |
ohair@286 | 81 | import javax.xml.ws.handler.soap.SOAPMessageContext; |
alanb@368 | 82 | import javax.xml.ws.soap.MTOMFeature; |
alanb@368 | 83 | |
ohair@286 | 84 | import java.util.*; |
ohair@286 | 85 | import java.util.logging.Logger; |
ohair@286 | 86 | import java.io.ByteArrayOutputStream; |
ohair@286 | 87 | import java.io.IOException; |
ohair@286 | 88 | import java.io.OutputStream; |
ohair@286 | 89 | import java.nio.channels.WritableByteChannel; |
ohair@286 | 90 | |
ohair@286 | 91 | /** |
ohair@286 | 92 | * Represents a container of a {@link Message}. |
ohair@286 | 93 | * |
ohair@286 | 94 | * <h2>What is a {@link Packet}?</h2> |
ohair@286 | 95 | * <p> |
ohair@286 | 96 | * A packet can be thought of as a frame/envelope/package that wraps |
ohair@286 | 97 | * a {@link Message}. A packet keeps track of optional metadata (properties) |
ohair@286 | 98 | * about a {@link Message} that doesn't go across the wire. |
ohair@286 | 99 | * This roughly corresponds to {@link MessageContext} in the JAX-WS API. |
ohair@286 | 100 | * |
ohair@286 | 101 | * <p> |
ohair@286 | 102 | * Usually a packet contains a {@link Message} in it, but sometimes |
ohair@286 | 103 | * (such as for a reply of an one-way operation), a packet may |
ohair@286 | 104 | * float around without a {@link Message} in it. |
ohair@286 | 105 | * |
ohair@286 | 106 | * |
ohair@286 | 107 | * <a name="properties"></a> |
ohair@286 | 108 | * <h2>Properties</h2> |
ohair@286 | 109 | * <p> |
ohair@286 | 110 | * Information frequently used inside the JAX-WS RI |
ohair@286 | 111 | * is stored in the strongly-typed fields. Other information is stored |
ohair@286 | 112 | * in terms of a generic {@link Map} (see |
ohair@286 | 113 | * {@link #invocationProperties}.) |
ohair@286 | 114 | * |
ohair@286 | 115 | * <p> |
ohair@286 | 116 | * Some properties need to be retained between request and response, |
ohair@286 | 117 | * some don't. For strongly typed fields, this characteristic is |
ohair@286 | 118 | * statically known for each of them, and propagation happens accordingly. |
ohair@286 | 119 | * For generic information stored in {@link Map}, {@link #invocationProperties} |
ohair@286 | 120 | * stores per-invocation scope information (which carries over to |
ohair@286 | 121 | * the response.) |
ohair@286 | 122 | * |
ohair@286 | 123 | * <p> |
ohair@286 | 124 | * This object is used as the backing store of {@link MessageContext}, and |
ohair@286 | 125 | * {@link LogicalMessageContext} and {@link SOAPMessageContext} will |
ohair@286 | 126 | * be delegating to this object for storing/retrieving values. |
ohair@286 | 127 | * |
ohair@286 | 128 | * |
ohair@286 | 129 | * <h3>Relationship to request/response context</h3> |
ohair@286 | 130 | * <p> |
ohair@286 | 131 | * {@link BindingProvider#getRequestContext() Request context} is used to |
ohair@286 | 132 | * seed the initial values of {@link Packet}. |
ohair@286 | 133 | * Some of those values go to strongly-typed fields, and others go to |
ohair@286 | 134 | * {@link #invocationProperties}, as they need to be retained in the reply message. |
ohair@286 | 135 | * |
ohair@286 | 136 | * <p> |
ohair@286 | 137 | * Similarly, {@link BindingProvider#getResponseContext() response context} |
ohair@286 | 138 | * is constructed from {@link Packet} (or rather it's just a view of {@link Packet}.) |
ohair@286 | 139 | * by using properties from {@link #invocationProperties}, |
ohair@286 | 140 | * modulo properties named explicitly in {@link #getHandlerScopePropertyNames(boolean)}. |
ohair@286 | 141 | * IOW, properties added to {@link #invocationProperties} |
ohair@286 | 142 | * are exposed to the response context by default. |
ohair@286 | 143 | * |
ohair@286 | 144 | * |
ohair@286 | 145 | * |
ohair@286 | 146 | * <h3>TODO</h3> |
ohair@286 | 147 | * <ol> |
ohair@286 | 148 | * <li>this class needs to be cloneable since Message is copiable. |
ohair@286 | 149 | * <li>The three live views aren't implemented correctly. It will be |
ohair@286 | 150 | * more work to do so, although I'm sure it's possible. |
alanb@368 | 151 | * <li>{@link PropertySet.Property} annotation is to make it easy |
ohair@286 | 152 | * for {@link MessageContext} to export properties on this object, |
ohair@286 | 153 | * but it probably needs some clean up. |
ohair@286 | 154 | * </ol> |
ohair@286 | 155 | * |
ohair@286 | 156 | * @author Kohsuke Kawaguchi |
ohair@286 | 157 | */ |
ohair@286 | 158 | public final class Packet |
alanb@368 | 159 | // Packet must continue to extend/implement deprecated interfaces until downstream |
alanb@368 | 160 | // usage is updated. |
alanb@368 | 161 | extends com.oracle.webservices.internal.api.message.BaseDistributedPropertySet |
alanb@368 | 162 | implements com.oracle.webservices.internal.api.message.MessageContext, MessageMetadata { |
ohair@286 | 163 | |
ohair@286 | 164 | /** |
ohair@286 | 165 | * Creates a {@link Packet} that wraps a given {@link Message}. |
ohair@286 | 166 | * |
ohair@286 | 167 | * <p> |
ohair@286 | 168 | * This method should be only used to create a fresh {@link Packet}. |
ohair@286 | 169 | * To create a {@link Packet} for a reply, use {@link #createResponse(Message)}. |
ohair@286 | 170 | * |
ohair@286 | 171 | * @param request |
ohair@286 | 172 | * The request {@link Message}. Can be null. |
ohair@286 | 173 | */ |
ohair@286 | 174 | public Packet(Message request) { |
ohair@286 | 175 | this(); |
ohair@286 | 176 | this.message = request; |
alanb@368 | 177 | if (message != null) message.setMessageMedadata(this); |
ohair@286 | 178 | } |
ohair@286 | 179 | |
ohair@286 | 180 | /** |
ohair@286 | 181 | * Creates an empty {@link Packet} that doesn't have any {@link Message}. |
ohair@286 | 182 | */ |
ohair@286 | 183 | public Packet() { |
ohair@286 | 184 | this.invocationProperties = new HashMap<String, Object>(); |
ohair@286 | 185 | } |
ohair@286 | 186 | |
ohair@286 | 187 | /** |
ohair@286 | 188 | * Used by {@link #createResponse(Message)} and {@link #copy(boolean)}. |
ohair@286 | 189 | */ |
ohair@286 | 190 | private Packet(Packet that) { |
alanb@368 | 191 | relatePackets(that, true); |
ohair@286 | 192 | this.invocationProperties = that.invocationProperties; |
ohair@286 | 193 | } |
ohair@286 | 194 | |
ohair@286 | 195 | /** |
ohair@286 | 196 | * Creates a copy of this {@link Packet}. |
ohair@286 | 197 | * |
ohair@286 | 198 | * @param copyMessage determines whether the {@link Message} from the original {@link Packet} should be copied as |
ohair@286 | 199 | * well, or not. If the value is {@code false}, the {@link Message} in the copy of the {@link Packet} is {@code null}. |
ohair@286 | 200 | * @return copy of the original packet |
ohair@286 | 201 | */ |
ohair@286 | 202 | public Packet copy(boolean copyMessage) { |
ohair@286 | 203 | // the copy constructor is originally designed for creating a response packet, |
ohair@286 | 204 | // but so far the implementation is usable for this purpose as well, so calling the copy constructor |
ohair@286 | 205 | // to avoid code dupliation. |
ohair@286 | 206 | Packet copy = new Packet(this); |
ohair@286 | 207 | if (copyMessage && this.message != null) { |
ohair@286 | 208 | copy.message = this.message.copy(); |
ohair@286 | 209 | } |
alanb@368 | 210 | if (copy.message != null) copy.message.setMessageMedadata(copy); |
ohair@286 | 211 | return copy; |
ohair@286 | 212 | } |
ohair@286 | 213 | |
ohair@286 | 214 | private Message message; |
ohair@286 | 215 | |
ohair@286 | 216 | /** |
ohair@286 | 217 | * Gets the last {@link Message} set through {@link #setMessage(Message)}. |
ohair@286 | 218 | * |
ohair@286 | 219 | * @return may null. See the class javadoc for when it's null. |
ohair@286 | 220 | */ |
ohair@286 | 221 | public Message getMessage() { |
alanb@368 | 222 | if (message != null && !(message instanceof MessageWrapper)) { |
alanb@368 | 223 | message = new MessageWrapper(this, message); |
alanb@368 | 224 | } |
alanb@368 | 225 | return message; |
alanb@368 | 226 | } |
alanb@368 | 227 | |
alanb@368 | 228 | public Message getInternalMessage() { |
alanb@368 | 229 | return (message instanceof MessageWrapper)? ((MessageWrapper)message).delegate : message; |
ohair@286 | 230 | } |
ohair@286 | 231 | |
ohair@286 | 232 | public WSBinding getBinding() { |
alanb@368 | 233 | if (endpoint != null) { |
alanb@368 | 234 | return endpoint.getBinding(); |
alanb@368 | 235 | } |
alanb@368 | 236 | if (proxy != null) { |
alanb@368 | 237 | return (WSBinding) proxy.getBinding(); |
alanb@368 | 238 | } |
ohair@286 | 239 | return null; |
ohair@286 | 240 | } |
ohair@286 | 241 | /** |
ohair@286 | 242 | * Sets a {@link Message} to this packet. |
ohair@286 | 243 | * |
ohair@286 | 244 | * @param message Can be null. |
ohair@286 | 245 | */ |
ohair@286 | 246 | public void setMessage(Message message) { |
ohair@286 | 247 | this.message = message; |
alanb@368 | 248 | if (message != null) this.message.setMessageMedadata(this); |
ohair@286 | 249 | } |
ohair@286 | 250 | |
alanb@368 | 251 | private WSDLOperationMapping wsdlOperationMapping = null; |
alanb@368 | 252 | |
ohair@286 | 253 | private QName wsdlOperation; |
ohair@286 | 254 | |
ohair@286 | 255 | /** |
ohair@286 | 256 | * Returns the QName of the wsdl operation associated with this packet. |
ohair@286 | 257 | * <p/> |
ohair@286 | 258 | * Information such as Payload QName, wsa:Action header, SOAPAction HTTP header are used depending on the features |
ohair@286 | 259 | * enabled on the particular port. |
ohair@286 | 260 | * |
ohair@286 | 261 | * @return null if there is no WSDL model or |
ohair@286 | 262 | * runtime cannot uniquely identify the wsdl operation from the information in the packet. |
ohair@286 | 263 | */ |
alanb@368 | 264 | @Property(MessageContext.WSDL_OPERATION) |
ohair@286 | 265 | public final |
ohair@286 | 266 | @Nullable |
ohair@286 | 267 | QName getWSDLOperation() { |
alanb@368 | 268 | if (wsdlOperation != null) return wsdlOperation; |
alanb@368 | 269 | if ( wsdlOperationMapping == null) wsdlOperationMapping = getWSDLOperationMapping(); |
alanb@368 | 270 | if ( wsdlOperationMapping != null ) wsdlOperation = wsdlOperationMapping.getOperationName(); |
alanb@368 | 271 | return wsdlOperation; |
alanb@368 | 272 | } |
ohair@286 | 273 | |
alanb@368 | 274 | public WSDLOperationMapping getWSDLOperationMapping() { |
alanb@368 | 275 | if (wsdlOperationMapping != null) return wsdlOperationMapping; |
ohair@286 | 276 | OperationDispatcher opDispatcher = null; |
ohair@286 | 277 | if (endpoint != null) { |
alanb@368 | 278 | opDispatcher = endpoint.getOperationDispatcher(); |
ohair@286 | 279 | } else if (proxy != null) { |
ohair@286 | 280 | opDispatcher = ((Stub) proxy).getOperationDispatcher(); |
ohair@286 | 281 | } |
ohair@286 | 282 | //OpDispatcher is null when there is no WSDLModel |
ohair@286 | 283 | if (opDispatcher != null) { |
ohair@286 | 284 | try { |
alanb@368 | 285 | wsdlOperationMapping = opDispatcher.getWSDLOperationMapping(this); |
ohair@286 | 286 | } catch (DispatchException e) { |
ohair@286 | 287 | //Ignore, this might be a protocol message which may not have a wsdl operation |
ohair@286 | 288 | //LOGGER.info("Cannot resolve wsdl operation that this Packet is targeted for."); |
ohair@286 | 289 | } |
ohair@286 | 290 | } |
alanb@368 | 291 | return wsdlOperationMapping; |
ohair@286 | 292 | } |
ohair@286 | 293 | |
ohair@286 | 294 | /** |
ohair@286 | 295 | * Set the wsdl operation to avoid lookup from other data. |
ohair@286 | 296 | * This is useful in SEI based clients, where the WSDL operation can be known |
ohair@286 | 297 | * from the associated {@link JavaMethod} |
ohair@286 | 298 | * |
ohair@286 | 299 | * @param wsdlOp QName |
ohair@286 | 300 | */ |
ohair@286 | 301 | public void setWSDLOperation(QName wsdlOp) { |
ohair@286 | 302 | this.wsdlOperation = wsdlOp; |
ohair@286 | 303 | } |
ohair@286 | 304 | |
ohair@286 | 305 | /** |
ohair@286 | 306 | * True if this message came from a transport (IOW inbound), |
ohair@286 | 307 | * and in paricular from a "secure" transport. A transport |
ohair@286 | 308 | * needs to set this flag appropriately. |
ohair@286 | 309 | * |
ohair@286 | 310 | * <p> |
ohair@286 | 311 | * This is a requirement from the security team. |
ohair@286 | 312 | */ |
ohair@286 | 313 | // TODO: expose this as a property |
ohair@286 | 314 | public boolean wasTransportSecure; |
ohair@286 | 315 | |
ohair@286 | 316 | /** |
ohair@286 | 317 | * Inbound transport headers are captured in a transport neutral way. |
ohair@286 | 318 | * Transports are expected to fill this data after creating a Packet. |
ohair@286 | 319 | * <p> |
ohair@286 | 320 | * {@link SOAPMessage#getMimeHeaders()} would return these headers. |
ohair@286 | 321 | */ |
ohair@286 | 322 | public static final String INBOUND_TRANSPORT_HEADERS = "com.sun.xml.internal.ws.api.message.packet.inbound.transport.headers"; |
ohair@286 | 323 | |
ohair@286 | 324 | /** |
ohair@286 | 325 | * Outbound transport headers are captured in a transport neutral way. |
ohair@286 | 326 | * |
ohair@286 | 327 | * <p> |
ohair@286 | 328 | * Transports may choose to ignore certain headers that interfere with |
ohair@286 | 329 | * its correct operation, such as |
ohair@286 | 330 | * <tt>Content-Type</tt> and <tt>Content-Length</tt>. |
ohair@286 | 331 | */ |
ohair@286 | 332 | public static final String OUTBOUND_TRANSPORT_HEADERS = "com.sun.xml.internal.ws.api.message.packet.outbound.transport.headers"; |
ohair@286 | 333 | |
ohair@286 | 334 | /** |
ohair@286 | 335 | * |
ohair@286 | 336 | */ |
ohair@286 | 337 | public static final String HA_INFO = "com.sun.xml.internal.ws.api.message.packet.hainfo"; |
ohair@286 | 338 | |
ohair@286 | 339 | |
ohair@286 | 340 | /** |
ohair@286 | 341 | * This property holds the snapshot of HandlerConfiguration |
ohair@286 | 342 | * at the time of invocation. |
ohair@286 | 343 | * This property is used by MUPipe and HandlerPipe implementations. |
ohair@286 | 344 | */ |
alanb@368 | 345 | @Property(BindingProviderProperties.JAXWS_HANDLER_CONFIG) |
ohair@286 | 346 | public HandlerConfiguration handlerConfig; |
ohair@286 | 347 | |
ohair@286 | 348 | /** |
ohair@286 | 349 | * If a message originates from a proxy stub that implements |
ohair@286 | 350 | * a port interface, this field is set to point to that object. |
ohair@286 | 351 | * |
ohair@286 | 352 | * TODO: who's using this property? |
ohair@286 | 353 | */ |
alanb@368 | 354 | @Property(BindingProviderProperties.JAXWS_CLIENT_HANDLE_PROPERTY) |
ohair@286 | 355 | public BindingProvider proxy; |
ohair@286 | 356 | |
ohair@286 | 357 | /** |
alanb@368 | 358 | * Determines if the governing {@link Adapter} or {@link com.sun.xml.internal.ws.api.pipe.Fiber.CompletionCallback} |
alanb@368 | 359 | * will handle delivering response messages targeted at non-anonymous endpoint |
alanb@368 | 360 | * addresses. Prior to the introduction of this flag |
alanb@368 | 361 | * the {@link WsaServerTube} would deliver non-anonymous responses. |
ohair@286 | 362 | */ |
ohair@286 | 363 | public boolean isAdapterDeliversNonAnonymousResponse; |
ohair@286 | 364 | |
ohair@286 | 365 | /** |
alanb@368 | 366 | * During invocation of a client Stub or Dispatch a Packet is |
alanb@368 | 367 | * created then the Stub's RequestContext is copied into the |
alanb@368 | 368 | * Packet. On certain internal cases the Packet is created |
alanb@368 | 369 | * *before* the invocation. In those cases we want the contents |
alanb@368 | 370 | * of the Packet to take precedence when ever any key/value pairs |
alanb@368 | 371 | * collide : if the Packet contains a value for a key use it, |
alanb@368 | 372 | * otherwise copy as usual from Stub. |
alanb@368 | 373 | */ |
alanb@368 | 374 | public boolean packetTakesPriorityOverRequestContext = false; |
alanb@368 | 375 | |
alanb@368 | 376 | /** |
ohair@286 | 377 | * The endpoint address to which this message is sent to. |
ohair@286 | 378 | * |
ohair@286 | 379 | * <p> |
ohair@286 | 380 | * The JAX-WS spec allows this to be changed for each message, |
ohair@286 | 381 | * so it's designed to be a property. |
ohair@286 | 382 | * |
ohair@286 | 383 | * <p> |
ohair@286 | 384 | * Must not be null for a request message on the client. Otherwise |
ohair@286 | 385 | * it's null. |
ohair@286 | 386 | */ |
ohair@286 | 387 | public EndpointAddress endpointAddress; |
ohair@286 | 388 | |
ohair@286 | 389 | /** |
ohair@286 | 390 | * @deprecated |
ohair@286 | 391 | * The programatic acccess should be done via |
ohair@286 | 392 | * {@link #endpointAddress}. This is for JAX-WS client applications |
ohair@286 | 393 | * that access this property via {@link BindingProvider#ENDPOINT_ADDRESS_PROPERTY}. |
ohair@286 | 394 | */ |
alanb@368 | 395 | @Property(BindingProvider.ENDPOINT_ADDRESS_PROPERTY) |
ohair@286 | 396 | public String getEndPointAddressString() { |
alanb@368 | 397 | if (endpointAddress == null) { |
ohair@286 | 398 | return null; |
alanb@368 | 399 | } else { |
ohair@286 | 400 | return endpointAddress.toString(); |
alanb@368 | 401 | } |
ohair@286 | 402 | } |
ohair@286 | 403 | |
ohair@286 | 404 | public void setEndPointAddressString(String s) { |
alanb@368 | 405 | if (s == null) { |
ohair@286 | 406 | this.endpointAddress = null; |
alanb@368 | 407 | } else { |
ohair@286 | 408 | this.endpointAddress = EndpointAddress.create(s); |
alanb@368 | 409 | } |
ohair@286 | 410 | } |
ohair@286 | 411 | |
ohair@286 | 412 | /** |
ohair@286 | 413 | * The value of {@link ContentNegotiation#PROPERTY} |
ohair@286 | 414 | * property. |
ohair@286 | 415 | * <p/> |
ohair@286 | 416 | * This property is used only on the client side. |
ohair@286 | 417 | */ |
ohair@286 | 418 | public ContentNegotiation contentNegotiation; |
ohair@286 | 419 | |
alanb@368 | 420 | @Property(ContentNegotiation.PROPERTY) |
ohair@286 | 421 | public String getContentNegotiationString() { |
ohair@286 | 422 | return (contentNegotiation != null) ? contentNegotiation.toString() : null; |
ohair@286 | 423 | } |
ohair@286 | 424 | |
ohair@286 | 425 | public void setContentNegotiationString(String s) { |
alanb@368 | 426 | if (s == null) { |
ohair@286 | 427 | contentNegotiation = null; |
alanb@368 | 428 | } else { |
ohair@286 | 429 | try { |
ohair@286 | 430 | contentNegotiation = ContentNegotiation.valueOf(s); |
ohair@286 | 431 | } catch (IllegalArgumentException e) { |
ohair@286 | 432 | // If the value is not recognized default to none |
ohair@286 | 433 | contentNegotiation = ContentNegotiation.none; |
ohair@286 | 434 | } |
ohair@286 | 435 | } |
ohair@286 | 436 | } |
ohair@286 | 437 | |
ohair@286 | 438 | /** |
ohair@286 | 439 | * Gives a list of Reference Parameters in the Message |
ohair@286 | 440 | * <p> |
ohair@286 | 441 | * Headers which have attribute wsa:IsReferenceParameter="true" |
ohair@286 | 442 | * This is not cached as one may reset the Message. |
ohair@286 | 443 | *<p> |
ohair@286 | 444 | */ |
alanb@368 | 445 | @Property(MessageContext.REFERENCE_PARAMETERS) |
ohair@286 | 446 | public |
ohair@286 | 447 | @NotNull |
ohair@286 | 448 | List<Element> getReferenceParameters() { |
alanb@368 | 449 | Message msg = getMessage(); |
ohair@286 | 450 | List<Element> refParams = new ArrayList<Element>(); |
alanb@368 | 451 | if (msg == null) { |
ohair@286 | 452 | return refParams; |
ohair@286 | 453 | } |
alanb@368 | 454 | MessageHeaders hl = msg.getHeaders(); |
alanb@368 | 455 | for (Header h : hl.asList()) { |
ohair@286 | 456 | String attr = h.getAttribute(AddressingVersion.W3C.nsUri, "IsReferenceParameter"); |
ohair@286 | 457 | if (attr != null && (attr.equals("true") || attr.equals("1"))) { |
ohair@286 | 458 | Document d = DOMUtil.createDom(); |
ohair@286 | 459 | SAX2DOMEx s2d = new SAX2DOMEx(d); |
ohair@286 | 460 | try { |
ohair@286 | 461 | h.writeTo(s2d, XmlUtil.DRACONIAN_ERROR_HANDLER); |
ohair@286 | 462 | refParams.add((Element) d.getLastChild()); |
ohair@286 | 463 | } catch (SAXException e) { |
ohair@286 | 464 | throw new WebServiceException(e); |
ohair@286 | 465 | } |
ohair@286 | 466 | /* |
ohair@286 | 467 | DOMResult result = new DOMResult(d); |
ohair@286 | 468 | XMLDOMWriterImpl domwriter = new XMLDOMWriterImpl(result); |
ohair@286 | 469 | try { |
ohair@286 | 470 | h.writeTo(domwriter); |
ohair@286 | 471 | refParams.add((Element) result.getNode().getLastChild()); |
ohair@286 | 472 | } catch (XMLStreamException e) { |
ohair@286 | 473 | throw new WebServiceException(e); |
ohair@286 | 474 | } |
ohair@286 | 475 | */ |
ohair@286 | 476 | } |
ohair@286 | 477 | } |
ohair@286 | 478 | return refParams; |
ohair@286 | 479 | } |
ohair@286 | 480 | |
ohair@286 | 481 | /** |
ohair@286 | 482 | * This method is for exposing header list through {@link PropertySet#get(Object)}, |
ohair@286 | 483 | * for user applications, and should never be invoked directly from within the JAX-WS RI. |
ohair@286 | 484 | */ |
alanb@368 | 485 | @Property(JAXWSProperties.INBOUND_HEADER_LIST_PROPERTY) |
alanb@368 | 486 | /*package*/ MessageHeaders getHeaderList() { |
alanb@368 | 487 | Message msg = getMessage(); |
alanb@368 | 488 | if (msg == null) { |
alanb@368 | 489 | return null; |
alanb@368 | 490 | } |
alanb@368 | 491 | return msg.getHeaders(); |
ohair@286 | 492 | } |
ohair@286 | 493 | |
ohair@286 | 494 | /** |
ohair@286 | 495 | * The list of MIME types that are acceptable to a receiver |
ohair@286 | 496 | * of an outbound message. |
ohair@286 | 497 | * |
ohair@286 | 498 | * This property is used only on the server side. |
ohair@286 | 499 | * |
ohair@286 | 500 | * <p>The representation shall be that specified by the HTTP Accept |
ohair@286 | 501 | * request-header field. |
ohair@286 | 502 | * |
ohair@286 | 503 | * <p>The list of content types will be obtained from the transport |
ohair@286 | 504 | * meta-data of a inbound message in a request/response message exchange. |
ohair@286 | 505 | * Hence this property will be set by the service-side transport pipe. |
ohair@286 | 506 | */ |
ohair@286 | 507 | public String acceptableMimeTypes; |
ohair@286 | 508 | |
ohair@286 | 509 | /** |
ohair@286 | 510 | * When non-null, this object is consulted to |
ohair@286 | 511 | * implement {@link WebServiceContext} methods |
ohair@286 | 512 | * exposed to the user application. |
ohair@286 | 513 | * |
ohair@286 | 514 | * Used only on the server side. |
ohair@286 | 515 | * |
ohair@286 | 516 | * <p> |
ohair@286 | 517 | * This property is set from the parameter |
ohair@286 | 518 | * of {@link WSEndpoint.PipeHead#process}. |
ohair@286 | 519 | */ |
ohair@286 | 520 | public WebServiceContextDelegate webServiceContextDelegate; |
ohair@286 | 521 | |
ohair@286 | 522 | /** |
ohair@286 | 523 | * Used only on the server side so that the transport |
ohair@286 | 524 | * can close the connection early. |
ohair@286 | 525 | * |
ohair@286 | 526 | * <p> |
ohair@286 | 527 | * This field can be null. While a message is being processed, |
ohair@286 | 528 | * this field can be set explicitly to null, to prevent |
ohair@286 | 529 | * future pipes from closing a transport (see {@link #keepTransportBackChannelOpen()}) |
ohair@286 | 530 | * |
ohair@286 | 531 | * <p> |
ohair@286 | 532 | * This property is set from the parameter |
ohair@286 | 533 | * of {@link WSEndpoint.PipeHead#process}. |
ohair@286 | 534 | */ |
ohair@286 | 535 | public |
ohair@286 | 536 | @Nullable |
ohair@286 | 537 | TransportBackChannel transportBackChannel; |
ohair@286 | 538 | |
ohair@286 | 539 | /** |
ohair@286 | 540 | * Keeps the transport back channel open (by seeting {@link #transportBackChannel} to null.) |
ohair@286 | 541 | * |
ohair@286 | 542 | * @return |
ohair@286 | 543 | * The previous value of {@link #transportBackChannel}. |
ohair@286 | 544 | */ |
ohair@286 | 545 | public TransportBackChannel keepTransportBackChannelOpen() { |
ohair@286 | 546 | TransportBackChannel r = transportBackChannel; |
ohair@286 | 547 | transportBackChannel = null; |
ohair@286 | 548 | return r; |
ohair@286 | 549 | } |
ohair@286 | 550 | |
ohair@286 | 551 | /** |
ohair@286 | 552 | * The governing owner of this packet. On the service-side this is the {@link Adapter} and on the client it is the {@link Stub}. |
ohair@286 | 553 | * |
ohair@286 | 554 | */ |
ohair@286 | 555 | public Component component; |
ohair@286 | 556 | |
ohair@286 | 557 | /** |
ohair@286 | 558 | * The governing {@link WSEndpoint} in which this message is floating. |
ohair@286 | 559 | * |
ohair@286 | 560 | * <p> |
ohair@286 | 561 | * This property is set if and only if this is on the server side. |
ohair@286 | 562 | */ |
alanb@368 | 563 | @Property(JAXWSProperties.WSENDPOINT) |
ohair@286 | 564 | public WSEndpoint endpoint; |
ohair@286 | 565 | |
ohair@286 | 566 | /** |
ohair@286 | 567 | * The value of the SOAPAction header associated with the message. |
ohair@286 | 568 | * |
ohair@286 | 569 | * <p> |
ohair@286 | 570 | * For outgoing messages, the transport may sends out this value. |
ohair@286 | 571 | * If this field is null, the transport may choose to send <tt>""</tt> |
ohair@286 | 572 | * (quoted empty string.) |
ohair@286 | 573 | * |
ohair@286 | 574 | * For incoming messages, the transport will set this field. |
ohair@286 | 575 | * If the incoming message did not contain the SOAPAction header, |
ohair@286 | 576 | * the transport sets this field to null. |
ohair@286 | 577 | * |
ohair@286 | 578 | * <p> |
ohair@286 | 579 | * If the value is non-null, it must be always in the quoted form. |
ohair@286 | 580 | * The value can be null. |
ohair@286 | 581 | * |
ohair@286 | 582 | * <p> |
ohair@286 | 583 | * Note that the way the transport sends this value out depends on |
ohair@286 | 584 | * transport and SOAP version. |
ohair@286 | 585 | * <p/> |
ohair@286 | 586 | * For HTTP transport and SOAP 1.1, BP requires that SOAPAction |
ohair@286 | 587 | * header is present (See {@BP R2744} and {@BP R2745}.) For SOAP 1.2, |
ohair@286 | 588 | * this is moved to the parameter of the "application/soap+xml". |
ohair@286 | 589 | */ |
alanb@368 | 590 | @Property(BindingProvider.SOAPACTION_URI_PROPERTY) |
ohair@286 | 591 | public String soapAction; |
ohair@286 | 592 | |
ohair@286 | 593 | /** |
ohair@286 | 594 | * A hint indicating that whether a transport should expect |
ohair@286 | 595 | * a reply back from the server. |
ohair@286 | 596 | * |
ohair@286 | 597 | * <p> |
ohair@286 | 598 | * This property is used on the client-side for |
ohair@286 | 599 | * outbound messages, so that a pipeline |
ohair@286 | 600 | * can communicate to the terminal (or intermediate) {@link Tube}s |
ohair@286 | 601 | * about this knowledge. |
ohair@286 | 602 | * |
ohair@286 | 603 | * <p> |
ohair@286 | 604 | * This property <b>MUST NOT</b> be used by 2-way transports |
ohair@286 | 605 | * that have the transport back channel. Those transports |
ohair@286 | 606 | * must always check a reply coming through the transport back |
ohair@286 | 607 | * channel regardless of this value, and act accordingly. |
ohair@286 | 608 | * (This is because the expectation of the client and |
ohair@286 | 609 | * that of the server can be different, for example because |
ohair@286 | 610 | * of a bug in user's configuration.) |
ohair@286 | 611 | * |
ohair@286 | 612 | * <p> |
ohair@286 | 613 | * This property is for one-way transports, and more |
ohair@286 | 614 | * specifically for the coordinator that correlates sent requests |
ohair@286 | 615 | * and incoming replies, to decide whether to block |
ohair@286 | 616 | * until a response is received. |
ohair@286 | 617 | * |
ohair@286 | 618 | * <p> |
ohair@286 | 619 | * Also note that this property is related to |
ohair@286 | 620 | * {@link WSDLOperation#isOneWay()} but not the same thing. |
ohair@286 | 621 | * In fact in general, they are completely orthogonal. |
ohair@286 | 622 | * |
ohair@286 | 623 | * For example, the calling application can choose to invoke |
ohair@286 | 624 | * {@link Dispatch#invoke(Object)} or {@link Dispatch#invokeOneWay(Object)} |
ohair@286 | 625 | * with an operation (which determines the value of this property), |
ohair@286 | 626 | * regardless of whether WSDL actually says it's one way or not. |
ohair@286 | 627 | * So these two booleans can take any combinations. |
ohair@286 | 628 | * |
ohair@286 | 629 | * |
ohair@286 | 630 | * <p> |
ohair@286 | 631 | * When this property is {@link Boolean#FALSE}, it means that |
ohair@286 | 632 | * the pipeline does not expect a reply from a server (and therefore |
ohair@286 | 633 | * the correlator should not block for a reply message |
ohair@286 | 634 | * -- if such a reply does arrive, it can be just ignored.) |
ohair@286 | 635 | * |
ohair@286 | 636 | * <p> |
ohair@286 | 637 | * When this property is {@link Boolean#TRUE}, it means that |
ohair@286 | 638 | * the pipeline expects a reply from a server (and therefore |
ohair@286 | 639 | * the correlator should block to see if a reply message is received, |
ohair@286 | 640 | * |
ohair@286 | 641 | * <p> |
ohair@286 | 642 | * This property is always set to {@link Boolean#TRUE} or |
ohair@286 | 643 | * {@link Boolean#FALSE} when used on the request message |
ohair@286 | 644 | * on the client side. |
ohair@286 | 645 | * No other {@link Boolean} instances are allowed. |
ohair@286 | 646 | * <p> |
ohair@286 | 647 | * |
ohair@286 | 648 | * In all other situations, this property is null. |
ohair@286 | 649 | * |
ohair@286 | 650 | */ |
alanb@368 | 651 | @Property(BindingProviderProperties.ONE_WAY_OPERATION) |
ohair@286 | 652 | public Boolean expectReply; |
ohair@286 | 653 | |
ohair@286 | 654 | |
ohair@286 | 655 | /** |
ohair@286 | 656 | * This property will be removed in a near future. |
ohair@286 | 657 | * |
ohair@286 | 658 | * <p> |
ohair@286 | 659 | * A part of what this flag represented moved to |
ohair@286 | 660 | * {@link #expectReply} and the other part was moved |
ohair@286 | 661 | * to {@link Message#isOneWay(WSDLPort)}. Please update |
ohair@286 | 662 | * your code soon, or risk breaking your build!! |
ohair@286 | 663 | */ |
ohair@286 | 664 | @Deprecated |
ohair@286 | 665 | public Boolean isOneWay; |
ohair@286 | 666 | |
ohair@286 | 667 | /** |
ohair@286 | 668 | * Indicates whether is invoking a synchronous pattern. If true, no |
ohair@286 | 669 | * async client programming model (e.g. AsyncResponse or AsyncHandler) |
ohair@286 | 670 | * were used to make the request that created this packet. |
ohair@286 | 671 | */ |
ohair@286 | 672 | public Boolean isSynchronousMEP; |
ohair@286 | 673 | |
ohair@286 | 674 | /** |
ohair@286 | 675 | * Indicates whether a non-null AsyncHandler was given at the point of |
ohair@286 | 676 | * making the request that created this packet. This flag can be used |
ohair@286 | 677 | * by Tube implementations to decide how to react when isSynchronousMEP |
ohair@286 | 678 | * is false. If true, the client gave a non-null AsyncHandler instance |
ohair@286 | 679 | * at the point of request, and will be expecting a response on that |
ohair@286 | 680 | * handler when this request has been processed. |
ohair@286 | 681 | */ |
ohair@286 | 682 | public Boolean nonNullAsyncHandlerGiven; |
ohair@286 | 683 | |
ohair@286 | 684 | /** |
alanb@368 | 685 | * USE-CASE: |
alanb@368 | 686 | * WS-AT is enabled, but there is no WSDL available. |
alanb@368 | 687 | * If Packet.isRequestReplyMEP() is Boolean.TRUE then WS-AT should |
alanb@368 | 688 | * add the TX context. |
alanb@368 | 689 | * |
alanb@368 | 690 | * This value is exposed to users via facades at higher abstraction layers. |
alanb@368 | 691 | * The user should NEVER use Packet directly. |
alanb@368 | 692 | * This value should ONLY be set by users. |
alanb@368 | 693 | */ |
alanb@368 | 694 | private Boolean isRequestReplyMEP; |
alanb@368 | 695 | public Boolean isRequestReplyMEP() { return isRequestReplyMEP; } |
alanb@368 | 696 | public void setRequestReplyMEP(final Boolean x) { isRequestReplyMEP = x; } |
alanb@368 | 697 | |
alanb@368 | 698 | /** |
ohair@286 | 699 | * Lazily created set of handler-scope property names. |
ohair@286 | 700 | * |
ohair@286 | 701 | * <p> |
ohair@286 | 702 | * We expect that this is only used when handlers are present |
ohair@286 | 703 | * and they explicitly set some handler-scope values. |
ohair@286 | 704 | * |
ohair@286 | 705 | * @see #getHandlerScopePropertyNames(boolean) |
ohair@286 | 706 | */ |
ohair@286 | 707 | private Set<String> handlerScopePropertyNames; |
ohair@286 | 708 | |
ohair@286 | 709 | /** |
ohair@286 | 710 | * Bag to capture properties that are available for the whole |
ohair@286 | 711 | * message invocation (namely on both requests and responses.) |
ohair@286 | 712 | * |
ohair@286 | 713 | * <p> |
ohair@286 | 714 | * These properties are copied from a request to a response. |
ohair@286 | 715 | * This is where we keep properties that are set by handlers. |
ohair@286 | 716 | * |
ohair@286 | 717 | * <p> |
ohair@286 | 718 | * See <a href="#properties">class javadoc</a> for more discussion. |
ohair@286 | 719 | * |
ohair@286 | 720 | * @see #getHandlerScopePropertyNames(boolean) |
ohair@286 | 721 | */ |
ohair@286 | 722 | public final Map<String, Object> invocationProperties; |
ohair@286 | 723 | |
ohair@286 | 724 | /** |
ohair@286 | 725 | * Gets a {@link Set} that stores handler-scope properties. |
ohair@286 | 726 | * |
ohair@286 | 727 | * <p> |
ohair@286 | 728 | * These properties will not be exposed to the response context. |
ohair@286 | 729 | * Consequently, if a {@link Tube} wishes to hide a property |
ohair@286 | 730 | * to {@link ResponseContext}, it needs to add the property name |
ohair@286 | 731 | * to this set. |
ohair@286 | 732 | * |
ohair@286 | 733 | * @param readOnly |
ohair@286 | 734 | * Return true if the caller only intends to read the value of this set. |
ohair@286 | 735 | * Internally, the {@link Set} is allocated lazily, and this flag helps |
ohair@286 | 736 | * optimizing the strategy. |
ohair@286 | 737 | * |
ohair@286 | 738 | * @return |
ohair@286 | 739 | * always non-null, possibly empty set that stores property names. |
ohair@286 | 740 | */ |
ohair@286 | 741 | public final Set<String> getHandlerScopePropertyNames(boolean readOnly) { |
ohair@286 | 742 | Set<String> o = this.handlerScopePropertyNames; |
ohair@286 | 743 | if (o == null) { |
alanb@368 | 744 | if (readOnly) { |
ohair@286 | 745 | return Collections.emptySet(); |
alanb@368 | 746 | } |
ohair@286 | 747 | o = new HashSet<String>(); |
ohair@286 | 748 | this.handlerScopePropertyNames = o; |
ohair@286 | 749 | } |
ohair@286 | 750 | return o; |
ohair@286 | 751 | } |
ohair@286 | 752 | |
ohair@286 | 753 | /** |
ohair@286 | 754 | * This method no longer works. |
ohair@286 | 755 | * |
ohair@286 | 756 | * @deprecated |
ohair@286 | 757 | * Use {@link #getHandlerScopePropertyNames(boolean)}. |
ohair@286 | 758 | * To be removed once Tango components are updated. |
ohair@286 | 759 | */ |
ohair@286 | 760 | public final Set<String> getApplicationScopePropertyNames(boolean readOnly) { |
ohair@286 | 761 | assert false; |
ohair@286 | 762 | return new HashSet<String>(); |
ohair@286 | 763 | } |
ohair@286 | 764 | |
ohair@286 | 765 | /** |
ohair@286 | 766 | * Creates a response {@link Packet} from a request packet ({@code this}). |
ohair@286 | 767 | * |
ohair@286 | 768 | * <p> |
ohair@286 | 769 | * When a {@link Packet} for a reply is created, some properties need to be |
ohair@286 | 770 | * copied over from a request to a response, and this method handles it correctly. |
ohair@286 | 771 | * |
ohair@286 | 772 | * @deprecated |
ohair@286 | 773 | * Use createClientResponse(Message) for client side and |
ohair@286 | 774 | * createServerResponse(Message, String) for server side response |
ohair@286 | 775 | * creation. |
ohair@286 | 776 | * |
ohair@286 | 777 | * @param msg |
ohair@286 | 778 | * The {@link Message} that represents a reply. Can be null. |
ohair@286 | 779 | */ |
ohair@286 | 780 | @Deprecated |
ohair@286 | 781 | public Packet createResponse(Message msg) { |
ohair@286 | 782 | Packet response = new Packet(this); |
ohair@286 | 783 | response.setMessage(msg); |
ohair@286 | 784 | return response; |
ohair@286 | 785 | } |
ohair@286 | 786 | |
ohair@286 | 787 | /** |
ohair@286 | 788 | * Creates a response {@link Packet} from a request packet ({@code this}). |
ohair@286 | 789 | * |
ohair@286 | 790 | * <p> |
ohair@286 | 791 | * When a {@link Packet} for a reply is created, some properties need to be |
ohair@286 | 792 | * copied over from a request to a response, and this method handles it correctly. |
ohair@286 | 793 | * |
ohair@286 | 794 | * @param msg |
ohair@286 | 795 | * The {@link Message} that represents a reply. Can be null. |
ohair@286 | 796 | */ |
ohair@286 | 797 | public Packet createClientResponse(Message msg) { |
ohair@286 | 798 | Packet response = new Packet(this); |
alanb@368 | 799 | response.setMessage(msg); |
alanb@368 | 800 | finishCreateRelateClientResponse(response); |
alanb@368 | 801 | return response; |
alanb@368 | 802 | } |
alanb@368 | 803 | |
alanb@368 | 804 | /** |
alanb@368 | 805 | * For use cases that start with an existing Packet. |
alanb@368 | 806 | */ |
alanb@368 | 807 | public Packet relateClientResponse(final Packet response) { |
alanb@368 | 808 | response.relatePackets(this, true); |
alanb@368 | 809 | finishCreateRelateClientResponse(response); |
alanb@368 | 810 | return response; |
alanb@368 | 811 | } |
alanb@368 | 812 | |
alanb@368 | 813 | private void finishCreateRelateClientResponse(final Packet response) { |
ohair@286 | 814 | response.soapAction = null; // de-initializing |
alanb@368 | 815 | response.setState(State.ClientResponse); |
ohair@286 | 816 | } |
ohair@286 | 817 | |
ohair@286 | 818 | /** |
ohair@286 | 819 | * Creates a server-side response {@link Packet} from a request |
ohair@286 | 820 | * packet ({@code this}). If WS-Addressing is enabled, a default Action |
ohair@286 | 821 | * Message Addressing Property is obtained using <code>wsdlPort</code> {@link WSDLPort} |
ohair@286 | 822 | * and <code>binding</code> {@link WSBinding}. |
ohair@286 | 823 | * <p><p> |
ohair@286 | 824 | * This method should be called to create application response messages |
ohair@286 | 825 | * since they are associated with a {@link WSBinding} and {@link WSDLPort}. |
ohair@286 | 826 | * For creating protocol messages that require a non-default Action, use |
ohair@286 | 827 | * {@link #createServerResponse(Message, com.sun.xml.internal.ws.api.addressing.AddressingVersion, com.sun.xml.internal.ws.api.SOAPVersion, String)}. |
ohair@286 | 828 | * |
ohair@286 | 829 | * @param responseMessage The {@link Message} that represents a reply. Can be null. |
ohair@286 | 830 | * @param wsdlPort The response WSDL port. |
ohair@286 | 831 | * @param binding The response Binding. Cannot be null. |
ohair@286 | 832 | * @return response packet |
ohair@286 | 833 | */ |
ohair@286 | 834 | public Packet createServerResponse(@Nullable Message responseMessage, @Nullable WSDLPort wsdlPort, @Nullable SEIModel seiModel, @NotNull WSBinding binding) { |
ohair@286 | 835 | Packet r = createClientResponse(responseMessage); |
alanb@368 | 836 | return relateServerResponse(r, wsdlPort, seiModel, binding); |
alanb@368 | 837 | } |
ohair@286 | 838 | |
alanb@368 | 839 | /** |
alanb@368 | 840 | * Copy all properties from ({@code this}) packet into a input {@link Packet} |
alanb@368 | 841 | * @param response packet |
alanb@368 | 842 | */ |
alanb@368 | 843 | public void copyPropertiesTo(@Nullable Packet response){ |
alanb@368 | 844 | relatePackets(response, false); |
alanb@368 | 845 | } |
alanb@368 | 846 | |
alanb@368 | 847 | |
alanb@368 | 848 | /** |
alanb@368 | 849 | * A common method to make members related between input packet and this packet |
alanb@368 | 850 | * |
alanb@368 | 851 | * @param packet |
alanb@368 | 852 | * @param isCopy 'true' means copying all properties from input packet; |
alanb@368 | 853 | * 'false' means copying all properties from this packet to input packet. |
alanb@368 | 854 | */ |
alanb@368 | 855 | private void relatePackets(@Nullable Packet packet, boolean isCopy) |
alanb@368 | 856 | { |
alanb@368 | 857 | Packet request; |
alanb@368 | 858 | Packet response; |
alanb@368 | 859 | |
alanb@368 | 860 | if (!isCopy) { //is relate |
alanb@368 | 861 | request = this; |
alanb@368 | 862 | response = packet; |
alanb@368 | 863 | |
alanb@368 | 864 | // processing specific properties |
alanb@368 | 865 | response.soapAction = null; |
alanb@368 | 866 | response.invocationProperties.putAll(request.invocationProperties); |
alanb@368 | 867 | if (this.getState().equals(State.ServerRequest)) { |
alanb@368 | 868 | response.setState(State.ServerResponse); |
alanb@368 | 869 | } |
alanb@368 | 870 | } else { //is copy constructor |
alanb@368 | 871 | request = packet; |
alanb@368 | 872 | response = this; |
alanb@368 | 873 | |
alanb@368 | 874 | // processing specific properties |
alanb@368 | 875 | response.soapAction = request.soapAction; |
alanb@368 | 876 | response.setState(request.getState()); |
alanb@368 | 877 | } |
alanb@368 | 878 | |
alanb@368 | 879 | request.copySatelliteInto(response); |
alanb@368 | 880 | response.isAdapterDeliversNonAnonymousResponse = request.isAdapterDeliversNonAnonymousResponse; |
alanb@368 | 881 | response.handlerConfig = request.handlerConfig; |
alanb@368 | 882 | response.handlerScopePropertyNames = request.handlerScopePropertyNames; |
alanb@368 | 883 | response.contentNegotiation = request.contentNegotiation; |
alanb@368 | 884 | response.wasTransportSecure = request.wasTransportSecure; |
alanb@368 | 885 | response.transportBackChannel = request.transportBackChannel; |
alanb@368 | 886 | response.endpointAddress = request.endpointAddress; |
alanb@368 | 887 | response.wsdlOperation = request.wsdlOperation; |
alanb@368 | 888 | response.wsdlOperationMapping = request.wsdlOperationMapping; |
alanb@368 | 889 | response.acceptableMimeTypes = request.acceptableMimeTypes; |
alanb@368 | 890 | response.endpoint = request.endpoint; |
alanb@368 | 891 | response.proxy = request.proxy; |
alanb@368 | 892 | response.webServiceContextDelegate = request.webServiceContextDelegate; |
alanb@368 | 893 | response.expectReply = request.expectReply; |
alanb@368 | 894 | response.component = request.component; |
alanb@368 | 895 | response.mtomAcceptable = request.mtomAcceptable; |
alanb@368 | 896 | response.mtomRequest = request.mtomRequest; |
alanb@368 | 897 | // copy other properties that need to be copied. is there any? |
alanb@368 | 898 | } |
alanb@368 | 899 | |
alanb@368 | 900 | |
alanb@368 | 901 | public Packet relateServerResponse(@Nullable Packet r, @Nullable WSDLPort wsdlPort, @Nullable SEIModel seiModel, @NotNull WSBinding binding) { |
alanb@368 | 902 | relatePackets(r, false); |
alanb@368 | 903 | r.setState(State.ServerResponse); |
ohair@286 | 904 | AddressingVersion av = binding.getAddressingVersion(); |
ohair@286 | 905 | // populate WS-A headers only if WS-A is enabled |
alanb@368 | 906 | if (av == null) { |
ohair@286 | 907 | return r; |
alanb@368 | 908 | } |
alanb@368 | 909 | |
alanb@368 | 910 | if (getMessage() == null) { |
alanb@368 | 911 | return r; |
alanb@368 | 912 | } |
alanb@368 | 913 | |
ohair@286 | 914 | //populate WS-A headers only if the request has addressing headers |
alanb@368 | 915 | String inputAction = AddressingUtils.getAction(getMessage().getHeaders(), av, binding.getSOAPVersion()); |
ohair@286 | 916 | if (inputAction == null) { |
ohair@286 | 917 | return r; |
ohair@286 | 918 | } |
ohair@286 | 919 | // if one-way, then dont populate any WS-A headers |
alanb@368 | 920 | if (r.getMessage() == null || (wsdlPort != null && getMessage().isOneWay(wsdlPort))) { |
ohair@286 | 921 | return r; |
ohair@286 | 922 | } |
ohair@286 | 923 | |
ohair@286 | 924 | // otherwise populate WS-Addressing headers |
ohair@286 | 925 | populateAddressingHeaders(binding, r, wsdlPort, seiModel); |
ohair@286 | 926 | return r; |
ohair@286 | 927 | } |
ohair@286 | 928 | |
ohair@286 | 929 | /** |
ohair@286 | 930 | * Creates a server-side response {@link Packet} from a request |
ohair@286 | 931 | * packet ({@code this}). If WS-Addressing is enabled, <code>action</code> |
ohair@286 | 932 | * is used as Action Message Addressing Property. |
ohair@286 | 933 | * <p><p> |
ohair@286 | 934 | * This method should be called only for creating protocol response messages |
ohair@286 | 935 | * that require a particular value of Action since they are not associated |
ohair@286 | 936 | * with a {@link WSBinding} and {@link WSDLPort} but do know the {@link AddressingVersion} |
ohair@286 | 937 | * and {@link SOAPVersion}. |
ohair@286 | 938 | * |
ohair@286 | 939 | * @param responseMessage The {@link Message} that represents a reply. Can be null. |
ohair@286 | 940 | * @param addressingVersion The WS-Addressing version of the response message. |
ohair@286 | 941 | * @param soapVersion The SOAP version of the response message. |
ohair@286 | 942 | * @param action The response Action Message Addressing Property value. |
ohair@286 | 943 | * @return response packet |
ohair@286 | 944 | */ |
ohair@286 | 945 | public Packet createServerResponse(@Nullable Message responseMessage, @NotNull AddressingVersion addressingVersion, @NotNull SOAPVersion soapVersion, @NotNull String action) { |
ohair@286 | 946 | Packet responsePacket = createClientResponse(responseMessage); |
alanb@368 | 947 | responsePacket.setState(State.ServerResponse); |
ohair@286 | 948 | // populate WS-A headers only if WS-A is enabled |
alanb@368 | 949 | if (addressingVersion == null) { |
ohair@286 | 950 | return responsePacket; |
alanb@368 | 951 | } |
ohair@286 | 952 | //populate WS-A headers only if the request has addressing headers |
alanb@368 | 953 | String inputAction = AddressingUtils.getAction(this.getMessage().getHeaders(), addressingVersion, soapVersion); |
ohair@286 | 954 | if (inputAction == null) { |
ohair@286 | 955 | return responsePacket; |
ohair@286 | 956 | } |
ohair@286 | 957 | |
ohair@286 | 958 | populateAddressingHeaders(responsePacket, addressingVersion, soapVersion, action, false); |
ohair@286 | 959 | return responsePacket; |
ohair@286 | 960 | } |
ohair@286 | 961 | |
ohair@286 | 962 | /** |
ohair@286 | 963 | * Overwrites the {@link Message} of the response packet ({@code this}) by the given {@link Message}. |
ohair@286 | 964 | * Unlike {@link #setMessage(Message)}, fill in the addressing headers correctly, and this process |
ohair@286 | 965 | * requires the access to the request packet. |
ohair@286 | 966 | * |
ohair@286 | 967 | * <p> |
ohair@286 | 968 | * This method is useful when the caller needs to swap a response message completely to a new one. |
ohair@286 | 969 | * |
ohair@286 | 970 | * @see #createServerResponse(Message, AddressingVersion, SOAPVersion, String) |
ohair@286 | 971 | */ |
ohair@286 | 972 | public void setResponseMessage(@NotNull Packet request, @Nullable Message responseMessage, @NotNull AddressingVersion addressingVersion, @NotNull SOAPVersion soapVersion, @NotNull String action) { |
ohair@286 | 973 | Packet temp = request.createServerResponse(responseMessage, addressingVersion, soapVersion, action); |
ohair@286 | 974 | setMessage(temp.getMessage()); |
ohair@286 | 975 | } |
ohair@286 | 976 | |
ohair@286 | 977 | private void populateAddressingHeaders(Packet responsePacket, AddressingVersion av, SOAPVersion sv, String action, boolean mustUnderstand) { |
ohair@286 | 978 | // populate WS-A headers only if WS-A is enabled |
ohair@286 | 979 | if (av == null) return; |
ohair@286 | 980 | |
ohair@286 | 981 | // if one-way, then dont populate any WS-A headers |
ohair@286 | 982 | if (responsePacket.getMessage() == null) |
ohair@286 | 983 | return; |
ohair@286 | 984 | |
alanb@368 | 985 | MessageHeaders hl = responsePacket.getMessage().getHeaders(); |
ohair@286 | 986 | |
ohair@286 | 987 | WsaPropertyBag wpb = getSatellite(WsaPropertyBag.class); |
alanb@368 | 988 | Message msg = getMessage(); |
ohair@286 | 989 | // wsa:To |
ohair@286 | 990 | WSEndpointReference replyTo = null; |
alanb@368 | 991 | Header replyToFromRequestMsg = AddressingUtils.getFirstHeader(msg.getHeaders(), av.replyToTag, true, sv); |
alanb@368 | 992 | Header replyToFromResponseMsg = hl.get(av.toTag, false); |
alanb@368 | 993 | boolean replaceToTag = true; |
alanb@368 | 994 | try{ |
alanb@368 | 995 | if (replyToFromRequestMsg != null){ |
alanb@368 | 996 | replyTo = replyToFromRequestMsg.readAsEPR(av); |
alanb@368 | 997 | } |
alanb@368 | 998 | if (replyToFromResponseMsg != null && replyTo == null) { |
alanb@368 | 999 | replaceToTag = false; |
alanb@368 | 1000 | } |
alanb@368 | 1001 | } catch (XMLStreamException e) { |
alanb@368 | 1002 | throw new WebServiceException(AddressingMessages.REPLY_TO_CANNOT_PARSE(), e); |
alanb@368 | 1003 | } |
alanb@368 | 1004 | if (replyTo == null) { |
alanb@368 | 1005 | replyTo = AddressingUtils.getReplyTo(msg.getHeaders(), av, sv); |
alanb@368 | 1006 | } |
ohair@286 | 1007 | |
ohair@286 | 1008 | // wsa:Action, add if the message doesn't already contain it, |
ohair@286 | 1009 | // generally true for SEI case where there is SEIModel or WSDLModel |
ohair@286 | 1010 | // false for Provider with no wsdl, Expects User to set the coresponding header on the Message. |
alanb@368 | 1011 | if (AddressingUtils.getAction(responsePacket.getMessage().getHeaders(), av, sv) == null) { |
ohair@286 | 1012 | //wsa:Action header is not set in the message, so use the wsa:Action passed as the parameter. |
ohair@286 | 1013 | hl.add(new StringHeader(av.actionTag, action, sv, mustUnderstand)); |
ohair@286 | 1014 | } |
ohair@286 | 1015 | |
ohair@286 | 1016 | // wsa:MessageID |
ohair@286 | 1017 | if (responsePacket.getMessage().getHeaders().get(av.messageIDTag, false) == null) { |
ohair@286 | 1018 | // if header doesn't exist, method getID creates a new random id |
ohair@286 | 1019 | String newID = Message.generateMessageID(); |
ohair@286 | 1020 | hl.add(new StringHeader(av.messageIDTag, newID)); |
ohair@286 | 1021 | } |
ohair@286 | 1022 | |
ohair@286 | 1023 | // wsa:RelatesTo |
ohair@286 | 1024 | String mid = null; |
alanb@368 | 1025 | if (wpb != null) { |
alanb@368 | 1026 | mid = wpb.getMessageID(); |
alanb@368 | 1027 | } |
alanb@368 | 1028 | if (mid == null) { |
alanb@368 | 1029 | mid = AddressingUtils.getMessageID(msg.getHeaders(), av, sv); |
alanb@368 | 1030 | } |
alanb@368 | 1031 | if (mid != null) { |
alanb@368 | 1032 | hl.addOrReplace(new RelatesToHeader(av.relatesToTag, mid)); |
alanb@368 | 1033 | } |
ohair@286 | 1034 | |
ohair@286 | 1035 | |
ohair@286 | 1036 | // populate reference parameters |
ohair@286 | 1037 | WSEndpointReference refpEPR = null; |
ohair@286 | 1038 | if (responsePacket.getMessage().isFault()) { |
ohair@286 | 1039 | // choose FaultTo |
alanb@368 | 1040 | if (wpb != null) { |
alanb@368 | 1041 | refpEPR = wpb.getFaultToFromRequest(); |
alanb@368 | 1042 | } |
alanb@368 | 1043 | if (refpEPR == null) { |
alanb@368 | 1044 | refpEPR = AddressingUtils.getFaultTo(msg.getHeaders(), av, sv); |
alanb@368 | 1045 | } |
ohair@286 | 1046 | // if FaultTo is null, then use ReplyTo |
alanb@368 | 1047 | if (refpEPR == null) { |
ohair@286 | 1048 | refpEPR = replyTo; |
alanb@368 | 1049 | } |
ohair@286 | 1050 | } else { |
ohair@286 | 1051 | // choose ReplyTo |
ohair@286 | 1052 | refpEPR = replyTo; |
ohair@286 | 1053 | } |
alanb@368 | 1054 | if (replaceToTag && refpEPR != null) { |
alanb@368 | 1055 | hl.addOrReplace(new StringHeader(av.toTag, refpEPR.getAddress())); |
ohair@286 | 1056 | refpEPR.addReferenceParametersToList(hl); |
ohair@286 | 1057 | } |
ohair@286 | 1058 | } |
ohair@286 | 1059 | |
ohair@286 | 1060 | private void populateAddressingHeaders(WSBinding binding, Packet responsePacket, WSDLPort wsdlPort, SEIModel seiModel) { |
ohair@286 | 1061 | AddressingVersion addressingVersion = binding.getAddressingVersion(); |
ohair@286 | 1062 | |
alanb@368 | 1063 | if (addressingVersion == null) { |
alanb@368 | 1064 | return; |
alanb@368 | 1065 | } |
ohair@286 | 1066 | |
ohair@286 | 1067 | WsaTubeHelper wsaHelper = addressingVersion.getWsaHelper(wsdlPort, seiModel, binding); |
alanb@368 | 1068 | String action = responsePacket.getMessage().isFault() ? |
ohair@286 | 1069 | wsaHelper.getFaultAction(this, responsePacket) : |
ohair@286 | 1070 | wsaHelper.getOutputAction(this); |
ohair@286 | 1071 | if (action == null) { |
ohair@286 | 1072 | LOGGER.info("WSA headers are not added as value for wsa:Action cannot be resolved for this message"); |
ohair@286 | 1073 | return; |
ohair@286 | 1074 | } |
alanb@368 | 1075 | populateAddressingHeaders(responsePacket, addressingVersion, binding.getSOAPVersion(), action, AddressingVersion.isRequired(binding)); |
ohair@286 | 1076 | } |
ohair@286 | 1077 | |
ohair@286 | 1078 | public String toShortString() { |
ohair@286 | 1079 | return super.toString(); |
ohair@286 | 1080 | } |
ohair@286 | 1081 | |
ohair@286 | 1082 | // For use only in a debugger |
alanb@368 | 1083 | @Override |
ohair@286 | 1084 | public String toString() { |
ohair@286 | 1085 | StringBuilder buf = new StringBuilder(); |
ohair@286 | 1086 | buf.append(super.toString()); |
ohair@286 | 1087 | String content; |
ohair@286 | 1088 | try { |
alanb@368 | 1089 | Message msg = getMessage(); |
alanb@368 | 1090 | if (msg != null) { |
ohair@286 | 1091 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); |
ohair@286 | 1092 | XMLStreamWriter xmlWriter = XMLStreamWriterFactory.create(baos, "UTF-8"); |
alanb@368 | 1093 | msg.copy().writeTo(xmlWriter); |
ohair@286 | 1094 | xmlWriter.flush(); |
ohair@286 | 1095 | xmlWriter.close(); |
ohair@286 | 1096 | baos.flush(); |
ohair@286 | 1097 | XMLStreamWriterFactory.recycle(xmlWriter); |
ohair@286 | 1098 | |
ohair@286 | 1099 | byte[] bytes = baos.toByteArray(); |
ohair@286 | 1100 | //message = Messages.create(XMLStreamReaderFactory.create(null, new ByteArrayInputStream(bytes), "UTF-8", true)); |
ohair@286 | 1101 | content = new String(bytes, "UTF-8"); |
ohair@286 | 1102 | } else { |
ohair@286 | 1103 | content = "<none>"; |
ohair@286 | 1104 | } |
ohair@286 | 1105 | } catch (Throwable t) { |
ohair@286 | 1106 | throw new WebServiceException(t); |
ohair@286 | 1107 | } |
ohair@286 | 1108 | buf.append(" Content: ").append(content); |
ohair@286 | 1109 | return buf.toString(); |
ohair@286 | 1110 | } |
ohair@286 | 1111 | |
ohair@286 | 1112 | // completes TypedMap |
ohair@286 | 1113 | private static final PropertyMap model; |
ohair@286 | 1114 | |
ohair@286 | 1115 | static { |
ohair@286 | 1116 | model = parse(Packet.class); |
ohair@286 | 1117 | } |
ohair@286 | 1118 | |
alanb@368 | 1119 | @Override |
ohair@286 | 1120 | protected PropertyMap getPropertyMap() { |
ohair@286 | 1121 | return model; |
ohair@286 | 1122 | } |
ohair@286 | 1123 | |
alanb@368 | 1124 | public Map<String, Object> asMapIncludingInvocationProperties() { |
alanb@368 | 1125 | final Map<String, Object> asMap = asMap(); |
alanb@368 | 1126 | return new AbstractMap<String, Object>() { |
alanb@368 | 1127 | @Override |
alanb@368 | 1128 | public Object get(Object key) { |
alanb@368 | 1129 | Object o = asMap.get(key); |
alanb@368 | 1130 | if (o != null) |
alanb@368 | 1131 | return o; |
alanb@368 | 1132 | |
alanb@368 | 1133 | return invocationProperties.get(key); |
alanb@368 | 1134 | } |
alanb@368 | 1135 | |
alanb@368 | 1136 | @Override |
alanb@368 | 1137 | public int size() { |
alanb@368 | 1138 | return asMap.size() + invocationProperties.size(); |
alanb@368 | 1139 | } |
alanb@368 | 1140 | |
alanb@368 | 1141 | @Override |
alanb@368 | 1142 | public boolean containsKey(Object key) { |
alanb@368 | 1143 | if (asMap.containsKey(key)) |
alanb@368 | 1144 | return true; |
alanb@368 | 1145 | return invocationProperties.containsKey(key); |
alanb@368 | 1146 | } |
alanb@368 | 1147 | |
alanb@368 | 1148 | @Override |
alanb@368 | 1149 | public Set<Entry<String, Object>> entrySet() { |
alanb@368 | 1150 | final Set<Entry<String, Object>> asMapEntries = asMap.entrySet(); |
alanb@368 | 1151 | final Set<Entry<String, Object>> ipEntries = invocationProperties.entrySet(); |
alanb@368 | 1152 | |
alanb@368 | 1153 | return new AbstractSet<Entry<String, Object>>() { |
alanb@368 | 1154 | @Override |
alanb@368 | 1155 | public Iterator<Entry<String, Object>> iterator() { |
alanb@368 | 1156 | final Iterator<Entry<String, Object>> asMapIt = asMapEntries.iterator(); |
alanb@368 | 1157 | final Iterator<Entry<String, Object>> ipIt = ipEntries.iterator(); |
alanb@368 | 1158 | |
alanb@368 | 1159 | return new Iterator<Entry<String, Object>>() { |
alanb@368 | 1160 | @Override |
alanb@368 | 1161 | public boolean hasNext() { |
alanb@368 | 1162 | return asMapIt.hasNext() || ipIt.hasNext(); |
alanb@368 | 1163 | } |
alanb@368 | 1164 | |
alanb@368 | 1165 | @Override |
alanb@368 | 1166 | public java.util.Map.Entry<String, Object> next() { |
alanb@368 | 1167 | if (asMapIt.hasNext()) |
alanb@368 | 1168 | return asMapIt.next(); |
alanb@368 | 1169 | return ipIt.next(); |
alanb@368 | 1170 | } |
alanb@368 | 1171 | |
alanb@368 | 1172 | @Override |
alanb@368 | 1173 | public void remove() { |
alanb@368 | 1174 | throw new UnsupportedOperationException(); |
alanb@368 | 1175 | } |
alanb@368 | 1176 | }; |
alanb@368 | 1177 | } |
alanb@368 | 1178 | |
alanb@368 | 1179 | @Override |
alanb@368 | 1180 | public int size() { |
alanb@368 | 1181 | return asMap.size() + invocationProperties.size(); |
alanb@368 | 1182 | } |
alanb@368 | 1183 | }; |
alanb@368 | 1184 | } |
alanb@368 | 1185 | |
alanb@368 | 1186 | @Override |
alanb@368 | 1187 | public Object put(String key, Object value) { |
alanb@368 | 1188 | if (supports(key)) |
alanb@368 | 1189 | return asMap.put(key, value); |
alanb@368 | 1190 | |
alanb@368 | 1191 | return invocationProperties.put(key, value); |
alanb@368 | 1192 | } |
alanb@368 | 1193 | |
alanb@368 | 1194 | @Override |
alanb@368 | 1195 | public void clear() { |
alanb@368 | 1196 | asMap.clear(); |
alanb@368 | 1197 | invocationProperties.clear(); |
alanb@368 | 1198 | } |
alanb@368 | 1199 | |
alanb@368 | 1200 | @Override |
alanb@368 | 1201 | public Object remove(Object key) { |
alanb@368 | 1202 | if (supports(key)) |
alanb@368 | 1203 | return asMap.remove(key); |
alanb@368 | 1204 | |
alanb@368 | 1205 | return invocationProperties.remove(key); |
alanb@368 | 1206 | } |
alanb@368 | 1207 | }; |
alanb@368 | 1208 | } |
alanb@368 | 1209 | |
ohair@286 | 1210 | private static final Logger LOGGER = Logger.getLogger(Packet.class.getName()); |
ohair@286 | 1211 | |
alanb@368 | 1212 | @Override |
ohair@286 | 1213 | public SOAPMessage getSOAPMessage() throws SOAPException { |
alanb@368 | 1214 | return getAsSOAPMessage(); |
ohair@286 | 1215 | } |
ohair@286 | 1216 | |
alanb@368 | 1217 | //TODO replace the message to a SAAJMEssage issue - JRFSAAJMessage or SAAJMessage? |
alanb@368 | 1218 | @Override |
alanb@368 | 1219 | public SOAPMessage getAsSOAPMessage() throws SOAPException { |
alanb@368 | 1220 | Message msg = this.getMessage(); |
alanb@368 | 1221 | if (msg == null) |
alanb@368 | 1222 | return null; |
alanb@368 | 1223 | if (msg instanceof MessageWritable) |
alanb@368 | 1224 | ((MessageWritable) msg).setMTOMConfiguration(mtomFeature); |
alanb@368 | 1225 | return msg.readAsSOAPMessage(this, this.getState().isInbound()); |
alanb@368 | 1226 | } |
alanb@368 | 1227 | |
alanb@368 | 1228 | public |
ohair@286 | 1229 | Codec codec = null; |
alanb@368 | 1230 | public Codec getCodec() { |
alanb@368 | 1231 | if (codec != null) { |
alanb@368 | 1232 | return codec; |
alanb@368 | 1233 | } |
ohair@286 | 1234 | if (endpoint != null) { |
ohair@286 | 1235 | codec = endpoint.createCodec(); |
ohair@286 | 1236 | } |
ohair@286 | 1237 | WSBinding wsb = getBinding(); |
ohair@286 | 1238 | if (wsb != null) { |
ohair@286 | 1239 | codec = wsb.getBindingId().createEncoder(wsb); |
ohair@286 | 1240 | } |
ohair@286 | 1241 | return codec; |
ohair@286 | 1242 | } |
ohair@286 | 1243 | |
alanb@368 | 1244 | @Override |
alanb@368 | 1245 | public com.oracle.webservices.internal.api.message.ContentType writeTo( OutputStream out ) throws IOException { |
alanb@368 | 1246 | Message msg = getInternalMessage(); |
alanb@368 | 1247 | if (msg instanceof MessageWritable) { |
alanb@368 | 1248 | ((MessageWritable) msg).setMTOMConfiguration(mtomFeature); |
alanb@368 | 1249 | return ((MessageWritable)msg).writeTo(out); |
alanb@368 | 1250 | } |
ohair@286 | 1251 | return getCodec().encode(this, out); |
ohair@286 | 1252 | } |
ohair@286 | 1253 | |
alanb@368 | 1254 | public com.oracle.webservices.internal.api.message.ContentType writeTo( WritableByteChannel buffer ) { |
ohair@286 | 1255 | return getCodec().encode(this, buffer); |
ohair@286 | 1256 | } |
alanb@368 | 1257 | |
alanb@368 | 1258 | private ContentType contentType; |
alanb@368 | 1259 | |
alanb@368 | 1260 | /** |
alanb@368 | 1261 | * If the request's Content-Type is multipart/related; type=application/xop+xml, then this set to to true |
alanb@368 | 1262 | * |
alanb@368 | 1263 | * Used on server-side, for encoding the repsonse. |
alanb@368 | 1264 | */ |
alanb@368 | 1265 | private Boolean mtomRequest; |
alanb@368 | 1266 | |
alanb@368 | 1267 | /** |
alanb@368 | 1268 | * Based on request's Accept header this is set. |
alanb@368 | 1269 | * Currently only set if MTOMFeature is enabled. |
alanb@368 | 1270 | * |
alanb@368 | 1271 | * Should be used on server-side, for encoding the response. |
alanb@368 | 1272 | */ |
alanb@368 | 1273 | private Boolean mtomAcceptable; |
alanb@368 | 1274 | |
alanb@368 | 1275 | private MTOMFeature mtomFeature; |
alanb@368 | 1276 | |
alanb@368 | 1277 | public Boolean getMtomRequest() { |
alanb@368 | 1278 | return mtomRequest; |
alanb@368 | 1279 | } |
alanb@368 | 1280 | |
alanb@368 | 1281 | public void setMtomRequest(Boolean mtomRequest) { |
alanb@368 | 1282 | this.mtomRequest = mtomRequest; |
alanb@368 | 1283 | } |
alanb@368 | 1284 | |
alanb@368 | 1285 | public Boolean getMtomAcceptable() { |
alanb@368 | 1286 | return mtomAcceptable; |
alanb@368 | 1287 | } |
alanb@368 | 1288 | |
alanb@368 | 1289 | Boolean checkMtomAcceptable; |
alanb@368 | 1290 | public void checkMtomAcceptable() { |
alanb@368 | 1291 | if (checkMtomAcceptable == null) { |
alanb@368 | 1292 | if (acceptableMimeTypes == null || isFastInfosetDisabled) { |
alanb@368 | 1293 | checkMtomAcceptable = false; |
alanb@368 | 1294 | } else { |
alanb@368 | 1295 | checkMtomAcceptable = (acceptableMimeTypes.indexOf(MtomCodec.XOP_XML_MIME_TYPE) != -1); |
alanb@368 | 1296 | // StringTokenizer st = new StringTokenizer(acceptableMimeTypes, ","); |
alanb@368 | 1297 | // while (st.hasMoreTokens()) { |
alanb@368 | 1298 | // final String token = st.nextToken().trim(); |
alanb@368 | 1299 | // if (token.toLowerCase().contains(MtomCodec.XOP_XML_MIME_TYPE)) { |
alanb@368 | 1300 | // mtomAcceptable = true; |
alanb@368 | 1301 | // } |
alanb@368 | 1302 | // } |
alanb@368 | 1303 | // if (mtomAcceptable == null) mtomAcceptable = false; |
alanb@368 | 1304 | } |
alanb@368 | 1305 | } |
alanb@368 | 1306 | mtomAcceptable = checkMtomAcceptable; |
alanb@368 | 1307 | } |
alanb@368 | 1308 | |
alanb@368 | 1309 | private Boolean fastInfosetAcceptable; |
alanb@368 | 1310 | |
alanb@368 | 1311 | public Boolean getFastInfosetAcceptable(String fiMimeType) { |
alanb@368 | 1312 | if (fastInfosetAcceptable == null) { |
alanb@368 | 1313 | if (acceptableMimeTypes == null || isFastInfosetDisabled) { |
alanb@368 | 1314 | fastInfosetAcceptable = false; |
alanb@368 | 1315 | } else { |
alanb@368 | 1316 | fastInfosetAcceptable = (acceptableMimeTypes.indexOf(fiMimeType) != -1); |
alanb@368 | 1317 | } |
alanb@368 | 1318 | // if (accept == null || isFastInfosetDisabled) return false; |
alanb@368 | 1319 | // |
alanb@368 | 1320 | // StringTokenizer st = new StringTokenizer(accept, ","); |
alanb@368 | 1321 | // while (st.hasMoreTokens()) { |
alanb@368 | 1322 | // final String token = st.nextToken().trim(); |
alanb@368 | 1323 | // if (token.equalsIgnoreCase(fiMimeType)) { |
alanb@368 | 1324 | // return true; |
alanb@368 | 1325 | // } |
alanb@368 | 1326 | // } |
alanb@368 | 1327 | // return false; |
alanb@368 | 1328 | } |
alanb@368 | 1329 | return fastInfosetAcceptable; |
alanb@368 | 1330 | } |
alanb@368 | 1331 | |
alanb@368 | 1332 | |
alanb@368 | 1333 | public void setMtomFeature(MTOMFeature mtomFeature) { |
alanb@368 | 1334 | this.mtomFeature = mtomFeature; |
alanb@368 | 1335 | } |
alanb@368 | 1336 | |
alanb@368 | 1337 | public MTOMFeature getMtomFeature() { |
alanb@368 | 1338 | //If we have a binding, use that in preference to an explicitly |
alanb@368 | 1339 | //set MTOMFeature |
alanb@368 | 1340 | WSBinding binding = getBinding(); |
alanb@368 | 1341 | if (binding != null) { |
alanb@368 | 1342 | return binding.getFeature(MTOMFeature.class); |
alanb@368 | 1343 | } |
alanb@368 | 1344 | return mtomFeature; |
alanb@368 | 1345 | } |
alanb@368 | 1346 | |
alanb@368 | 1347 | @Override |
alanb@368 | 1348 | public com.oracle.webservices.internal.api.message.ContentType getContentType() { |
alanb@368 | 1349 | if (contentType == null) { |
alanb@368 | 1350 | contentType = getInternalContentType(); |
alanb@368 | 1351 | } |
alanb@368 | 1352 | if (contentType == null) { |
alanb@368 | 1353 | contentType = getCodec().getStaticContentType(this); |
alanb@368 | 1354 | } |
alanb@368 | 1355 | if (contentType == null) { |
alanb@368 | 1356 | //TODO write to buffer |
alanb@368 | 1357 | } |
alanb@368 | 1358 | return contentType; |
alanb@368 | 1359 | } |
alanb@368 | 1360 | |
alanb@368 | 1361 | public ContentType getInternalContentType() { |
alanb@368 | 1362 | Message msg = getInternalMessage(); |
alanb@368 | 1363 | if (msg instanceof MessageWritable) { |
alanb@368 | 1364 | return ((MessageWritable)msg).getContentType(); |
alanb@368 | 1365 | } |
alanb@368 | 1366 | return contentType; |
alanb@368 | 1367 | } |
alanb@368 | 1368 | |
alanb@368 | 1369 | public void setContentType(ContentType contentType) { |
alanb@368 | 1370 | this.contentType = contentType; |
alanb@368 | 1371 | } |
alanb@368 | 1372 | |
alanb@368 | 1373 | public enum Status { |
alanb@368 | 1374 | Request, Response, Unknown; |
alanb@368 | 1375 | public boolean isRequest() { return Request.equals(this); } |
alanb@368 | 1376 | public boolean isResponse() { return Response.equals(this); } |
alanb@368 | 1377 | } |
alanb@368 | 1378 | |
alanb@368 | 1379 | public enum State { |
alanb@368 | 1380 | ServerRequest(true), ClientRequest(false), ServerResponse(false), ClientResponse(true); |
alanb@368 | 1381 | private boolean inbound; |
alanb@368 | 1382 | State(boolean inbound) { |
alanb@368 | 1383 | this.inbound = inbound; |
alanb@368 | 1384 | } |
alanb@368 | 1385 | public boolean isInbound() { |
alanb@368 | 1386 | return inbound; |
alanb@368 | 1387 | } |
alanb@368 | 1388 | } |
alanb@368 | 1389 | |
alanb@368 | 1390 | // private Status status = Status.Unknown; |
alanb@368 | 1391 | |
alanb@368 | 1392 | //Default state is ServerRequest - some custom adapters may not set the value of state |
alanb@368 | 1393 | //upon server request - all other code paths should set it |
alanb@368 | 1394 | private State state = State.ServerRequest; |
alanb@368 | 1395 | |
alanb@368 | 1396 | // public Status getStatus() { return status; } |
alanb@368 | 1397 | |
alanb@368 | 1398 | public State getState() { return state; } |
alanb@368 | 1399 | public void setState(State state) { this.state = state; } |
alanb@368 | 1400 | |
alanb@368 | 1401 | public boolean shouldUseMtom() { |
alanb@368 | 1402 | if (getState().isInbound()) { |
alanb@368 | 1403 | return isMtomContentType(); |
alanb@368 | 1404 | } else { |
alanb@368 | 1405 | return shouldUseMtomOutbound(); |
alanb@368 | 1406 | } |
alanb@368 | 1407 | } |
alanb@368 | 1408 | |
alanb@368 | 1409 | private boolean shouldUseMtomOutbound() { |
alanb@368 | 1410 | //Use the getter to make sure all the logic is executed correctly |
alanb@368 | 1411 | MTOMFeature myMtomFeature = getMtomFeature(); |
alanb@368 | 1412 | if(myMtomFeature != null && myMtomFeature.isEnabled()) { |
alanb@368 | 1413 | //On client, always use XOP encoding if MTOM is enabled |
alanb@368 | 1414 | //On Server, mtomAcceptable and mtomRequest will be set - use XOP encoding |
alanb@368 | 1415 | //if either request is XOP encoded (mtomRequest) or |
alanb@368 | 1416 | //client accepts XOP encoding (mtomAcceptable) |
alanb@368 | 1417 | if (getMtomAcceptable() == null && getMtomRequest() == null) { |
alanb@368 | 1418 | return true; |
alanb@368 | 1419 | } else { |
alanb@368 | 1420 | if (getMtomAcceptable() != null && getMtomAcceptable() && getState().equals(State.ServerResponse)) { |
alanb@368 | 1421 | return true; |
alanb@368 | 1422 | } |
alanb@368 | 1423 | if (getMtomRequest() != null && getMtomRequest() && getState().equals(State.ServerResponse)) { |
alanb@368 | 1424 | return true; |
alanb@368 | 1425 | } |
alanb@368 | 1426 | } |
alanb@368 | 1427 | } |
alanb@368 | 1428 | return false; |
alanb@368 | 1429 | } |
alanb@368 | 1430 | |
alanb@368 | 1431 | private boolean isMtomContentType() { |
alanb@368 | 1432 | return (getInternalContentType() != null) && |
alanb@368 | 1433 | (getInternalContentType().getContentType().contains("application/xop+xml")); |
alanb@368 | 1434 | } |
alanb@368 | 1435 | |
alanb@368 | 1436 | /** |
alanb@368 | 1437 | * @deprecated |
alanb@368 | 1438 | */ |
alanb@368 | 1439 | public void addSatellite(@NotNull com.sun.xml.internal.ws.api.PropertySet satellite) { |
alanb@368 | 1440 | super.addSatellite(satellite); |
alanb@368 | 1441 | } |
alanb@368 | 1442 | |
alanb@368 | 1443 | /** |
alanb@368 | 1444 | * @deprecated |
alanb@368 | 1445 | */ |
alanb@368 | 1446 | public void addSatellite(@NotNull Class keyClass, @NotNull com.sun.xml.internal.ws.api.PropertySet satellite) { |
alanb@368 | 1447 | super.addSatellite(keyClass, satellite); |
alanb@368 | 1448 | } |
alanb@368 | 1449 | |
alanb@368 | 1450 | /** |
alanb@368 | 1451 | * @deprecated |
alanb@368 | 1452 | */ |
alanb@368 | 1453 | public void copySatelliteInto(@NotNull com.sun.xml.internal.ws.api.DistributedPropertySet r) { |
alanb@368 | 1454 | super.copySatelliteInto(r); |
alanb@368 | 1455 | } |
alanb@368 | 1456 | |
alanb@368 | 1457 | /** |
alanb@368 | 1458 | * @deprecated |
alanb@368 | 1459 | */ |
alanb@368 | 1460 | public void removeSatellite(com.sun.xml.internal.ws.api.PropertySet satellite) { |
alanb@368 | 1461 | super.removeSatellite(satellite); |
alanb@368 | 1462 | } |
alanb@368 | 1463 | |
alanb@368 | 1464 | /** |
alanb@368 | 1465 | * This is propogated from SOAPBindingCodec and will affect isMtomAcceptable and isFastInfosetAcceptable |
alanb@368 | 1466 | */ |
alanb@368 | 1467 | private boolean isFastInfosetDisabled; |
alanb@368 | 1468 | |
alanb@368 | 1469 | public void setFastInfosetDisabled(boolean b) { |
alanb@368 | 1470 | isFastInfosetDisabled = b; |
alanb@368 | 1471 | } |
ohair@286 | 1472 | } |