src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/Packet.java

Print this page

        

@@ -1,7 +1,7 @@
 /*
- * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License version 2 only, as
  * published by the Free Software Foundation.  Oracle designates this

@@ -23,22 +23,27 @@
  * questions.
  */
 
 package com.sun.xml.internal.ws.api.message;
 
+import com.oracle.webservices.internal.api.message.ContentType;
+import com.oracle.webservices.internal.api.message.PropertySet;
 import com.sun.istack.internal.NotNull;
 import com.sun.istack.internal.Nullable;
 import com.sun.xml.internal.bind.marshaller.SAX2DOMEx;
 import com.sun.xml.internal.ws.addressing.WsaPropertyBag;
+import com.sun.xml.internal.ws.addressing.WsaServerTube;
 import com.sun.xml.internal.ws.addressing.WsaTubeHelper;
-import com.sun.xml.internal.ws.addressing.model.InvalidAddressingHeaderException;
-import com.sun.xml.internal.ws.api.*;
+import com.sun.xml.internal.ws.api.Component;
+import com.sun.xml.internal.ws.api.EndpointAddress;
+import com.sun.xml.internal.ws.api.SOAPVersion;
+import com.sun.xml.internal.ws.api.WSBinding;
 import com.sun.xml.internal.ws.api.addressing.AddressingVersion;
 import com.sun.xml.internal.ws.api.addressing.WSEndpointReference;
-import com.sun.xml.internal.ws.api.message.saaj.SAAJFactory;
 import com.sun.xml.internal.ws.api.model.JavaMethod;
 import com.sun.xml.internal.ws.api.model.SEIModel;
+import com.sun.xml.internal.ws.api.model.WSDLOperationMapping;
 import com.sun.xml.internal.ws.api.model.wsdl.WSDLOperation;
 import com.sun.xml.internal.ws.api.model.wsdl.WSDLPort;
 import com.sun.xml.internal.ws.api.pipe.Codec;
 import com.sun.xml.internal.ws.api.pipe.Tube;
 import com.sun.xml.internal.ws.api.server.Adapter;

@@ -46,42 +51,43 @@
 import com.sun.xml.internal.ws.api.server.WSEndpoint;
 import com.sun.xml.internal.ws.api.server.WebServiceContextDelegate;
 import com.sun.xml.internal.ws.api.streaming.XMLStreamWriterFactory;
 import com.sun.xml.internal.ws.client.*;
 import com.sun.xml.internal.ws.developer.JAXWSProperties;
+import com.sun.xml.internal.ws.encoding.MtomCodec;
 import com.sun.xml.internal.ws.message.RelatesToHeader;
 import com.sun.xml.internal.ws.message.StringHeader;
-import com.sun.xml.internal.ws.transport.http.WSHTTPConnection;
-import com.sun.xml.internal.ws.message.saaj.SAAJMessage;
-import com.sun.xml.internal.ws.server.WSEndpointImpl;
 import com.sun.xml.internal.ws.util.DOMUtil;
 import com.sun.xml.internal.ws.util.xml.XmlUtil;
 import com.sun.xml.internal.ws.wsdl.DispatchException;
 import com.sun.xml.internal.ws.wsdl.OperationDispatcher;
+import com.sun.xml.internal.ws.resources.AddressingMessages;
+
 
-import com.sun.xml.internal.org.jvnet.ws.message.ContentType;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 import org.xml.sax.SAXException;
 
 import javax.xml.namespace.QName;
 import javax.xml.soap.SOAPException;
 import javax.xml.soap.SOAPMessage;
 import javax.xml.stream.XMLStreamWriter;
+import javax.xml.stream.XMLStreamException;
 import javax.xml.ws.BindingProvider;
 import javax.xml.ws.Dispatch;
 import javax.xml.ws.WebServiceContext;
 import javax.xml.ws.WebServiceException;
 import javax.xml.ws.handler.LogicalMessageContext;
 import javax.xml.ws.handler.MessageContext;
 import javax.xml.ws.handler.soap.SOAPMessageContext;
+import javax.xml.ws.soap.MTOMFeature;
+
 import java.util.*;
 import java.util.logging.Logger;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.OutputStream;
-import java.nio.ByteBuffer;
 import java.nio.channels.WritableByteChannel;
 
 /**
  * Represents a container of a {@link Message}.
  *

@@ -140,21 +146,22 @@
  * <h3>TODO</h3>
  * <ol>
  *  <li>this class needs to be cloneable since Message is copiable.
  *  <li>The three live views aren't implemented correctly. It will be
  *      more work to do so, although I'm sure it's possible.
- *  <li>{@link Property} annotation is to make it easy
+ *  <li>{@link PropertySet.Property} annotation is to make it easy
  *      for {@link MessageContext} to export properties on this object,
  *      but it probably needs some clean up.
  * </ol>
  *
  * @author Kohsuke Kawaguchi
  */
 public final class Packet
