aoqi@0: /* aoqi@0: * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. aoqi@0: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. aoqi@0: * aoqi@0: * This code is free software; you can redistribute it and/or modify it aoqi@0: * under the terms of the GNU General Public License version 2 only, as aoqi@0: * published by the Free Software Foundation. Oracle designates this aoqi@0: * particular file as subject to the "Classpath" exception as provided aoqi@0: * by Oracle in the LICENSE file that accompanied this code. aoqi@0: * aoqi@0: * This code is distributed in the hope that it will be useful, but WITHOUT aoqi@0: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or aoqi@0: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License aoqi@0: * version 2 for more details (a copy is included in the LICENSE file that aoqi@0: * accompanied this code). aoqi@0: * aoqi@0: * You should have received a copy of the GNU General Public License version aoqi@0: * 2 along with this work; if not, write to the Free Software Foundation, aoqi@0: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. aoqi@0: * aoqi@0: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA aoqi@0: * or visit www.oracle.com if you need additional information or have any aoqi@0: * questions. aoqi@0: */ aoqi@0: aoqi@0: package com.sun.xml.internal.ws.api.message; aoqi@0: aoqi@0: import com.oracle.webservices.internal.api.message.ContentType; aoqi@0: import com.oracle.webservices.internal.api.message.PropertySet; aoqi@0: import com.sun.istack.internal.NotNull; aoqi@0: import com.sun.istack.internal.Nullable; aoqi@0: import com.sun.xml.internal.bind.marshaller.SAX2DOMEx; aoqi@0: import com.sun.xml.internal.ws.addressing.WsaPropertyBag; aoqi@0: import com.sun.xml.internal.ws.addressing.WsaServerTube; aoqi@0: import com.sun.xml.internal.ws.addressing.WsaTubeHelper; aoqi@0: import com.sun.xml.internal.ws.api.Component; aoqi@0: import com.sun.xml.internal.ws.api.EndpointAddress; aoqi@0: import com.sun.xml.internal.ws.api.SOAPVersion; aoqi@0: import com.sun.xml.internal.ws.api.WSBinding; aoqi@0: import com.sun.xml.internal.ws.api.addressing.AddressingVersion; aoqi@0: import com.sun.xml.internal.ws.api.addressing.WSEndpointReference; aoqi@0: import com.sun.xml.internal.ws.api.model.JavaMethod; aoqi@0: import com.sun.xml.internal.ws.api.model.SEIModel; aoqi@0: import com.sun.xml.internal.ws.api.model.WSDLOperationMapping; aoqi@0: import com.sun.xml.internal.ws.api.model.wsdl.WSDLOperation; aoqi@0: import com.sun.xml.internal.ws.api.model.wsdl.WSDLPort; aoqi@0: import com.sun.xml.internal.ws.api.pipe.Codec; aoqi@0: import com.sun.xml.internal.ws.api.pipe.Tube; aoqi@0: import com.sun.xml.internal.ws.api.server.Adapter; aoqi@0: import com.sun.xml.internal.ws.api.server.TransportBackChannel; aoqi@0: import com.sun.xml.internal.ws.api.server.WSEndpoint; aoqi@0: import com.sun.xml.internal.ws.api.server.WebServiceContextDelegate; aoqi@0: import com.sun.xml.internal.ws.api.streaming.XMLStreamWriterFactory; aoqi@0: import com.sun.xml.internal.ws.client.*; aoqi@0: import com.sun.xml.internal.ws.developer.JAXWSProperties; aoqi@0: import com.sun.xml.internal.ws.encoding.MtomCodec; aoqi@0: import com.sun.xml.internal.ws.message.RelatesToHeader; aoqi@0: import com.sun.xml.internal.ws.message.StringHeader; aoqi@0: import com.sun.xml.internal.ws.util.DOMUtil; aoqi@0: import com.sun.xml.internal.ws.util.xml.XmlUtil; aoqi@0: import com.sun.xml.internal.ws.wsdl.DispatchException; aoqi@0: import com.sun.xml.internal.ws.wsdl.OperationDispatcher; aoqi@0: import com.sun.xml.internal.ws.resources.AddressingMessages; aoqi@0: aoqi@0: aoqi@0: import org.w3c.dom.Document; aoqi@0: import org.w3c.dom.Element; aoqi@0: import org.xml.sax.SAXException; aoqi@0: aoqi@0: import javax.xml.namespace.QName; aoqi@0: import javax.xml.soap.SOAPException; aoqi@0: import javax.xml.soap.SOAPMessage; aoqi@0: import javax.xml.stream.XMLStreamWriter; aoqi@0: import javax.xml.stream.XMLStreamException; aoqi@0: import javax.xml.ws.BindingProvider; aoqi@0: import javax.xml.ws.Dispatch; aoqi@0: import javax.xml.ws.WebServiceContext; aoqi@0: import javax.xml.ws.WebServiceException; aoqi@0: import javax.xml.ws.handler.LogicalMessageContext; aoqi@0: import javax.xml.ws.handler.MessageContext; aoqi@0: import javax.xml.ws.handler.soap.SOAPMessageContext; aoqi@0: import javax.xml.ws.soap.MTOMFeature; aoqi@0: aoqi@0: import java.util.*; aoqi@0: import java.util.logging.Logger; aoqi@0: import java.io.ByteArrayOutputStream; aoqi@0: import java.io.IOException; aoqi@0: import java.io.OutputStream; aoqi@0: import java.nio.channels.WritableByteChannel; aoqi@0: aoqi@0: /** aoqi@0: * Represents a container of a {@link Message}. aoqi@0: * aoqi@0: *

What is a {@link Packet}?

aoqi@0: *

aoqi@0: * A packet can be thought of as a frame/envelope/package that wraps aoqi@0: * a {@link Message}. A packet keeps track of optional metadata (properties) aoqi@0: * about a {@link Message} that doesn't go across the wire. aoqi@0: * This roughly corresponds to {@link MessageContext} in the JAX-WS API. aoqi@0: * aoqi@0: *

aoqi@0: * Usually a packet contains a {@link Message} in it, but sometimes aoqi@0: * (such as for a reply of an one-way operation), a packet may aoqi@0: * float around without a {@link Message} in it. aoqi@0: * aoqi@0: * aoqi@0: * aoqi@0: *

Properties

aoqi@0: *

aoqi@0: * Information frequently used inside the JAX-WS RI aoqi@0: * is stored in the strongly-typed fields. Other information is stored aoqi@0: * in terms of a generic {@link Map} (see aoqi@0: * {@link #invocationProperties}.) aoqi@0: * aoqi@0: *

aoqi@0: * Some properties need to be retained between request and response, aoqi@0: * some don't. For strongly typed fields, this characteristic is aoqi@0: * statically known for each of them, and propagation happens accordingly. aoqi@0: * For generic information stored in {@link Map}, {@link #invocationProperties} aoqi@0: * stores per-invocation scope information (which carries over to aoqi@0: * the response.) aoqi@0: * aoqi@0: *

aoqi@0: * This object is used as the backing store of {@link MessageContext}, and aoqi@0: * {@link LogicalMessageContext} and {@link SOAPMessageContext} will aoqi@0: * be delegating to this object for storing/retrieving values. aoqi@0: * aoqi@0: * aoqi@0: *

Relationship to request/response context

aoqi@0: *

aoqi@0: * {@link BindingProvider#getRequestContext() Request context} is used to aoqi@0: * seed the initial values of {@link Packet}. aoqi@0: * Some of those values go to strongly-typed fields, and others go to aoqi@0: * {@link #invocationProperties}, as they need to be retained in the reply message. aoqi@0: * aoqi@0: *

aoqi@0: * Similarly, {@link BindingProvider#getResponseContext() response context} aoqi@0: * is constructed from {@link Packet} (or rather it's just a view of {@link Packet}.) aoqi@0: * by using properties from {@link #invocationProperties}, aoqi@0: * modulo properties named explicitly in {@link #getHandlerScopePropertyNames(boolean)}. aoqi@0: * IOW, properties added to {@link #invocationProperties} aoqi@0: * are exposed to the response context by default. aoqi@0: * aoqi@0: * aoqi@0: * aoqi@0: *

TODO

aoqi@0: *
    aoqi@0: *
  1. this class needs to be cloneable since Message is copiable. aoqi@0: *
  2. The three live views aren't implemented correctly. It will be aoqi@0: * more work to do so, although I'm sure it's possible. aoqi@0: *
  3. {@link PropertySet.Property} annotation is to make it easy aoqi@0: * for {@link MessageContext} to export properties on this object, aoqi@0: * but it probably needs some clean up. aoqi@0: *
aoqi@0: * aoqi@0: * @author Kohsuke Kawaguchi aoqi@0: */ aoqi@0: public final class Packet aoqi@0: // Packet must continue to extend/implement deprecated interfaces until downstream aoqi@0: // usage is updated. aoqi@0: extends com.oracle.webservices.internal.api.message.BaseDistributedPropertySet aoqi@0: implements com.oracle.webservices.internal.api.message.MessageContext, MessageMetadata { aoqi@0: aoqi@0: /** aoqi@0: * Creates a {@link Packet} that wraps a given {@link Message}. aoqi@0: * aoqi@0: *