-    extends DistributedPropertySet
-    implements com.sun.xml.internal.org.jvnet.ws.message.MessageContext
-{
+        // Packet must continue to extend/implement deprecated interfaces until downstream
+        // usage is updated.
+    extends com.oracle.webservices.internal.api.message.BaseDistributedPropertySet
+    implements com.oracle.webservices.internal.api.message.MessageContext, MessageMetadata {
 
     /**
      * Creates a {@link Packet} that wraps a given {@link Message}.
      *
      * <p>

@@ -165,10 +172,11 @@
      *      The request {@link Message}. Can be null.
      */
     public Packet(Message request) {
         this();
         this.message = request;
+        if (message != null) message.setMessageMedadata(this);
     }
 
     /**
      * Creates an empty {@link Packet} that doesn't have any {@link Message}.
      */

@@ -178,28 +186,12 @@
 
     /**
      * Used by {@link #createResponse(Message)} and {@link #copy(boolean)}.
      */
     private Packet(Packet that) {
-        that.copySatelliteInto((DistributedPropertySet) this);
-        this.handlerConfig = that.handlerConfig;
+        relatePackets(that, true);
         this.invocationProperties = that.invocationProperties;
-        this.handlerScopePropertyNames = that.handlerScopePropertyNames;
-        this.contentNegotiation = that.contentNegotiation;
-        this.wasTransportSecure = that.wasTransportSecure;
-        this.transportBackChannel = that.transportBackChannel;
-        this.endpointAddress = that.endpointAddress;
-        this.isAdapterDeliversNonAnonymousResponse = that.isAdapterDeliversNonAnonymousResponse;
-        this.wsdlOperation = that.wsdlOperation;
-        this.acceptableMimeTypes = that.acceptableMimeTypes;
-        this.endpoint = that.endpoint;
-        this.proxy = that.proxy;
-        this.webServiceContextDelegate = that.webServiceContextDelegate;
-        this.soapAction = that.soapAction;
-        this.expectReply = that.expectReply;
-        this.component = that.component;
-        // copy other properties that need to be copied. is there any?
     }
 
     /**
      * Creates a copy of this {@link Packet}.
      *

@@ -213,11 +205,11 @@
         // to avoid code dupliation.
         Packet copy = new Packet(this);
         if (copyMessage && this.message != null) {
             copy.message = this.message.copy();
         }
-
+        if (copy.message != null) copy.message.setMessageMedadata(copy);
         return copy;
     }
 
     private Message message;
 

@@ -225,29 +217,41 @@
      * Gets the last {@link Message} set through {@link #setMessage(Message)}.
      *
      * @return may null. See the class javadoc for when it's null.
      */
     public Message getMessage() {
+        if (message != null && !(message instanceof MessageWrapper)) {
+            message = new MessageWrapper(this, message);
+        }
         return message;
     }
 
+    public Message getInternalMessage() {
+        return (message instanceof MessageWrapper)? ((MessageWrapper)message).delegate : message;
+    }
+
     public WSBinding getBinding() {
-        if (endpoint != null)
+        if (endpoint != null) {
                 return endpoint.getBinding();
-        if (proxy != null)
+        }
+        if (proxy != null) {
                 return (WSBinding) proxy.getBinding();
+        }
         return null;
     }
     /**
      * Sets a {@link Message} to this packet.
      *
      * @param message Can be null.
      */
     public void setMessage(Message message) {
         this.message = message;
+        if (message != null) this.message.setMessageMedadata(this);
     }
 
+    private WSDLOperationMapping wsdlOperationMapping = null;
+
     private QName wsdlOperation;
 
     /**
      * Returns the QName of the wsdl operation associated with this packet.
      * <p/>

@@ -255,33 +259,38 @@
      * enabled on the particular port.
      *
      * @return null if there is no WSDL model or
      *         runtime cannot uniquely identify the wsdl operation from the information in the packet.
      */
-    @com.sun.xml.internal.ws.api.PropertySet.Property(MessageContext.WSDL_OPERATION)
+    @Property(MessageContext.WSDL_OPERATION)
     public final
     @Nullable
     QName getWSDLOperation() {
-        if (wsdlOperation != null)
+        if (wsdlOperation != null) return wsdlOperation;
+        if ( wsdlOperationMapping == null)  wsdlOperationMapping = getWSDLOperationMapping();
+        if ( wsdlOperationMapping != null ) wsdlOperation = wsdlOperationMapping.getOperationName();
             return wsdlOperation;
+    }
 
+    public WSDLOperationMapping getWSDLOperationMapping() {
+        if (wsdlOperationMapping != null) return wsdlOperationMapping;
         OperationDispatcher opDispatcher = null;
         if (endpoint != null) {
-            opDispatcher = ((WSEndpointImpl) endpoint).getOperationDispatcher();
+            opDispatcher = endpoint.getOperationDispatcher();
         } else if (proxy != null) {
             opDispatcher = ((Stub) proxy).getOperationDispatcher();
         }
         //OpDispatcher is null when there is no WSDLModel
         if (opDispatcher != null) {
             try {
-                wsdlOperation = opDispatcher.getWSDLOperationQName(this);
+                wsdlOperationMapping = opDispatcher.getWSDLOperationMapping(this);
             } catch (DispatchException e) {
                 //Ignore, this might be a protocol message which may not have a wsdl operation
                 //LOGGER.info("Cannot resolve wsdl operation that this Packet is targeted for.");
             }
         }
-        return wsdlOperation;
+        return wsdlOperationMapping;
     }
 
     /**
      * Set the wsdl operation to avoid lookup from other data.
      * This is useful in SEI based clients, where the WSDL operation can be known

@@ -331,30 +340,42 @@
     /**
      * This property holds the snapshot of HandlerConfiguration
      * at the time of invocation.
      * This property is used by MUPipe and HandlerPipe implementations.
      */
-    @com.sun.xml.internal.ws.api.PropertySet.Property(BindingProviderProperties.JAXWS_HANDLER_CONFIG)
+    @Property(BindingProviderProperties.JAXWS_HANDLER_CONFIG)
     public HandlerConfiguration handlerConfig;
 
     /**
      * If a message originates from a proxy stub that implements
      * a port interface, this field is set to point to that object.
      *
      * TODO: who's using this property?
      */
-    @com.sun.xml.internal.ws.api.PropertySet.Property(BindingProviderProperties.JAXWS_CLIENT_HANDLE_PROPERTY)
+    @Property(BindingProviderProperties.JAXWS_CLIENT_HANDLE_PROPERTY)
     public BindingProvider proxy;
 
     /**
-     * Determines if the governing {@link Adapter} or {@link Fiber.CompletionCallback} will handle delivering
-     * response messages targeted at non-anonymous endpoint addresses.  Prior to the introduction of this
-     * flag the {@link WsaServerTube} would deliver non-anonymous responses.
+     * Determines if the governing {@link Adapter} or {@link com.sun.xml.internal.ws.api.pipe.Fiber.CompletionCallback}
+     * will handle delivering response messages targeted at non-anonymous endpoint
+     * addresses.  Prior to the introduction of this flag
+     * the {@link WsaServerTube} would deliver non-anonymous responses.
      */
     public boolean isAdapterDeliversNonAnonymousResponse;
 
     /**
+     * During invocation of a client Stub or Dispatch a Packet is
+     * created then the Stub's RequestContext is copied into the
+     * Packet.  On certain internal cases the Packet is created
+     * *before* the invocation.  In those cases we want the contents
+     * of the Packet to take precedence when ever any key/value pairs
+     * collide : if the Packet contains a value for a key use it,
+     * otherwise copy as usual from Stub.
+     */
+    public boolean packetTakesPriorityOverRequestContext = false;
+
+    /**
      * The endpoint address to which this message is sent to.
      *
      * <p>
      * The JAX-WS spec allows this to be changed for each message,
      * so it's designed to be a property.

@@ -369,42 +390,44 @@
      * @deprecated
      *      The programatic acccess should be done via
      *      {@link #endpointAddress}. This is for JAX-WS client applications
      *      that access this property via {@link BindingProvider#ENDPOINT_ADDRESS_PROPERTY}.
      */
-    @com.sun.xml.internal.ws.api.PropertySet.Property(BindingProvider.ENDPOINT_ADDRESS_PROPERTY)
+    @Property(BindingProvider.ENDPOINT_ADDRESS_PROPERTY)
     public String getEndPointAddressString() {
-        if (endpointAddress == null)
+        if (endpointAddress == null) {
             return null;
-        else
+        } else {
             return endpointAddress.toString();
     }
+    }
 
     public void setEndPointAddressString(String s) {
-        if (s == null)
+        if (s == null) {
             this.endpointAddress = null;
-        else
+        } else {
             this.endpointAddress = EndpointAddress.create(s);
     }
+    }
 
     /**
      * The value of {@link ContentNegotiation#PROPERTY}
      * property.
      * <p/>
      * This property is used only on the client side.
      */
     public ContentNegotiation contentNegotiation;
 
-    @com.sun.xml.internal.ws.api.PropertySet.Property(ContentNegotiation.PROPERTY)
+    @Property(ContentNegotiation.PROPERTY)
     public String getContentNegotiationString() {
         return (contentNegotiation != null) ? contentNegotiation.toString() : null;
     }
 
     public void setContentNegotiationString(String s) {
-        if (s == null)
+        if (s == null) {
             contentNegotiation = null;
-        else {
+        } else {
             try {
                 contentNegotiation = ContentNegotiation.valueOf(s);
             } catch (IllegalArgumentException e) {
                 // If the value is not recognized default to none
                 contentNegotiation = ContentNegotiation.none;

@@ -417,20 +440,21 @@
      * <p>
      * Headers which have attribute wsa:IsReferenceParameter="true"
      * This is not cached as one may reset the Message.
      *<p>
      */
-    @com.sun.xml.internal.ws.api.PropertySet.Property(MessageContext.REFERENCE_PARAMETERS)
+    @Property(MessageContext.REFERENCE_PARAMETERS)
     public
     @NotNull
     List<Element> getReferenceParameters() {
+        Message msg = getMessage();
         List<Element> refParams = new ArrayList<Element>();
-        if (message == null) {
+        if (msg == null) {
             return refParams;
         }
-        HeaderList hl = message.getHeaders();
-        for (Header h : hl) {
+        MessageHeaders hl = msg.getHeaders();
+        for (Header h : hl.asList()) {
             String attr = h.getAttribute(AddressingVersion.W3C.nsUri, "IsReferenceParameter");
             if (attr != null && (attr.equals("true") || attr.equals("1"))) {
                 Document d = DOMUtil.createDom();
                 SAX2DOMEx s2d = new SAX2DOMEx(d);
                 try {

@@ -453,18 +477,20 @@
         }
         return refParams;
     }
 
     /**
-     * @deprecated
      *      This method is for exposing header list through {@link PropertySet#get(Object)},
      *      for user applications, and should never be invoked directly from within the JAX-WS RI.
      */
-    @com.sun.xml.internal.ws.api.PropertySet.Property(JAXWSProperties.INBOUND_HEADER_LIST_PROPERTY)
-    /*package*/ HeaderList getHeaderList() {
-        if (message == null) return null;
-        return message.getHeaders();
+    @Property(JAXWSProperties.INBOUND_HEADER_LIST_PROPERTY)
+    /*package*/ MessageHeaders getHeaderList() {
+        Message msg = getMessage();
+        if (msg == null) {
+            return null;
+        }
+        return msg.getHeaders();
     }
 
     /**
      * The list of MIME types that are acceptable to a receiver
      * of an outbound message.

@@ -532,11 +558,11 @@
      * The governing {@link WSEndpoint} in which this message is floating.
      *
      * <p>
      * This property is set if and only if this is on the server side.
      */
-    @com.sun.xml.internal.ws.api.PropertySet.Property(JAXWSProperties.WSENDPOINT)
+    @Property(JAXWSProperties.WSENDPOINT)
     public WSEndpoint endpoint;
 
     /**
      * The value of the SOAPAction header associated with the message.
      *

@@ -559,11 +585,11 @@
      * <p/>
      * For HTTP transport and SOAP 1.1, BP requires that SOAPAction
      * header is present (See {@BP R2744} and {@BP R2745}.) For SOAP 1.2,
      * this is moved to the parameter of the "application/soap+xml".
      */
-    @com.sun.xml.internal.ws.api.PropertySet.Property(BindingProvider.SOAPACTION_URI_PROPERTY)
+    @Property(BindingProvider.SOAPACTION_URI_PROPERTY)
     public String soapAction;
 
     /**
      * A hint indicating that whether a transport should expect
      * a reply back from the server.

@@ -620,11 +646,11 @@
      * <p>
      *
      * In all other situations, this property is null.
      *
      */
-    @com.sun.xml.internal.ws.api.PropertySet.Property(BindingProviderProperties.ONE_WAY_OPERATION)
+    @Property(BindingProviderProperties.ONE_WAY_OPERATION)
     public Boolean expectReply;
 
 
     /**
      * This property will be removed in a near future.

@@ -654,10 +680,24 @@
      * handler when this request has been processed.
      */
     public Boolean nonNullAsyncHandlerGiven;
 
     /**
+     * USE-CASE:
+     * WS-AT is enabled, but there is no WSDL available.
+     * If Packet.isRequestReplyMEP() is Boolean.TRUE then WS-AT should
+     * add the TX context.
+     *
+     * This value is exposed to users via facades at higher abstraction layers.
+     * The user should NEVER use Packet directly.
+     * This value should ONLY be set by users.
+     */
+    private Boolean isRequestReplyMEP;
+    public Boolean isRequestReplyMEP() { return isRequestReplyMEP; }
+    public void setRequestReplyMEP(final Boolean x) { isRequestReplyMEP = x; }
+
+    /**
      * Lazily created set of handler-scope property names.
      *
      * <p>
      * We expect that this is only used when handlers are present
      * and they explicitly set some handler-scope values.

@@ -699,12 +739,13 @@
      *      always non-null, possibly empty set that stores property names.
      */
     public final Set<String> getHandlerScopePropertyNames(boolean readOnly) {
         Set<String> o = this.handlerScopePropertyNames;
         if (o == null) {
-            if (readOnly)
+            if (readOnly) {
                 return Collections.emptySet();
+            }
             o = new HashSet<String>();
             this.handlerScopePropertyNames = o;
         }
         return o;
     }

@@ -753,16 +794,30 @@
      * @param msg
      *      The {@link Message} that represents a reply. Can be null.
      */
     public Packet createClientResponse(Message msg) {
         Packet response = new Packet(this);
-        response.soapAction = null; // de-initializing
         response.setMessage(msg);
+        finishCreateRelateClientResponse(response);
         return response;
     }
 
     /**
+     * For use cases that start with an existing Packet.
+     */
+    public Packet relateClientResponse(final Packet response) {
+        response.relatePackets(this, true);
+        finishCreateRelateClientResponse(response);
+        return response;
+    }
+
+    private void finishCreateRelateClientResponse(final Packet response) {
+        response.soapAction = null; // de-initializing
+        response.setState(State.ClientResponse);
+    }
+
+    /**
      * Creates a server-side response {@link Packet} from a request
      * packet ({@code this}). If WS-Addressing is enabled, a default Action
      * Message Addressing Property is obtained using <code>wsdlPort</code> {@link WSDLPort}
      * and <code>binding</code> {@link WSBinding}.
      * <p><p>

@@ -776,59 +831,97 @@
      * @param binding The response Binding. Cannot be null.
      * @return response packet
      */
     public Packet createServerResponse(@Nullable Message responseMessage, @Nullable WSDLPort wsdlPort, @Nullable SEIModel seiModel, @NotNull WSBinding binding) {
         Packet r = createClientResponse(responseMessage);
+        return relateServerResponse(r, wsdlPort, seiModel, binding);
+    }
 
-        AddressingVersion av = binding.getAddressingVersion();
-        // populate WS-A headers only if WS-A is enabled
-        if (av == null)
-            return r;
-        //populate WS-A headers only if the request has addressing headers
-        String inputAction = this.getMessage().getHeaders().getAction(av, binding.getSOAPVersion());
-        if (inputAction == null) {
-            return r;
+    /**
+     * Copy all properties from ({@code this}) packet into a input {@link Packet}
+     * @param response packet
+     */
+    public void copyPropertiesTo(@Nullable Packet response){
+        relatePackets(response, false);
         }
-        // if one-way, then dont populate any WS-A headers
-        if (responseMessage == null || (wsdlPort != null && message.isOneWay(wsdlPort)))
-            return r;
 
-        // otherwise populate WS-Addressing headers
-        populateAddressingHeaders(binding, r, wsdlPort, seiModel);
-        return r;
+
+    /**
+     * A common method to make members related between input packet and this packet
+     *
+     * @param packet
+     * @param isCopy 'true' means copying all properties from input packet;
+     *               'false' means copying all properties from this packet to input packet.
+     */
+    private void relatePackets(@Nullable Packet packet, boolean isCopy)
+    {
+        Packet request;
+            Packet response;
+
+        if (!isCopy) { //is relate
+          request = this;
+          response = packet;
+
+          // processing specific properties
+          response.soapAction = null;
+          response.invocationProperties.putAll(request.invocationProperties);
+          if (this.getState().equals(State.ServerRequest)) {
+              response.setState(State.ServerResponse);
     }
+        } else { //is copy constructor
+          request = packet;
+          response = this;
 
+          // processing specific properties
+          response.soapAction = request.soapAction;
+          response.setState(request.getState());
+        }
+
+        request.copySatelliteInto(response);
+        response.isAdapterDeliversNonAnonymousResponse = request.isAdapterDeliversNonAnonymousResponse;
+        response.handlerConfig = request.handlerConfig;
+        response.handlerScopePropertyNames = request.handlerScopePropertyNames;
+        response.contentNegotiation = request.contentNegotiation;
+        response.wasTransportSecure = request.wasTransportSecure;
+        response.transportBackChannel = request.transportBackChannel;
+        response.endpointAddress = request.endpointAddress;
+        response.wsdlOperation = request.wsdlOperation;
+        response.wsdlOperationMapping = request.wsdlOperationMapping;
+        response.acceptableMimeTypes = request.acceptableMimeTypes;
+        response.endpoint = request.endpoint;
+        response.proxy = request.proxy;
+        response.webServiceContextDelegate = request.webServiceContextDelegate;
+        response.expectReply = request.expectReply;
+        response.component = request.component;
+        response.mtomAcceptable = request.mtomAcceptable;
+        response.mtomRequest = request.mtomRequest;
+        // copy other properties that need to be copied. is there any?
+    }
 
-    public Packet relateServerResponse(@Nullable Packet r, @Nullable WSDLPort wsdlPort, @Nullable SEIModel seiModel, @NotNull WSBinding binding) {
-        copySatelliteInto((DistributedPropertySet) r);
-        r.soapAction = null;
-        r.handlerConfig = this.handlerConfig;
-        r.invocationProperties.putAll(this.invocationProperties);
-        r.handlerScopePropertyNames = this.handlerScopePropertyNames;
-        r.contentNegotiation = this.contentNegotiation;
-        r.wasTransportSecure = this.wasTransportSecure;
-        r.endpointAddress = this.endpointAddress;
-        r.wsdlOperation = this.wsdlOperation;
-
-        r.acceptableMimeTypes = this.acceptableMimeTypes;
-        r.endpoint = this.endpoint;
-        r.proxy = this.proxy;
-        r.webServiceContextDelegate = this.webServiceContextDelegate;
-        r.expectReply = this.expectReply;
 
+    public Packet relateServerResponse(@Nullable Packet r, @Nullable WSDLPort wsdlPort, @Nullable SEIModel seiModel, @NotNull WSBinding binding) {
+        relatePackets(r, false);
+        r.setState(State.ServerResponse);
         AddressingVersion av = binding.getAddressingVersion();
         // populate WS-A headers only if WS-A is enabled
-        if (av == null)
+        if (av == null) {
+            return r;
+        }
+
+        if (getMessage() == null) {
             return r;
+        }
+
         //populate WS-A headers only if the request has addressing headers
-        String inputAction = this.getMessage().getHeaders().getAction(av, binding.getSOAPVersion());
+        String inputAction = AddressingUtils.getAction(getMessage().getHeaders(), av, binding.getSOAPVersion());
         if (inputAction == null) {
             return r;
         }
         // if one-way, then dont populate any WS-A headers
-        if (r.getMessage() == null || (wsdlPort != null && message.isOneWay(wsdlPort)))
+        if (r.getMessage() == null || (wsdlPort != null && getMessage().isOneWay(wsdlPort))) {
             return r;
+        }
 
         // otherwise populate WS-Addressing headers
         populateAddressingHeaders(binding, r, wsdlPort, seiModel);
         return r;
     }

@@ -849,16 +942,17 @@
      * @param action The response Action Message Addressing Property value.
      * @return response packet
      */
     public Packet createServerResponse(@Nullable Message responseMessage, @NotNull AddressingVersion addressingVersion, @NotNull SOAPVersion soapVersion, @NotNull String action) {
         Packet responsePacket = createClientResponse(responseMessage);
-
+        responsePacket.setState(State.ServerResponse);
         // populate WS-A headers only if WS-A is enabled
-        if (addressingVersion == null)
+        if (addressingVersion == null) {
             return responsePacket;
+        }
         //populate WS-A headers only if the request has addressing headers
-        String inputAction = this.getMessage().getHeaders().getAction(addressingVersion, soapVersion);
+        String inputAction = AddressingUtils.getAction(this.getMessage().getHeaders(), addressingVersion, soapVersion);
         if (inputAction == null) {
             return responsePacket;
         }
 
         populateAddressingHeaders(responsePacket, addressingVersion, soapVersion, action, false);

@@ -886,25 +980,37 @@
 
         // if one-way, then dont populate any WS-A headers
         if (responsePacket.getMessage() == null)
             return;
 
-        HeaderList hl = responsePacket.getMessage().getHeaders();
+        MessageHeaders hl = responsePacket.getMessage().getHeaders();
 
         WsaPropertyBag wpb = getSatellite(WsaPropertyBag.class);
-
+        Message msg = getMessage();
         // wsa:To
         WSEndpointReference replyTo = null;
-        if (wpb != null)
-                replyTo = wpb.getReplyToFromRequest();
-        if (replyTo == null)
-                replyTo = message.getHeaders().getReplyTo(av, sv);
+        Header replyToFromRequestMsg = AddressingUtils.getFirstHeader(msg.getHeaders(), av.replyToTag, true, sv);
+        Header replyToFromResponseMsg = hl.get(av.toTag, false);
+        boolean replaceToTag = true;
+        try{
+            if (replyToFromRequestMsg != null){
+                replyTo = replyToFromRequestMsg.readAsEPR(av);
+            }
+            if (replyToFromResponseMsg != null && replyTo == null) {
+                replaceToTag = false;
+            }
+        } catch (XMLStreamException e) {
+            throw new WebServiceException(AddressingMessages.REPLY_TO_CANNOT_PARSE(), e);
+        }
+        if (replyTo == null) {
+              replyTo = AddressingUtils.getReplyTo(msg.getHeaders(), av, sv);
+        }
 
         // wsa:Action, add if the message doesn't already contain it,
         // generally true for SEI case where there is SEIModel or WSDLModel
         //           false for Provider with no wsdl, Expects User to set the coresponding header on the Message.
-        if (responsePacket.getMessage().getHeaders().getAction(av, sv) == null) {
+        if (AddressingUtils.getAction(responsePacket.getMessage().getHeaders(), av, sv) == null) {
             //wsa:Action header is not set in the message, so use the wsa:Action  passed as the parameter.
             hl.add(new StringHeader(av.actionTag, action, sv, mustUnderstand));
         }
 
         // wsa:MessageID

@@ -914,69 +1020,79 @@
             hl.add(new StringHeader(av.messageIDTag, newID));
         }
 
         // wsa:RelatesTo
         String mid = null;
-        if (wpb != null)
+        if (wpb != null) {
                 mid = wpb.getMessageID();
-        if (mid == null)
-                mid = message.getHeaders().getMessageID(av, sv);
-        if (mid != null)
-            hl.add(new RelatesToHeader(av.relatesToTag, mid));
+        }
+        if (mid == null) {
+            mid = AddressingUtils.getMessageID(msg.getHeaders(), av, sv);
+        }
+        if (mid != null) {
+            hl.addOrReplace(new RelatesToHeader(av.relatesToTag, mid));
+        }
 
 
         // populate reference parameters
         WSEndpointReference refpEPR = null;
         if (responsePacket.getMessage().isFault()) {
             // choose FaultTo
-                if (wpb != null)
+            if (wpb != null) {
                         refpEPR = wpb.getFaultToFromRequest();
-                if (refpEPR == null)
-                        refpEPR = message.getHeaders().getFaultTo(av, sv);
+            }
+            if (refpEPR == null) {
+                refpEPR = AddressingUtils.getFaultTo(msg.getHeaders(), av, sv);
+            }
             // if FaultTo is null, then use ReplyTo
-            if (refpEPR == null)
+            if (refpEPR == null) {
                 refpEPR = replyTo;
+            }
         } else {
             // choose ReplyTo
             refpEPR = replyTo;
         }
-        if (refpEPR != null) {
-            hl.add(new StringHeader(av.toTag, refpEPR.getAddress()));
+        if (replaceToTag && refpEPR != null) {
+            hl.addOrReplace(new StringHeader(av.toTag, refpEPR.getAddress()));
             refpEPR.addReferenceParametersToList(hl);
         }
     }
 
     private void populateAddressingHeaders(WSBinding binding, Packet responsePacket, WSDLPort wsdlPort, SEIModel seiModel) {
         AddressingVersion addressingVersion = binding.getAddressingVersion();
 
-        if (addressingVersion == null) return;
+        if (addressingVersion == null) {
+            return;
+        }
 
         WsaTubeHelper wsaHelper = addressingVersion.getWsaHelper(wsdlPort, seiModel, binding);
-        String action = responsePacket.message.isFault() ?
+        String action = responsePacket.getMessage().isFault() ?
                 wsaHelper.getFaultAction(this, responsePacket) :
                 wsaHelper.getOutputAction(this);
         if (action == null) {
             LOGGER.info("WSA headers are not added as value for wsa:Action cannot be resolved for this message");
             return;
         }
-        populateAddressingHeaders(responsePacket, addressingVersion, binding.getSOAPVersion(), action, addressingVersion.isRequired(binding));
+        populateAddressingHeaders(responsePacket, addressingVersion, binding.getSOAPVersion(), action, AddressingVersion.isRequired(binding));
     }
 
     public String toShortString() {
       return super.toString();
     }
 
     // For use only in a debugger
+    @Override
     public String toString() {
       StringBuilder buf = new StringBuilder();
       buf.append(super.toString());
       String content;
         try {
-        if (message != null) {
+            Message msg = getMessage();
+        if (msg != null) {
                         ByteArrayOutputStream baos = new ByteArrayOutputStream();
                         XMLStreamWriter xmlWriter = XMLStreamWriterFactory.create(baos, "UTF-8");
-                        message.copy().writeTo(xmlWriter);
+                        msg.copy().writeTo(xmlWriter);
                         xmlWriter.flush();
                         xmlWriter.close();
                         baos.flush();
                         XMLStreamWriterFactory.recycle(xmlWriter);
 

@@ -998,37 +1114,359 @@
 
     static {
         model = parse(Packet.class);
     }
 
+    @Override
     protected PropertyMap getPropertyMap() {
         return model;
     }
 
+    public Map<String, Object> asMapIncludingInvocationProperties() {
+        final Map<String, Object> asMap = asMap();
+        return new AbstractMap<String, Object>() {
+            @Override
+            public Object get(Object key) {
+                Object o = asMap.get(key);
+                if (o != null)
+                    return o;
+
+                return invocationProperties.get(key);
+            }
+
+            @Override
+            public int size() {
+                return asMap.size() + invocationProperties.size();
+            }
+
+            @Override
+            public boolean containsKey(Object key) {
+                if (asMap.containsKey(key))
+                    return true;
+                return invocationProperties.containsKey(key);
+            }
+
+            @Override
+            public Set<Entry<String, Object>> entrySet() {
+                final Set<Entry<String, Object>> asMapEntries = asMap.entrySet();
+                final Set<Entry<String, Object>> ipEntries = invocationProperties.entrySet();
+
+                return new AbstractSet<Entry<String, Object>>() {
+                    @Override
+                    public Iterator<Entry<String, Object>> iterator() {
+                        final Iterator<Entry<String, Object>> asMapIt = asMapEntries.iterator();
+                        final Iterator<Entry<String, Object>> ipIt = ipEntries.iterator();
+
+                        return new Iterator<Entry<String, Object>>() {
+                            @Override
+                            public boolean hasNext() {
+                                return asMapIt.hasNext() || ipIt.hasNext();
+                            }
+
+                            @Override
+                            public java.util.Map.Entry<String, Object> next() {
+                                if (asMapIt.hasNext())
+                                    return asMapIt.next();
+                                return ipIt.next();
+                            }
+
+                            @Override
+                            public void remove() {
+                                throw new UnsupportedOperationException();
+                            }
+                        };
+                    }
+
+                    @Override
+                    public int size() {
+                        return asMap.size() + invocationProperties.size();
+                    }
+                };
+            }
+
+            @Override
+            public Object put(String key, Object value) {
+                if (supports(key))
+                    return asMap.put(key, value);
+
+                return invocationProperties.put(key, value);
+            }
+
+            @Override
+            public void clear() {
+                asMap.clear();
+                invocationProperties.clear();
+            }
+
+            @Override
+            public Object remove(Object key) {
+                if (supports(key))
+                    return asMap.remove(key);
+
+                return invocationProperties.remove(key);
+            }
+        };
+    }
+
     private static final Logger LOGGER = Logger.getLogger(Packet.class.getName());
 
+    @Override
     public SOAPMessage getSOAPMessage() throws SOAPException {
-        return (message != null) ? message.readAsSOAPMessage() : null;
+        return getAsSOAPMessage();
+    }
+
+    //TODO replace the message to a SAAJMEssage issue - JRFSAAJMessage or SAAJMessage?
+    @Override
+    public SOAPMessage getAsSOAPMessage() throws SOAPException {
+        Message msg = this.getMessage();
+        if (msg == null)
+            return null;
+        if (msg instanceof MessageWritable)
+            ((MessageWritable) msg).setMTOMConfiguration(mtomFeature);
+        return msg.readAsSOAPMessage(this, this.getState().isInbound());
     }
 
+    public
     Codec codec = null;
-    Codec getCodec() {
-        if (codec != null) return codec;
+    public Codec getCodec() {
+        if (codec != null) {
+            return codec;
+        }
         if (endpoint != null) {
             codec = endpoint.createCodec();
         }
         WSBinding wsb = getBinding();
         if (wsb != null) {
             codec = wsb.getBindingId().createEncoder(wsb);
         }
         return codec;
     }
 
-
-    public ContentType writeTo( OutputStream out ) throws IOException {
+    @Override
+    public com.oracle.webservices.internal.api.message.ContentType writeTo( OutputStream out ) throws IOException {
+        Message msg = getInternalMessage();
+        if (msg instanceof MessageWritable) {
+            ((MessageWritable) msg).setMTOMConfiguration(mtomFeature);
+            return ((MessageWritable)msg).writeTo(out);
+        }
         return getCodec().encode(this, out);
     }
 
-    public ContentType writeTo( WritableByteChannel buffer ) {
+    public com.oracle.webservices.internal.api.message.ContentType writeTo( WritableByteChannel buffer ) {
         return getCodec().encode(this, buffer);
     }
+
+    private ContentType contentType;
+
+    /**
+     * If the request's Content-Type is multipart/related; type=application/xop+xml, then this set to to true
+     *
+     * Used on server-side, for encoding the repsonse.
+     */
+    private Boolean mtomRequest;
+
+    /**
+     * Based on request's Accept header this is set.
+     * Currently only set if MTOMFeature is enabled.
+     *
+     * Should be used on server-side, for encoding the response.
+     */
+    private Boolean mtomAcceptable;
+
+    private MTOMFeature mtomFeature;
+
+    public Boolean getMtomRequest() {
+        return mtomRequest;
+    }
+
+    public void setMtomRequest(Boolean mtomRequest) {
+        this.mtomRequest = mtomRequest;
+    }
+
+    public Boolean getMtomAcceptable() {
+        return mtomAcceptable;
+    }
+
+    Boolean checkMtomAcceptable;
+    public void checkMtomAcceptable() {
+        if (checkMtomAcceptable == null) {
+            if (acceptableMimeTypes == null || isFastInfosetDisabled) {
+                checkMtomAcceptable = false;
+            } else {
+                checkMtomAcceptable = (acceptableMimeTypes.indexOf(MtomCodec.XOP_XML_MIME_TYPE) != -1);
+//                StringTokenizer st = new StringTokenizer(acceptableMimeTypes, ",");
+//                while (st.hasMoreTokens()) {
+//                    final String token = st.nextToken().trim();
+//                    if (token.toLowerCase().contains(MtomCodec.XOP_XML_MIME_TYPE)) {
+//                        mtomAcceptable = true;
+//                    }
+//                }
+//                if (mtomAcceptable == null) mtomAcceptable = false;
+            }
+        }
+        mtomAcceptable = checkMtomAcceptable;
+    }
+
+    private Boolean fastInfosetAcceptable;
+
+    public Boolean getFastInfosetAcceptable(String fiMimeType) {
+        if (fastInfosetAcceptable == null) {
+            if (acceptableMimeTypes == null || isFastInfosetDisabled) {
+                fastInfosetAcceptable = false;
+            } else {
+                fastInfosetAcceptable = (acceptableMimeTypes.indexOf(fiMimeType) != -1);
+            }
+//        if (accept == null || isFastInfosetDisabled) return false;
+//
+//        StringTokenizer st = new StringTokenizer(accept, ",");
+//        while (st.hasMoreTokens()) {
+//            final String token = st.nextToken().trim();
+//            if (token.equalsIgnoreCase(fiMimeType)) {
+//                return true;
+//            }
+//        }
+//        return false;
+        }
+        return fastInfosetAcceptable;
+    }
+
+
+    public void setMtomFeature(MTOMFeature mtomFeature) {
+        this.mtomFeature = mtomFeature;
+    }
+
+    public MTOMFeature getMtomFeature() {
+        //If we have a binding, use that in preference to an explicitly
+        //set MTOMFeature
+        WSBinding binding = getBinding();
+        if (binding != null) {
+            return binding.getFeature(MTOMFeature.class);
+        }
+        return mtomFeature;
+    }
+
+    @Override
+    public com.oracle.webservices.internal.api.message.ContentType getContentType() {
+        if (contentType == null) {
+            contentType = getInternalContentType();
+        }
+        if (contentType == null) {
+            contentType = getCodec().getStaticContentType(this);
+        }
+        if (contentType == null) {
+            //TODO write to buffer
+        }
+        return contentType;
+    }
+
+    public ContentType getInternalContentType() {
+        Message msg = getInternalMessage();
+        if (msg instanceof MessageWritable) {
+            return ((MessageWritable)msg).getContentType();
+        }
+        return contentType;
+    }
+
+    public void setContentType(ContentType contentType) {
+        this.contentType = contentType;
+    }
+
+    public enum Status {
+        Request, Response, Unknown;
+        public boolean isRequest()  { return Request.equals(this); }
+        public boolean isResponse() { return Response.equals(this); }
+    }
+
+    public enum State {
+        ServerRequest(true), ClientRequest(false), ServerResponse(false), ClientResponse(true);
+        private boolean inbound;
+        State(boolean inbound) {
+            this.inbound = inbound;
+        }
+        public boolean isInbound() {
+            return inbound;
+        }
+    }
+
+//    private Status status = Status.Unknown;
+
+    //Default state is ServerRequest - some custom adapters may not set the value of state
+    //upon server request - all other code paths should set it
+    private State state = State.ServerRequest;
+
+//    public Status getStatus() { return status; }
+
+    public State getState() { return state; }
+    public void setState(State state) { this.state = state; }
+
+    public boolean shouldUseMtom() {
+        if (getState().isInbound()) {
+            return isMtomContentType();
+        } else {
+            return shouldUseMtomOutbound();
+        }
+    }
+
+    private boolean shouldUseMtomOutbound() {
+        //Use the getter to make sure all the logic is executed correctly
+        MTOMFeature myMtomFeature = getMtomFeature();
+        if(myMtomFeature != null && myMtomFeature.isEnabled()) {
+            //On client, always use XOP encoding if MTOM is enabled
+            //On Server, mtomAcceptable and mtomRequest will be set - use XOP encoding
+            //if either request is XOP encoded (mtomRequest) or
+            //client accepts XOP encoding (mtomAcceptable)
+            if (getMtomAcceptable() == null && getMtomRequest() == null) {
+                return true;
+            } else {
+                if (getMtomAcceptable() != null &&  getMtomAcceptable() && getState().equals(State.ServerResponse)) {
+                    return true;
+                }
+                if (getMtomRequest() != null && getMtomRequest() && getState().equals(State.ServerResponse)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    private boolean isMtomContentType() {
+        return (getInternalContentType() != null) &&
+        (getInternalContentType().getContentType().contains("application/xop+xml"));
+    }
+
+    /**
+     * @deprecated
+     */
+    public void addSatellite(@NotNull com.sun.xml.internal.ws.api.PropertySet satellite) {
+        super.addSatellite(satellite);
+    }
+
+    /**
+     * @deprecated
+     */
+    public void addSatellite(@NotNull Class keyClass, @NotNull com.sun.xml.internal.ws.api.PropertySet satellite) {
+        super.addSatellite(keyClass, satellite);
+    }
+
+    /**
+     * @deprecated
+     */
+    public void copySatelliteInto(@NotNull com.sun.xml.internal.ws.api.DistributedPropertySet r) {
+        super.copySatelliteInto(r);
+    }
+
+    /**
+     * @deprecated
+     */
+    public void removeSatellite(com.sun.xml.internal.ws.api.PropertySet satellite) {
+        super.removeSatellite(satellite);
+    }
+
+    /**
+     * This is propogated from SOAPBindingCodec and will affect isMtomAcceptable and isFastInfosetAcceptable
+     */
+    private boolean isFastInfosetDisabled;
+
+    public void setFastInfosetDisabled(boolean b) {
+        isFastInfosetDisabled = b;
+    }
 }