aoqi@0: * This method should be only used to create a fresh {@link Packet}. aoqi@0: * To create a {@link Packet} for a reply, use {@link #createResponse(Message)}. aoqi@0: * aoqi@0: * @param request aoqi@0: * The request {@link Message}. Can be null. aoqi@0: */ aoqi@0: public Packet(Message request) { aoqi@0: this(); aoqi@0: this.message = request; aoqi@0: if (message != null) message.setMessageMedadata(this); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Creates an empty {@link Packet} that doesn't have any {@link Message}. aoqi@0: */ aoqi@0: public Packet() { aoqi@0: this.invocationProperties = new HashMap(); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Used by {@link #createResponse(Message)} and {@link #copy(boolean)}. aoqi@0: */ aoqi@0: private Packet(Packet that) { aoqi@0: relatePackets(that, true); aoqi@0: this.invocationProperties = that.invocationProperties; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Creates a copy of this {@link Packet}. aoqi@0: * aoqi@0: * @param copyMessage determines whether the {@link Message} from the original {@link Packet} should be copied as aoqi@0: * well, or not. If the value is {@code false}, the {@link Message} in the copy of the {@link Packet} is {@code null}. aoqi@0: * @return copy of the original packet aoqi@0: */ aoqi@0: public Packet copy(boolean copyMessage) { aoqi@0: // the copy constructor is originally designed for creating a response packet, aoqi@0: // but so far the implementation is usable for this purpose as well, so calling the copy constructor aoqi@0: // to avoid code dupliation. aoqi@0: Packet copy = new Packet(this); aoqi@0: if (copyMessage && this.message != null) { aoqi@0: copy.message = this.message.copy(); aoqi@0: } aoqi@0: if (copy.message != null) copy.message.setMessageMedadata(copy); aoqi@0: return copy; aoqi@0: } aoqi@0: aoqi@0: private Message message; aoqi@0: aoqi@0: /** aoqi@0: * Gets the last {@link Message} set through {@link #setMessage(Message)}. aoqi@0: * aoqi@0: * @return may null. See the class javadoc for when it's null. aoqi@0: */ aoqi@0: public Message getMessage() { aoqi@0: if (message != null && !(message instanceof MessageWrapper)) { aoqi@0: message = new MessageWrapper(this, message); aoqi@0: } aoqi@0: return message; aoqi@0: } aoqi@0: aoqi@0: public Message getInternalMessage() { aoqi@0: return (message instanceof MessageWrapper)? ((MessageWrapper)message).delegate : message; aoqi@0: } aoqi@0: aoqi@0: public WSBinding getBinding() { aoqi@0: if (endpoint != null) { aoqi@0: return endpoint.getBinding(); aoqi@0: } aoqi@0: if (proxy != null) { aoqi@0: return (WSBinding) proxy.getBinding(); aoqi@0: } aoqi@0: return null; aoqi@0: } aoqi@0: /** aoqi@0: * Sets a {@link Message} to this packet. aoqi@0: * aoqi@0: * @param message Can be null. aoqi@0: */ aoqi@0: public void setMessage(Message message) { aoqi@0: this.message = message; aoqi@0: if (message != null) this.message.setMessageMedadata(this); aoqi@0: } aoqi@0: aoqi@0: private WSDLOperationMapping wsdlOperationMapping = null; aoqi@0: aoqi@0: private QName wsdlOperation; aoqi@0: aoqi@0: /** aoqi@0: * Returns the QName of the wsdl operation associated with this packet. aoqi@0: *

aoqi@0: * Information such as Payload QName, wsa:Action header, SOAPAction HTTP header are used depending on the features aoqi@0: * enabled on the particular port. aoqi@0: * aoqi@0: * @return null if there is no WSDL model or aoqi@0: * runtime cannot uniquely identify the wsdl operation from the information in the packet. aoqi@0: */ aoqi@0: @Property(MessageContext.WSDL_OPERATION) aoqi@0: public final aoqi@0: @Nullable aoqi@0: QName getWSDLOperation() { aoqi@0: if (wsdlOperation != null) return wsdlOperation; aoqi@0: if ( wsdlOperationMapping == null) wsdlOperationMapping = getWSDLOperationMapping(); aoqi@0: if ( wsdlOperationMapping != null ) wsdlOperation = wsdlOperationMapping.getOperationName(); aoqi@0: return wsdlOperation; aoqi@0: } aoqi@0: aoqi@0: public WSDLOperationMapping getWSDLOperationMapping() { aoqi@0: if (wsdlOperationMapping != null) return wsdlOperationMapping; aoqi@0: OperationDispatcher opDispatcher = null; aoqi@0: if (endpoint != null) { aoqi@0: opDispatcher = endpoint.getOperationDispatcher(); aoqi@0: } else if (proxy != null) { aoqi@0: opDispatcher = ((Stub) proxy).getOperationDispatcher(); aoqi@0: } aoqi@0: //OpDispatcher is null when there is no WSDLModel aoqi@0: if (opDispatcher != null) { aoqi@0: try { aoqi@0: wsdlOperationMapping = opDispatcher.getWSDLOperationMapping(this); aoqi@0: } catch (DispatchException e) { aoqi@0: //Ignore, this might be a protocol message which may not have a wsdl operation aoqi@0: //LOGGER.info("Cannot resolve wsdl operation that this Packet is targeted for."); aoqi@0: } aoqi@0: } aoqi@0: return wsdlOperationMapping; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Set the wsdl operation to avoid lookup from other data. aoqi@0: * This is useful in SEI based clients, where the WSDL operation can be known aoqi@0: * from the associated {@link JavaMethod} aoqi@0: * aoqi@0: * @param wsdlOp QName aoqi@0: */ aoqi@0: public void setWSDLOperation(QName wsdlOp) { aoqi@0: this.wsdlOperation = wsdlOp; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * True if this message came from a transport (IOW inbound), aoqi@0: * and in paricular from a "secure" transport. A transport aoqi@0: * needs to set this flag appropriately. aoqi@0: * aoqi@0: *

aoqi@0: * This is a requirement from the security team. aoqi@0: */ aoqi@0: // TODO: expose this as a property aoqi@0: public boolean wasTransportSecure; aoqi@0: aoqi@0: /** aoqi@0: * Inbound transport headers are captured in a transport neutral way. aoqi@0: * Transports are expected to fill this data after creating a Packet. aoqi@0: *

aoqi@0: * {@link SOAPMessage#getMimeHeaders()} would return these headers. aoqi@0: */ aoqi@0: public static final String INBOUND_TRANSPORT_HEADERS = "com.sun.xml.internal.ws.api.message.packet.inbound.transport.headers"; aoqi@0: aoqi@0: /** aoqi@0: * Outbound transport headers are captured in a transport neutral way. aoqi@0: * aoqi@0: *

aoqi@0: * Transports may choose to ignore certain headers that interfere with aoqi@0: * its correct operation, such as aoqi@0: * Content-Type and Content-Length. aoqi@0: */ aoqi@0: public static final String OUTBOUND_TRANSPORT_HEADERS = "com.sun.xml.internal.ws.api.message.packet.outbound.transport.headers"; aoqi@0: aoqi@0: /** aoqi@0: * aoqi@0: */ aoqi@0: public static final String HA_INFO = "com.sun.xml.internal.ws.api.message.packet.hainfo"; aoqi@0: aoqi@0: aoqi@0: /** aoqi@0: * This property holds the snapshot of HandlerConfiguration aoqi@0: * at the time of invocation. aoqi@0: * This property is used by MUPipe and HandlerPipe implementations. aoqi@0: */ aoqi@0: @Property(BindingProviderProperties.JAXWS_HANDLER_CONFIG) aoqi@0: public HandlerConfiguration handlerConfig; aoqi@0: aoqi@0: /** aoqi@0: * If a message originates from a proxy stub that implements aoqi@0: * a port interface, this field is set to point to that object. aoqi@0: * aoqi@0: * TODO: who's using this property? aoqi@0: */ aoqi@0: @Property(BindingProviderProperties.JAXWS_CLIENT_HANDLE_PROPERTY) aoqi@0: public BindingProvider proxy; aoqi@0: aoqi@0: /** aoqi@0: * Determines if the governing {@link Adapter} or {@link com.sun.xml.internal.ws.api.pipe.Fiber.CompletionCallback} aoqi@0: * will handle delivering response messages targeted at non-anonymous endpoint aoqi@0: * addresses. Prior to the introduction of this flag aoqi@0: * the {@link WsaServerTube} would deliver non-anonymous responses. aoqi@0: */ aoqi@0: public boolean isAdapterDeliversNonAnonymousResponse; aoqi@0: aoqi@0: /** aoqi@0: * During invocation of a client Stub or Dispatch a Packet is aoqi@0: * created then the Stub's RequestContext is copied into the aoqi@0: * Packet. On certain internal cases the Packet is created aoqi@0: * *before* the invocation. In those cases we want the contents aoqi@0: * of the Packet to take precedence when ever any key/value pairs aoqi@0: * collide : if the Packet contains a value for a key use it, aoqi@0: * otherwise copy as usual from Stub. aoqi@0: */ aoqi@0: public boolean packetTakesPriorityOverRequestContext = false; aoqi@0: aoqi@0: /** aoqi@0: * The endpoint address to which this message is sent to. aoqi@0: * aoqi@0: *

aoqi@0: * The JAX-WS spec allows this to be changed for each message, aoqi@0: * so it's designed to be a property. aoqi@0: * aoqi@0: *

aoqi@0: * Must not be null for a request message on the client. Otherwise aoqi@0: * it's null. aoqi@0: */ aoqi@0: public EndpointAddress endpointAddress; aoqi@0: aoqi@0: /** aoqi@0: * @deprecated aoqi@0: * The programatic acccess should be done via aoqi@0: * {@link #endpointAddress}. This is for JAX-WS client applications aoqi@0: * that access this property via {@link BindingProvider#ENDPOINT_ADDRESS_PROPERTY}. aoqi@0: */ aoqi@0: @Property(BindingProvider.ENDPOINT_ADDRESS_PROPERTY) aoqi@0: public String getEndPointAddressString() { aoqi@0: if (endpointAddress == null) { aoqi@0: return null; aoqi@0: } else { aoqi@0: return endpointAddress.toString(); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: public void setEndPointAddressString(String s) { aoqi@0: if (s == null) { aoqi@0: this.endpointAddress = null; aoqi@0: } else { aoqi@0: this.endpointAddress = EndpointAddress.create(s); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * The value of {@link ContentNegotiation#PROPERTY} aoqi@0: * property. aoqi@0: *

aoqi@0: * This property is used only on the client side. aoqi@0: */ aoqi@0: public ContentNegotiation contentNegotiation; aoqi@0: aoqi@0: @Property(ContentNegotiation.PROPERTY) aoqi@0: public String getContentNegotiationString() { aoqi@0: return (contentNegotiation != null) ? contentNegotiation.toString() : null; aoqi@0: } aoqi@0: aoqi@0: public void setContentNegotiationString(String s) { aoqi@0: if (s == null) { aoqi@0: contentNegotiation = null; aoqi@0: } else { aoqi@0: try { aoqi@0: contentNegotiation = ContentNegotiation.valueOf(s); aoqi@0: } catch (IllegalArgumentException e) { aoqi@0: // If the value is not recognized default to none aoqi@0: contentNegotiation = ContentNegotiation.none; aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Gives a list of Reference Parameters in the Message aoqi@0: *

aoqi@0: * Headers which have attribute wsa:IsReferenceParameter="true" aoqi@0: * This is not cached as one may reset the Message. aoqi@0: *

aoqi@0: */ aoqi@0: @Property(MessageContext.REFERENCE_PARAMETERS) aoqi@0: public aoqi@0: @NotNull aoqi@0: List getReferenceParameters() { aoqi@0: Message msg = getMessage(); aoqi@0: List refParams = new ArrayList(); aoqi@0: if (msg == null) { aoqi@0: return refParams; aoqi@0: } aoqi@0: MessageHeaders hl = msg.getHeaders(); aoqi@0: for (Header h : hl.asList()) { aoqi@0: String attr = h.getAttribute(AddressingVersion.W3C.nsUri, "IsReferenceParameter"); aoqi@0: if (attr != null && (attr.equals("true") || attr.equals("1"))) { aoqi@0: Document d = DOMUtil.createDom(); aoqi@0: SAX2DOMEx s2d = new SAX2DOMEx(d); aoqi@0: try { aoqi@0: h.writeTo(s2d, XmlUtil.DRACONIAN_ERROR_HANDLER); aoqi@0: refParams.add((Element) d.getLastChild()); aoqi@0: } catch (SAXException e) { aoqi@0: throw new WebServiceException(e); aoqi@0: } aoqi@0: /* aoqi@0: DOMResult result = new DOMResult(d); aoqi@0: XMLDOMWriterImpl domwriter = new XMLDOMWriterImpl(result); aoqi@0: try { aoqi@0: h.writeTo(domwriter); aoqi@0: refParams.add((Element) result.getNode().getLastChild()); aoqi@0: } catch (XMLStreamException e) { aoqi@0: throw new WebServiceException(e); aoqi@0: } aoqi@0: */ aoqi@0: } aoqi@0: } aoqi@0: return refParams; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * This method is for exposing header list through {@link PropertySet#get(Object)}, aoqi@0: * for user applications, and should never be invoked directly from within the JAX-WS RI. aoqi@0: */ aoqi@0: @Property(JAXWSProperties.INBOUND_HEADER_LIST_PROPERTY) aoqi@0: /*package*/ MessageHeaders getHeaderList() { aoqi@0: Message msg = getMessage(); aoqi@0: if (msg == null) { aoqi@0: return null; aoqi@0: } aoqi@0: return msg.getHeaders(); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * The list of MIME types that are acceptable to a receiver aoqi@0: * of an outbound message. aoqi@0: * aoqi@0: * This property is used only on the server side. aoqi@0: * aoqi@0: *

The representation shall be that specified by the HTTP Accept aoqi@0: * request-header field. aoqi@0: * aoqi@0: *

The list of content types will be obtained from the transport aoqi@0: * meta-data of a inbound message in a request/response message exchange. aoqi@0: * Hence this property will be set by the service-side transport pipe. aoqi@0: */ aoqi@0: public String acceptableMimeTypes; aoqi@0: aoqi@0: /** aoqi@0: * When non-null, this object is consulted to aoqi@0: * implement {@link WebServiceContext} methods aoqi@0: * exposed to the user application. aoqi@0: * aoqi@0: * Used only on the server side. aoqi@0: * aoqi@0: *

aoqi@0: * This property is set from the parameter aoqi@0: * of {@link WSEndpoint.PipeHead#process}. aoqi@0: */ aoqi@0: public WebServiceContextDelegate webServiceContextDelegate; aoqi@0: aoqi@0: /** aoqi@0: * Used only on the server side so that the transport aoqi@0: * can close the connection early. aoqi@0: * aoqi@0: *

aoqi@0: * This field can be null. While a message is being processed, aoqi@0: * this field can be set explicitly to null, to prevent aoqi@0: * future pipes from closing a transport (see {@link #keepTransportBackChannelOpen()}) aoqi@0: * aoqi@0: *

aoqi@0: * This property is set from the parameter aoqi@0: * of {@link WSEndpoint.PipeHead#process}. aoqi@0: */ aoqi@0: public aoqi@0: @Nullable aoqi@0: TransportBackChannel transportBackChannel; aoqi@0: aoqi@0: /** aoqi@0: * Keeps the transport back channel open (by seeting {@link #transportBackChannel} to null.) aoqi@0: * aoqi@0: * @return aoqi@0: * The previous value of {@link #transportBackChannel}. aoqi@0: */ aoqi@0: public TransportBackChannel keepTransportBackChannelOpen() { aoqi@0: TransportBackChannel r = transportBackChannel; aoqi@0: transportBackChannel = null; aoqi@0: return r; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * The governing owner of this packet. On the service-side this is the {@link Adapter} and on the client it is the {@link Stub}. aoqi@0: * aoqi@0: */ aoqi@0: public Component component; aoqi@0: aoqi@0: /** aoqi@0: * The governing {@link WSEndpoint} in which this message is floating. aoqi@0: * aoqi@0: *

aoqi@0: * This property is set if and only if this is on the server side. aoqi@0: */ aoqi@0: @Property(JAXWSProperties.WSENDPOINT) aoqi@0: public WSEndpoint endpoint; aoqi@0: aoqi@0: /** aoqi@0: * The value of the SOAPAction header associated with the message. aoqi@0: * aoqi@0: *

aoqi@0: * For outgoing messages, the transport may sends out this value. aoqi@0: * If this field is null, the transport may choose to send "" aoqi@0: * (quoted empty string.) aoqi@0: * aoqi@0: * For incoming messages, the transport will set this field. aoqi@0: * If the incoming message did not contain the SOAPAction header, aoqi@0: * the transport sets this field to null. aoqi@0: * aoqi@0: *

aoqi@0: * If the value is non-null, it must be always in the quoted form. aoqi@0: * The value can be null. aoqi@0: * aoqi@0: *

aoqi@0: * Note that the way the transport sends this value out depends on aoqi@0: * transport and SOAP version. aoqi@0: *

aoqi@0: * For HTTP transport and SOAP 1.1, BP requires that SOAPAction aoqi@0: * header is present (See {@BP R2744} and {@BP R2745}.) For SOAP 1.2, aoqi@0: * this is moved to the parameter of the "application/soap+xml". aoqi@0: */ aoqi@0: @Property(BindingProvider.SOAPACTION_URI_PROPERTY) aoqi@0: public String soapAction; aoqi@0: aoqi@0: /** aoqi@0: * A hint indicating that whether a transport should expect aoqi@0: * a reply back from the server. aoqi@0: * aoqi@0: *

aoqi@0: * This property is used on the client-side for aoqi@0: * outbound messages, so that a pipeline aoqi@0: * can communicate to the terminal (or intermediate) {@link Tube}s aoqi@0: * about this knowledge. aoqi@0: * aoqi@0: *

aoqi@0: * This property MUST NOT be used by 2-way transports aoqi@0: * that have the transport back channel. Those transports aoqi@0: * must always check a reply coming through the transport back aoqi@0: * channel regardless of this value, and act accordingly. aoqi@0: * (This is because the expectation of the client and aoqi@0: * that of the server can be different, for example because aoqi@0: * of a bug in user's configuration.) aoqi@0: * aoqi@0: *

aoqi@0: * This property is for one-way transports, and more aoqi@0: * specifically for the coordinator that correlates sent requests aoqi@0: * and incoming replies, to decide whether to block aoqi@0: * until a response is received. aoqi@0: * aoqi@0: *

aoqi@0: * Also note that this property is related to aoqi@0: * {@link WSDLOperation#isOneWay()} but not the same thing. aoqi@0: * In fact in general, they are completely orthogonal. aoqi@0: * aoqi@0: * For example, the calling application can choose to invoke aoqi@0: * {@link Dispatch#invoke(Object)} or {@link Dispatch#invokeOneWay(Object)} aoqi@0: * with an operation (which determines the value of this property), aoqi@0: * regardless of whether WSDL actually says it's one way or not. aoqi@0: * So these two booleans can take any combinations. aoqi@0: * aoqi@0: * aoqi@0: *

aoqi@0: * When this property is {@link Boolean#FALSE}, it means that aoqi@0: * the pipeline does not expect a reply from a server (and therefore aoqi@0: * the correlator should not block for a reply message aoqi@0: * -- if such a reply does arrive, it can be just ignored.) aoqi@0: * aoqi@0: *

aoqi@0: * When this property is {@link Boolean#TRUE}, it means that aoqi@0: * the pipeline expects a reply from a server (and therefore aoqi@0: * the correlator should block to see if a reply message is received, aoqi@0: * aoqi@0: *

aoqi@0: * This property is always set to {@link Boolean#TRUE} or aoqi@0: * {@link Boolean#FALSE} when used on the request message aoqi@0: * on the client side. aoqi@0: * No other {@link Boolean} instances are allowed. aoqi@0: *

aoqi@0: * aoqi@0: * In all other situations, this property is null. aoqi@0: * aoqi@0: */ aoqi@0: @Property(BindingProviderProperties.ONE_WAY_OPERATION) aoqi@0: public Boolean expectReply; aoqi@0: aoqi@0: aoqi@0: /** aoqi@0: * This property will be removed in a near future. aoqi@0: * aoqi@0: *

aoqi@0: * A part of what this flag represented moved to aoqi@0: * {@link #expectReply} and the other part was moved aoqi@0: * to {@link Message#isOneWay(WSDLPort)}. Please update aoqi@0: * your code soon, or risk breaking your build!! aoqi@0: */ aoqi@0: @Deprecated aoqi@0: public Boolean isOneWay; aoqi@0: aoqi@0: /** aoqi@0: * Indicates whether is invoking a synchronous pattern. If true, no aoqi@0: * async client programming model (e.g. AsyncResponse or AsyncHandler) aoqi@0: * were used to make the request that created this packet. aoqi@0: */ aoqi@0: public Boolean isSynchronousMEP; aoqi@0: aoqi@0: /** aoqi@0: * Indicates whether a non-null AsyncHandler was given at the point of aoqi@0: * making the request that created this packet. This flag can be used aoqi@0: * by Tube implementations to decide how to react when isSynchronousMEP aoqi@0: * is false. If true, the client gave a non-null AsyncHandler instance aoqi@0: * at the point of request, and will be expecting a response on that aoqi@0: * handler when this request has been processed. aoqi@0: */ aoqi@0: public Boolean nonNullAsyncHandlerGiven; aoqi@0: aoqi@0: /** aoqi@0: * USE-CASE: aoqi@0: * WS-AT is enabled, but there is no WSDL available. aoqi@0: * If Packet.isRequestReplyMEP() is Boolean.TRUE then WS-AT should aoqi@0: * add the TX context. aoqi@0: * aoqi@0: * This value is exposed to users via facades at higher abstraction layers. aoqi@0: * The user should NEVER use Packet directly. aoqi@0: * This value should ONLY be set by users. aoqi@0: */ aoqi@0: private Boolean isRequestReplyMEP; aoqi@0: public Boolean isRequestReplyMEP() { return isRequestReplyMEP; } aoqi@0: public void setRequestReplyMEP(final Boolean x) { isRequestReplyMEP = x; } aoqi@0: aoqi@0: /** aoqi@0: * Lazily created set of handler-scope property names. aoqi@0: * aoqi@0: *

aoqi@0: * We expect that this is only used when handlers are present aoqi@0: * and they explicitly set some handler-scope values. aoqi@0: * aoqi@0: * @see #getHandlerScopePropertyNames(boolean) aoqi@0: */ aoqi@0: private Set handlerScopePropertyNames; aoqi@0: aoqi@0: /** aoqi@0: * Bag to capture properties that are available for the whole aoqi@0: * message invocation (namely on both requests and responses.) aoqi@0: * aoqi@0: *

aoqi@0: * These properties are copied from a request to a response. aoqi@0: * This is where we keep properties that are set by handlers. aoqi@0: * aoqi@0: *

aoqi@0: * See class javadoc for more discussion. aoqi@0: * aoqi@0: * @see #getHandlerScopePropertyNames(boolean) aoqi@0: */ aoqi@0: public final Map invocationProperties; aoqi@0: aoqi@0: /** aoqi@0: * Gets a {@link Set} that stores handler-scope properties. aoqi@0: * aoqi@0: *

aoqi@0: * These properties will not be exposed to the response context. aoqi@0: * Consequently, if a {@link Tube} wishes to hide a property aoqi@0: * to {@link ResponseContext}, it needs to add the property name aoqi@0: * to this set. aoqi@0: * aoqi@0: * @param readOnly aoqi@0: * Return true if the caller only intends to read the value of this set. aoqi@0: * Internally, the {@link Set} is allocated lazily, and this flag helps aoqi@0: * optimizing the strategy. aoqi@0: * aoqi@0: * @return aoqi@0: * always non-null, possibly empty set that stores property names. aoqi@0: */ aoqi@0: public final Set getHandlerScopePropertyNames(boolean readOnly) { aoqi@0: Set o = this.handlerScopePropertyNames; aoqi@0: if (o == null) { aoqi@0: if (readOnly) { aoqi@0: return Collections.emptySet(); aoqi@0: } aoqi@0: o = new HashSet(); aoqi@0: this.handlerScopePropertyNames = o; aoqi@0: } aoqi@0: return o; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * This method no longer works. aoqi@0: * aoqi@0: * @deprecated aoqi@0: * Use {@link #getHandlerScopePropertyNames(boolean)}. aoqi@0: * To be removed once Tango components are updated. aoqi@0: */ aoqi@0: public final Set getApplicationScopePropertyNames(boolean readOnly) { aoqi@0: assert false; aoqi@0: return new HashSet(); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Creates a response {@link Packet} from a request packet ({@code this}). aoqi@0: * aoqi@0: *

aoqi@0: * When a {@link Packet} for a reply is created, some properties need to be aoqi@0: * copied over from a request to a response, and this method handles it correctly. aoqi@0: * aoqi@0: * @deprecated aoqi@0: * Use createClientResponse(Message) for client side and aoqi@0: * createServerResponse(Message, String) for server side response aoqi@0: * creation. aoqi@0: * aoqi@0: * @param msg aoqi@0: * The {@link Message} that represents a reply. Can be null. aoqi@0: */ aoqi@0: @Deprecated aoqi@0: public Packet createResponse(Message msg) { aoqi@0: Packet response = new Packet(this); aoqi@0: response.setMessage(msg); aoqi@0: return response; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Creates a response {@link Packet} from a request packet ({@code this}). aoqi@0: * aoqi@0: *

aoqi@0: * When a {@link Packet} for a reply is created, some properties need to be aoqi@0: * copied over from a request to a response, and this method handles it correctly. aoqi@0: * aoqi@0: * @param msg aoqi@0: * The {@link Message} that represents a reply. Can be null. aoqi@0: */ aoqi@0: public Packet createClientResponse(Message msg) { aoqi@0: Packet response = new Packet(this); aoqi@0: response.setMessage(msg); aoqi@0: finishCreateRelateClientResponse(response); aoqi@0: return response; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * For use cases that start with an existing Packet. aoqi@0: */ aoqi@0: public Packet relateClientResponse(final Packet response) { aoqi@0: response.relatePackets(this, true); aoqi@0: finishCreateRelateClientResponse(response); aoqi@0: return response; aoqi@0: } aoqi@0: aoqi@0: private void finishCreateRelateClientResponse(final Packet response) { aoqi@0: response.soapAction = null; // de-initializing aoqi@0: response.setState(State.ClientResponse); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Creates a server-side response {@link Packet} from a request aoqi@0: * packet ({@code this}). If WS-Addressing is enabled, a default Action aoqi@0: * Message Addressing Property is obtained using wsdlPort {@link WSDLPort} aoqi@0: * and binding {@link WSBinding}. aoqi@0: *

aoqi@0: * This method should be called to create application response messages aoqi@0: * since they are associated with a {@link WSBinding} and {@link WSDLPort}. aoqi@0: * For creating protocol messages that require a non-default Action, use aoqi@0: * {@link #createServerResponse(Message, com.sun.xml.internal.ws.api.addressing.AddressingVersion, com.sun.xml.internal.ws.api.SOAPVersion, String)}. aoqi@0: * aoqi@0: * @param responseMessage The {@link Message} that represents a reply. Can be null. aoqi@0: * @param wsdlPort The response WSDL port. aoqi@0: * @param binding The response Binding. Cannot be null. aoqi@0: * @return response packet aoqi@0: */ aoqi@0: public Packet createServerResponse(@Nullable Message responseMessage, @Nullable WSDLPort wsdlPort, @Nullable SEIModel seiModel, @NotNull WSBinding binding) { aoqi@0: Packet r = createClientResponse(responseMessage); aoqi@0: return relateServerResponse(r, wsdlPort, seiModel, binding); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Copy all properties from ({@code this}) packet into a input {@link Packet} aoqi@0: * @param response packet aoqi@0: */ aoqi@0: public void copyPropertiesTo(@Nullable Packet response){ aoqi@0: relatePackets(response, false); aoqi@0: } aoqi@0: aoqi@0: aoqi@0: /** aoqi@0: * A common method to make members related between input packet and this packet aoqi@0: * aoqi@0: * @param packet aoqi@0: * @param isCopy 'true' means copying all properties from input packet; aoqi@0: * 'false' means copying all properties from this packet to input packet. aoqi@0: */ aoqi@0: private void relatePackets(@Nullable Packet packet, boolean isCopy) aoqi@0: { aoqi@0: Packet request; aoqi@0: Packet response; aoqi@0: aoqi@0: if (!isCopy) { //is relate aoqi@0: request = this; aoqi@0: response = packet; aoqi@0: aoqi@0: // processing specific properties aoqi@0: response.soapAction = null; aoqi@0: response.invocationProperties.putAll(request.invocationProperties); aoqi@0: if (this.getState().equals(State.ServerRequest)) { aoqi@0: response.setState(State.ServerResponse); aoqi@0: } aoqi@0: } else { //is copy constructor aoqi@0: request = packet; aoqi@0: response = this; aoqi@0: aoqi@0: // processing specific properties aoqi@0: response.soapAction = request.soapAction; aoqi@0: response.setState(request.getState()); aoqi@0: } aoqi@0: aoqi@0: request.copySatelliteInto(response); aoqi@0: response.isAdapterDeliversNonAnonymousResponse = request.isAdapterDeliversNonAnonymousResponse; aoqi@0: response.handlerConfig = request.handlerConfig; aoqi@0: response.handlerScopePropertyNames = request.handlerScopePropertyNames; aoqi@0: response.contentNegotiation = request.contentNegotiation; aoqi@0: response.wasTransportSecure = request.wasTransportSecure; aoqi@0: response.transportBackChannel = request.transportBackChannel; aoqi@0: response.endpointAddress = request.endpointAddress; aoqi@0: response.wsdlOperation = request.wsdlOperation; aoqi@0: response.wsdlOperationMapping = request.wsdlOperationMapping; aoqi@0: response.acceptableMimeTypes = request.acceptableMimeTypes; aoqi@0: response.endpoint = request.endpoint; aoqi@0: response.proxy = request.proxy; aoqi@0: response.webServiceContextDelegate = request.webServiceContextDelegate; aoqi@0: response.expectReply = request.expectReply; aoqi@0: response.component = request.component; aoqi@0: response.mtomAcceptable = request.mtomAcceptable; aoqi@0: response.mtomRequest = request.mtomRequest; aoqi@0: // copy other properties that need to be copied. is there any? aoqi@0: } aoqi@0: aoqi@0: aoqi@0: public Packet relateServerResponse(@Nullable Packet r, @Nullable WSDLPort wsdlPort, @Nullable SEIModel seiModel, @NotNull WSBinding binding) { aoqi@0: relatePackets(r, false); aoqi@0: r.setState(State.ServerResponse); aoqi@0: AddressingVersion av = binding.getAddressingVersion(); aoqi@0: // populate WS-A headers only if WS-A is enabled aoqi@0: if (av == null) { aoqi@0: return r; aoqi@0: } aoqi@0: aoqi@0: if (getMessage() == null) { aoqi@0: return r; aoqi@0: } aoqi@0: aoqi@0: //populate WS-A headers only if the request has addressing headers aoqi@0: String inputAction = AddressingUtils.getAction(getMessage().getHeaders(), av, binding.getSOAPVersion()); aoqi@0: if (inputAction == null) { aoqi@0: return r; aoqi@0: } aoqi@0: // if one-way, then dont populate any WS-A headers aoqi@0: if (r.getMessage() == null || (wsdlPort != null && getMessage().isOneWay(wsdlPort))) { aoqi@0: return r; aoqi@0: } aoqi@0: aoqi@0: // otherwise populate WS-Addressing headers aoqi@0: populateAddressingHeaders(binding, r, wsdlPort, seiModel); aoqi@0: return r; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Creates a server-side response {@link Packet} from a request aoqi@0: * packet ({@code this}). If WS-Addressing is enabled, action aoqi@0: * is used as Action Message Addressing Property. aoqi@0: *

aoqi@0: * This method should be called only for creating protocol response messages aoqi@0: * that require a particular value of Action since they are not associated aoqi@0: * with a {@link WSBinding} and {@link WSDLPort} but do know the {@link AddressingVersion} aoqi@0: * and {@link SOAPVersion}. aoqi@0: * aoqi@0: * @param responseMessage The {@link Message} that represents a reply. Can be null. aoqi@0: * @param addressingVersion The WS-Addressing version of the response message. aoqi@0: * @param soapVersion The SOAP version of the response message. aoqi@0: * @param action The response Action Message Addressing Property value. aoqi@0: * @return response packet aoqi@0: */ aoqi@0: public Packet createServerResponse(@Nullable Message responseMessage, @NotNull AddressingVersion addressingVersion, @NotNull SOAPVersion soapVersion, @NotNull String action) { aoqi@0: Packet responsePacket = createClientResponse(responseMessage); aoqi@0: responsePacket.setState(State.ServerResponse); aoqi@0: // populate WS-A headers only if WS-A is enabled aoqi@0: if (addressingVersion == null) { aoqi@0: return responsePacket; aoqi@0: } aoqi@0: //populate WS-A headers only if the request has addressing headers aoqi@0: String inputAction = AddressingUtils.getAction(this.getMessage().getHeaders(), addressingVersion, soapVersion); aoqi@0: if (inputAction == null) { aoqi@0: return responsePacket; aoqi@0: } aoqi@0: aoqi@0: populateAddressingHeaders(responsePacket, addressingVersion, soapVersion, action, false); aoqi@0: return responsePacket; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Overwrites the {@link Message} of the response packet ({@code this}) by the given {@link Message}. aoqi@0: * Unlike {@link #setMessage(Message)}, fill in the addressing headers correctly, and this process aoqi@0: * requires the access to the request packet. aoqi@0: * aoqi@0: *

aoqi@0: * This method is useful when the caller needs to swap a response message completely to a new one. aoqi@0: * aoqi@0: * @see #createServerResponse(Message, AddressingVersion, SOAPVersion, String) aoqi@0: */ aoqi@0: public void setResponseMessage(@NotNull Packet request, @Nullable Message responseMessage, @NotNull AddressingVersion addressingVersion, @NotNull SOAPVersion soapVersion, @NotNull String action) { aoqi@0: Packet temp = request.createServerResponse(responseMessage, addressingVersion, soapVersion, action); aoqi@0: setMessage(temp.getMessage()); aoqi@0: } aoqi@0: aoqi@0: private void populateAddressingHeaders(Packet responsePacket, AddressingVersion av, SOAPVersion sv, String action, boolean mustUnderstand) { aoqi@0: // populate WS-A headers only if WS-A is enabled aoqi@0: if (av == null) return; aoqi@0: aoqi@0: // if one-way, then dont populate any WS-A headers aoqi@0: if (responsePacket.getMessage() == null) aoqi@0: return; aoqi@0: aoqi@0: MessageHeaders hl = responsePacket.getMessage().getHeaders(); aoqi@0: aoqi@0: WsaPropertyBag wpb = getSatellite(WsaPropertyBag.class); aoqi@0: Message msg = getMessage(); aoqi@0: // wsa:To aoqi@0: WSEndpointReference replyTo = null; aoqi@0: Header replyToFromRequestMsg = AddressingUtils.getFirstHeader(msg.getHeaders(), av.replyToTag, true, sv); aoqi@0: Header replyToFromResponseMsg = hl.get(av.toTag, false); aoqi@0: boolean replaceToTag = true; aoqi@0: try{ aoqi@0: if (replyToFromRequestMsg != null){ aoqi@0: replyTo = replyToFromRequestMsg.readAsEPR(av); aoqi@0: } aoqi@0: if (replyToFromResponseMsg != null && replyTo == null) { aoqi@0: replaceToTag = false; aoqi@0: } aoqi@0: } catch (XMLStreamException e) { aoqi@0: throw new WebServiceException(AddressingMessages.REPLY_TO_CANNOT_PARSE(), e); aoqi@0: } aoqi@0: if (replyTo == null) { aoqi@0: replyTo = AddressingUtils.getReplyTo(msg.getHeaders(), av, sv); aoqi@0: } aoqi@0: aoqi@0: // wsa:Action, add if the message doesn't already contain it, aoqi@0: // generally true for SEI case where there is SEIModel or WSDLModel aoqi@0: // false for Provider with no wsdl, Expects User to set the coresponding header on the Message. aoqi@0: if (AddressingUtils.getAction(responsePacket.getMessage().getHeaders(), av, sv) == null) { aoqi@0: //wsa:Action header is not set in the message, so use the wsa:Action passed as the parameter. aoqi@0: hl.add(new StringHeader(av.actionTag, action, sv, mustUnderstand)); aoqi@0: } aoqi@0: aoqi@0: // wsa:MessageID aoqi@0: if (responsePacket.getMessage().getHeaders().get(av.messageIDTag, false) == null) { aoqi@0: // if header doesn't exist, method getID creates a new random id aoqi@0: String newID = Message.generateMessageID(); aoqi@0: hl.add(new StringHeader(av.messageIDTag, newID)); aoqi@0: } aoqi@0: aoqi@0: // wsa:RelatesTo aoqi@0: String mid = null; aoqi@0: if (wpb != null) { aoqi@0: mid = wpb.getMessageID(); aoqi@0: } aoqi@0: if (mid == null) { aoqi@0: mid = AddressingUtils.getMessageID(msg.getHeaders(), av, sv); aoqi@0: } aoqi@0: if (mid != null) { aoqi@0: hl.addOrReplace(new RelatesToHeader(av.relatesToTag, mid)); aoqi@0: } aoqi@0: aoqi@0: aoqi@0: // populate reference parameters aoqi@0: WSEndpointReference refpEPR = null; aoqi@0: if (responsePacket.getMessage().isFault()) { aoqi@0: // choose FaultTo aoqi@0: if (wpb != null) { aoqi@0: refpEPR = wpb.getFaultToFromRequest(); aoqi@0: } aoqi@0: if (refpEPR == null) { aoqi@0: refpEPR = AddressingUtils.getFaultTo(msg.getHeaders(), av, sv); aoqi@0: } aoqi@0: // if FaultTo is null, then use ReplyTo aoqi@0: if (refpEPR == null) { aoqi@0: refpEPR = replyTo; aoqi@0: } aoqi@0: } else { aoqi@0: // choose ReplyTo aoqi@0: refpEPR = replyTo; aoqi@0: } aoqi@0: if (replaceToTag && refpEPR != null) { aoqi@0: hl.addOrReplace(new StringHeader(av.toTag, refpEPR.getAddress())); aoqi@0: refpEPR.addReferenceParametersToList(hl); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: private void populateAddressingHeaders(WSBinding binding, Packet responsePacket, WSDLPort wsdlPort, SEIModel seiModel) { aoqi@0: AddressingVersion addressingVersion = binding.getAddressingVersion(); aoqi@0: aoqi@0: if (addressingVersion == null) { aoqi@0: return; aoqi@0: } aoqi@0: aoqi@0: WsaTubeHelper wsaHelper = addressingVersion.getWsaHelper(wsdlPort, seiModel, binding); aoqi@0: String action = responsePacket.getMessage().isFault() ? aoqi@0: wsaHelper.getFaultAction(this, responsePacket) : aoqi@0: wsaHelper.getOutputAction(this); aoqi@0: if (action == null) { aoqi@0: LOGGER.info("WSA headers are not added as value for wsa:Action cannot be resolved for this message"); aoqi@0: return; aoqi@0: } aoqi@0: populateAddressingHeaders(responsePacket, addressingVersion, binding.getSOAPVersion(), action, AddressingVersion.isRequired(binding)); aoqi@0: } aoqi@0: aoqi@0: public String toShortString() { aoqi@0: return super.toString(); aoqi@0: } aoqi@0: aoqi@0: // For use only in a debugger aoqi@0: @Override aoqi@0: public String toString() { aoqi@0: StringBuilder buf = new StringBuilder(); aoqi@0: buf.append(super.toString()); aoqi@0: String content; aoqi@0: try { aoqi@0: Message msg = getMessage(); aoqi@0: if (msg != null) { aoqi@0: ByteArrayOutputStream baos = new ByteArrayOutputStream(); aoqi@0: XMLStreamWriter xmlWriter = XMLStreamWriterFactory.create(baos, "UTF-8"); aoqi@0: msg.copy().writeTo(xmlWriter); aoqi@0: xmlWriter.flush(); aoqi@0: xmlWriter.close(); aoqi@0: baos.flush(); aoqi@0: XMLStreamWriterFactory.recycle(xmlWriter); aoqi@0: aoqi@0: byte[] bytes = baos.toByteArray(); aoqi@0: //message = Messages.create(XMLStreamReaderFactory.create(null, new ByteArrayInputStream(bytes), "UTF-8", true)); aoqi@0: content = new String(bytes, "UTF-8"); aoqi@0: } else { aoqi@0: content = ""; aoqi@0: } aoqi@0: } catch (Throwable t) { aoqi@0: throw new WebServiceException(t); aoqi@0: } aoqi@0: buf.append(" Content: ").append(content); aoqi@0: return buf.toString(); aoqi@0: } aoqi@0: aoqi@0: // completes TypedMap aoqi@0: private static final PropertyMap model; aoqi@0: aoqi@0: static { aoqi@0: model = parse(Packet.class); aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: protected PropertyMap getPropertyMap() { aoqi@0: return model; aoqi@0: } aoqi@0: aoqi@0: public Map asMapIncludingInvocationProperties() { aoqi@0: final Map asMap = asMap(); aoqi@0: return new AbstractMap() { aoqi@0: @Override aoqi@0: public Object get(Object key) { aoqi@0: Object o = asMap.get(key); aoqi@0: if (o != null) aoqi@0: return o; aoqi@0: aoqi@0: return invocationProperties.get(key); aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public int size() { aoqi@0: return asMap.size() + invocationProperties.size(); aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public boolean containsKey(Object key) { aoqi@0: if (asMap.containsKey(key)) aoqi@0: return true; aoqi@0: return invocationProperties.containsKey(key); aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public Set> entrySet() { aoqi@0: final Set> asMapEntries = asMap.entrySet(); aoqi@0: final Set> ipEntries = invocationProperties.entrySet(); aoqi@0: aoqi@0: return new AbstractSet>() { aoqi@0: @Override aoqi@0: public Iterator> iterator() { aoqi@0: final Iterator> asMapIt = asMapEntries.iterator(); aoqi@0: final Iterator> ipIt = ipEntries.iterator(); aoqi@0: aoqi@0: return new Iterator>() { aoqi@0: @Override aoqi@0: public boolean hasNext() { aoqi@0: return asMapIt.hasNext() || ipIt.hasNext(); aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public java.util.Map.Entry next() { aoqi@0: if (asMapIt.hasNext()) aoqi@0: return asMapIt.next(); aoqi@0: return ipIt.next(); aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public void remove() { aoqi@0: throw new UnsupportedOperationException(); aoqi@0: } aoqi@0: }; aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public int size() { aoqi@0: return asMap.size() + invocationProperties.size(); aoqi@0: } aoqi@0: }; aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public Object put(String key, Object value) { aoqi@0: if (supports(key)) aoqi@0: return asMap.put(key, value); aoqi@0: aoqi@0: return invocationProperties.put(key, value); aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public void clear() { aoqi@0: asMap.clear(); aoqi@0: invocationProperties.clear(); aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public Object remove(Object key) { aoqi@0: if (supports(key)) aoqi@0: return asMap.remove(key); aoqi@0: aoqi@0: return invocationProperties.remove(key); aoqi@0: } aoqi@0: }; aoqi@0: } aoqi@0: aoqi@0: private static final Logger LOGGER = Logger.getLogger(Packet.class.getName()); aoqi@0: aoqi@0: @Override aoqi@0: public SOAPMessage getSOAPMessage() throws SOAPException { aoqi@0: return getAsSOAPMessage(); aoqi@0: } aoqi@0: aoqi@0: //TODO replace the message to a SAAJMEssage issue - JRFSAAJMessage or SAAJMessage? aoqi@0: @Override aoqi@0: public SOAPMessage getAsSOAPMessage() throws SOAPException { aoqi@0: Message msg = this.getMessage(); aoqi@0: if (msg == null) aoqi@0: return null; aoqi@0: if (msg instanceof MessageWritable) aoqi@0: ((MessageWritable) msg).setMTOMConfiguration(mtomFeature); aoqi@0: return msg.readAsSOAPMessage(this, this.getState().isInbound()); aoqi@0: } aoqi@0: aoqi@0: public aoqi@0: Codec codec = null; aoqi@0: public Codec getCodec() { aoqi@0: if (codec != null) { aoqi@0: return codec; aoqi@0: } aoqi@0: if (endpoint != null) { aoqi@0: codec = endpoint.createCodec(); aoqi@0: } aoqi@0: WSBinding wsb = getBinding(); aoqi@0: if (wsb != null) { aoqi@0: codec = wsb.getBindingId().createEncoder(wsb); aoqi@0: } aoqi@0: return codec; aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public com.oracle.webservices.internal.api.message.ContentType writeTo( OutputStream out ) throws IOException { aoqi@0: Message msg = getInternalMessage(); aoqi@0: if (msg instanceof MessageWritable) { aoqi@0: ((MessageWritable) msg).setMTOMConfiguration(mtomFeature); aoqi@0: return ((MessageWritable)msg).writeTo(out); aoqi@0: } aoqi@0: return getCodec().encode(this, out); aoqi@0: } aoqi@0: aoqi@0: public com.oracle.webservices.internal.api.message.ContentType writeTo( WritableByteChannel buffer ) { aoqi@0: return getCodec().encode(this, buffer); aoqi@0: } aoqi@0: aoqi@0: private ContentType contentType; aoqi@0: aoqi@0: /** aoqi@0: * If the request's Content-Type is multipart/related; type=application/xop+xml, then this set to to true aoqi@0: * aoqi@0: * Used on server-side, for encoding the repsonse. aoqi@0: */ aoqi@0: private Boolean mtomRequest; aoqi@0: aoqi@0: /** aoqi@0: * Based on request's Accept header this is set. aoqi@0: * Currently only set if MTOMFeature is enabled. aoqi@0: * aoqi@0: * Should be used on server-side, for encoding the response. aoqi@0: */ aoqi@0: private Boolean mtomAcceptable; aoqi@0: aoqi@0: private MTOMFeature mtomFeature; aoqi@0: aoqi@0: public Boolean getMtomRequest() { aoqi@0: return mtomRequest; aoqi@0: } aoqi@0: aoqi@0: public void setMtomRequest(Boolean mtomRequest) { aoqi@0: this.mtomRequest = mtomRequest; aoqi@0: } aoqi@0: aoqi@0: public Boolean getMtomAcceptable() { aoqi@0: return mtomAcceptable; aoqi@0: } aoqi@0: aoqi@0: Boolean checkMtomAcceptable; aoqi@0: public void checkMtomAcceptable() { aoqi@0: if (checkMtomAcceptable == null) { aoqi@0: if (acceptableMimeTypes == null || isFastInfosetDisabled) { aoqi@0: checkMtomAcceptable = false; aoqi@0: } else { aoqi@0: checkMtomAcceptable = (acceptableMimeTypes.indexOf(MtomCodec.XOP_XML_MIME_TYPE) != -1); aoqi@0: // StringTokenizer st = new StringTokenizer(acceptableMimeTypes, ","); aoqi@0: // while (st.hasMoreTokens()) { aoqi@0: // final String token = st.nextToken().trim(); aoqi@0: // if (token.toLowerCase().contains(MtomCodec.XOP_XML_MIME_TYPE)) { aoqi@0: // mtomAcceptable = true; aoqi@0: // } aoqi@0: // } aoqi@0: // if (mtomAcceptable == null) mtomAcceptable = false; aoqi@0: } aoqi@0: } aoqi@0: mtomAcceptable = checkMtomAcceptable; aoqi@0: } aoqi@0: aoqi@0: private Boolean fastInfosetAcceptable; aoqi@0: aoqi@0: public Boolean getFastInfosetAcceptable(String fiMimeType) { aoqi@0: if (fastInfosetAcceptable == null) { aoqi@0: if (acceptableMimeTypes == null || isFastInfosetDisabled) { aoqi@0: fastInfosetAcceptable = false; aoqi@0: } else { aoqi@0: fastInfosetAcceptable = (acceptableMimeTypes.indexOf(fiMimeType) != -1); aoqi@0: } aoqi@0: // if (accept == null || isFastInfosetDisabled) return false; aoqi@0: // aoqi@0: // StringTokenizer st = new StringTokenizer(accept, ","); aoqi@0: // while (st.hasMoreTokens()) { aoqi@0: // final String token = st.nextToken().trim(); aoqi@0: // if (token.equalsIgnoreCase(fiMimeType)) { aoqi@0: // return true; aoqi@0: // } aoqi@0: // } aoqi@0: // return false; aoqi@0: } aoqi@0: return fastInfosetAcceptable; aoqi@0: } aoqi@0: aoqi@0: aoqi@0: public void setMtomFeature(MTOMFeature mtomFeature) { aoqi@0: this.mtomFeature = mtomFeature; aoqi@0: } aoqi@0: aoqi@0: public MTOMFeature getMtomFeature() { aoqi@0: //If we have a binding, use that in preference to an explicitly aoqi@0: //set MTOMFeature aoqi@0: WSBinding binding = getBinding(); aoqi@0: if (binding != null) { aoqi@0: return binding.getFeature(MTOMFeature.class); aoqi@0: } aoqi@0: return mtomFeature; aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public com.oracle.webservices.internal.api.message.ContentType getContentType() { aoqi@0: if (contentType == null) { aoqi@0: contentType = getInternalContentType(); aoqi@0: } aoqi@0: if (contentType == null) { aoqi@0: contentType = getCodec().getStaticContentType(this); aoqi@0: } aoqi@0: if (contentType == null) { aoqi@0: //TODO write to buffer aoqi@0: } aoqi@0: return contentType; aoqi@0: } aoqi@0: aoqi@0: public ContentType getInternalContentType() { aoqi@0: Message msg = getInternalMessage(); aoqi@0: if (msg instanceof MessageWritable) { aoqi@0: return ((MessageWritable)msg).getContentType(); aoqi@0: } aoqi@0: return contentType; aoqi@0: } aoqi@0: aoqi@0: public void setContentType(ContentType contentType) { aoqi@0: this.contentType = contentType; aoqi@0: } aoqi@0: aoqi@0: public enum Status { aoqi@0: Request, Response, Unknown; aoqi@0: public boolean isRequest() { return Request.equals(this); } aoqi@0: public boolean isResponse() { return Response.equals(this); } aoqi@0: } aoqi@0: aoqi@0: public enum State { aoqi@0: ServerRequest(true), ClientRequest(false), ServerResponse(false), ClientResponse(true); aoqi@0: private boolean inbound; aoqi@0: State(boolean inbound) { aoqi@0: this.inbound = inbound; aoqi@0: } aoqi@0: public boolean isInbound() { aoqi@0: return inbound; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // private Status status = Status.Unknown; aoqi@0: aoqi@0: //Default state is ServerRequest - some custom adapters may not set the value of state aoqi@0: //upon server request - all other code paths should set it aoqi@0: private State state = State.ServerRequest; aoqi@0: aoqi@0: // public Status getStatus() { return status; } aoqi@0: aoqi@0: public State getState() { return state; } aoqi@0: public void setState(State state) { this.state = state; } aoqi@0: aoqi@0: public boolean shouldUseMtom() { aoqi@0: if (getState().isInbound()) { aoqi@0: return isMtomContentType(); aoqi@0: } else { aoqi@0: return shouldUseMtomOutbound(); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: private boolean shouldUseMtomOutbound() { aoqi@0: //Use the getter to make sure all the logic is executed correctly aoqi@0: MTOMFeature myMtomFeature = getMtomFeature(); aoqi@0: if(myMtomFeature != null && myMtomFeature.isEnabled()) { aoqi@0: //On client, always use XOP encoding if MTOM is enabled aoqi@0: //On Server, mtomAcceptable and mtomRequest will be set - use XOP encoding aoqi@0: //if either request is XOP encoded (mtomRequest) or aoqi@0: //client accepts XOP encoding (mtomAcceptable) aoqi@0: if (getMtomAcceptable() == null && getMtomRequest() == null) { aoqi@0: return true; aoqi@0: } else { aoqi@0: if (getMtomAcceptable() != null && getMtomAcceptable() && getState().equals(State.ServerResponse)) { aoqi@0: return true; aoqi@0: } aoqi@0: if (getMtomRequest() != null && getMtomRequest() && getState().equals(State.ServerResponse)) { aoqi@0: return true; aoqi@0: } aoqi@0: if (getMtomRequest() != null && getMtomRequest() && getState().equals(State.ClientRequest)) { aoqi@0: return true; aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: return false; aoqi@0: } aoqi@0: aoqi@0: private boolean isMtomContentType() { aoqi@0: return (getInternalContentType() != null) && aoqi@0: (getInternalContentType().getContentType().contains("application/xop+xml")); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * @deprecated aoqi@0: */ aoqi@0: public void addSatellite(@NotNull com.sun.xml.internal.ws.api.PropertySet satellite) { aoqi@0: super.addSatellite(satellite); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * @deprecated aoqi@0: */ aoqi@0: public void addSatellite(@NotNull Class keyClass, @NotNull com.sun.xml.internal.ws.api.PropertySet satellite) { aoqi@0: super.addSatellite(keyClass, satellite); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * @deprecated aoqi@0: */ aoqi@0: public void copySatelliteInto(@NotNull com.sun.xml.internal.ws.api.DistributedPropertySet r) { aoqi@0: super.copySatelliteInto(r); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * @deprecated aoqi@0: */ aoqi@0: public void removeSatellite(com.sun.xml.internal.ws.api.PropertySet satellite) { aoqi@0: super.removeSatellite(satellite); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * This is propogated from SOAPBindingCodec and will affect isMtomAcceptable and isFastInfosetAcceptable aoqi@0: */ aoqi@0: private boolean isFastInfosetDisabled; aoqi@0: aoqi@0: public void setFastInfosetDisabled(boolean b) { aoqi@0: isFastInfosetDisabled = b; aoqi@0: } aoqi@0: }