Index: src/main/java/org/apache/synapse/core/axis2/SynapseCallbackReceiver.java
===================================================================
--- src/main/java/org/apache/synapse/core/axis2/SynapseCallbackReceiver.java	(revision 1065487)
+++ src/main/java/org/apache/synapse/core/axis2/SynapseCallbackReceiver.java	(working copy)
@@ -96,7 +96,7 @@
     }
 
     /**
-     * Everytime a response message is received this method gets invoked. It will then select
+     * Every time a response message is received this method gets invoked. It will then select
      * the outgoing *Synapse* message context for the reply we received, and determine what action
      * to take at the Synapse level
      *
@@ -170,7 +170,7 @@
                     ErrorLogFactory.createErrorLog(response));
             // there is a sending fault. propagate the fault to fault handlers.
 
-            Stack faultStack = synapseOutMsgCtx.getFaultStack();
+            Stack<FaultHandler> faultStack = synapseOutMsgCtx.getFaultStack();
             if (faultStack != null && !faultStack.isEmpty()) {
 
                 // if we have access to the full synapseOutMsgCtx.getEnvelope(), then let
@@ -184,22 +184,41 @@
 
                 Exception e = (Exception) response.getProperty(SynapseConstants.ERROR_EXCEPTION);
 
-                synapseOutMsgCtx.setProperty(SynapseConstants.SENDING_FAULT, Boolean.TRUE);
-                synapseOutMsgCtx.setProperty(SynapseConstants.ERROR_CODE,
+                populateResponseContext(response, synapseOutMsgCtx);
+
+                // create the synapse message context for the response
+                Axis2MessageContext synapseInMessageContext =
+                        createSynapseMessageContext(response, synapseOutMsgCtx);
+
+                // If this response is related to session affinity endpoints -Server initiated session
+                Dispatcher dispatcher =
+                        (Dispatcher) synapseOutMsgCtx.getProperty(
+                                SynapseConstants.PROP_SAL_ENDPOINT_CURRENT_DISPATCHER);
+                if (dispatcher != null && dispatcher.isServerInitiatedSession()) {
+                    dispatcher.updateSession(synapseInMessageContext);
+                }
+
+                synapseInMessageContext.setProperty(SynapseConstants.SENDING_FAULT, Boolean.TRUE);
+                synapseInMessageContext.setProperty(SynapseConstants.ERROR_CODE,
                     response.getProperty(SynapseConstants.ERROR_CODE));
-                synapseOutMsgCtx.setProperty(SynapseConstants.ERROR_MESSAGE,
+                synapseInMessageContext.setProperty(SynapseConstants.ERROR_MESSAGE,
                     response.getProperty(SynapseConstants.ERROR_MESSAGE));
-                synapseOutMsgCtx.setProperty(SynapseConstants.ERROR_DETAIL,
+                synapseInMessageContext.setProperty(SynapseConstants.ERROR_DETAIL,
                     response.getProperty(SynapseConstants.ERROR_DETAIL));
-                synapseOutMsgCtx.setProperty(SynapseConstants.ERROR_EXCEPTION, e);
+                synapseInMessageContext.setProperty(SynapseConstants.ERROR_EXCEPTION, e);
 
                 if (log.isDebugEnabled()) {
                     log.debug("[Failed Request Message ID : " + messageID + "]" +
                             " [New to be Retried Request Message ID : " +
                             synapseOutMsgCtx.getMessageID() + "]");
-                }                   
+                }
 
-                ((FaultHandler) faultStack.pop()).handleFault(synapseOutMsgCtx, null);
+                for (FaultHandler faultHandler : faultStack) {
+                    synapseInMessageContext.pushFaultHandler(faultHandler);
+                }
+
+                Stack<FaultHandler> newFaultStack = synapseInMessageContext.getFaultStack();
+                (newFaultStack.pop()).handleFault(synapseInMessageContext, null);
             }
 
         } else {
@@ -228,107 +247,12 @@
                 }
                 log.debug("Body : \n" + response.getEnvelope());
             }
-            MessageContext axisOutMsgCtx =
-                    ((Axis2MessageContext) synapseOutMsgCtx).getAxis2MessageContext();
+            populateResponseContext(response, synapseOutMsgCtx);
 
-            //Processes 'Accept-Encoding'
-            ResponseAcceptEncodingProcessor.process(response, axisOutMsgCtx);
-
-            response.setServiceContext(null);
-            response.setOperationContext(axisOutMsgCtx.getOperationContext());
-            response.setAxisMessage(axisOutMsgCtx.getAxisOperation().getMessage(
-                    WSDLConstants.MESSAGE_LABEL_OUT_VALUE));
-
-            // set properties on response
-            response.setServerSide(true);
-            response.setProperty(SynapseConstants.ISRESPONSE_PROPERTY, Boolean.TRUE);
-            response.setProperty(MessageContext.TRANSPORT_OUT,
-                    axisOutMsgCtx.getProperty(MessageContext.TRANSPORT_OUT));
-            response.setProperty(org.apache.axis2.Constants.OUT_TRANSPORT_INFO,
-                    axisOutMsgCtx.getProperty(org.apache.axis2.Constants.OUT_TRANSPORT_INFO));
-            response.setTransportIn(axisOutMsgCtx.getTransportIn());
-            response.setTransportOut(axisOutMsgCtx.getTransportOut());
-
-            // If request is REST assume that the response is REST too
-            response.setDoingREST(axisOutMsgCtx.isDoingREST());
-            if (axisOutMsgCtx.isDoingMTOM()) {
-                response.setDoingMTOM(true);
-                response.setProperty(
-                        org.apache.axis2.Constants.Configuration.ENABLE_MTOM,
-                        org.apache.axis2.Constants.VALUE_TRUE);
-            }
-            if (axisOutMsgCtx.isDoingSwA()) {
-                response.setDoingSwA(true);
-                response.setProperty(
-                        org.apache.axis2.Constants.Configuration.ENABLE_SWA,
-                        org.apache.axis2.Constants.VALUE_TRUE);
-            }
-
-            // when axis2 receives a soap message without addressing headers it users
-            // DISABLE_ADDRESSING_FOR_OUT_MESSAGES property to keep it and hence avoid addressing
-            // headers on the response. this causes a problem for synapse if the original message
-            // it receivs (from client) has addressing and the synaspse service invocation has not
-            // engage addressing. in this case when synapse receives the response from the server
-            // addessing In handler dissable addressing since that response does not have addressing
-            // headers. synapse sends the response to its orignal client using the same message
-            // context. Then this response does not have addressing headers since it already
-            // disable. to avoid this we need to set the DISABLE_ADDRESSING_FOR_OUT_MESSAGES
-            // property state to original state.
-            if (axisOutMsgCtx.getProperty(
-                    AddressingConstants.DISABLE_ADDRESSING_FOR_OUT_MESSAGES) != null) {
-                
-                response.setProperty(AddressingConstants.DISABLE_ADDRESSING_FOR_OUT_MESSAGES,
-                        axisOutMsgCtx.getProperty(
-                                AddressingConstants.DISABLE_ADDRESSING_FOR_OUT_MESSAGES));
-            } else {
-                response.removeProperty(AddressingConstants.DISABLE_ADDRESSING_FOR_OUT_MESSAGES);
-            }
-
-             // copy the message type property thats used by the out message to the response message
-            response.setProperty(org.apache.axis2.Constants.Configuration.MESSAGE_TYPE,
-                axisOutMsgCtx.getProperty(org.apache.axis2.Constants.Configuration.MESSAGE_TYPE));
-            
-            // compare original received message (axisOutMsgCtx) soap version with the response
-            // if they are different change to original version 
-            if(axisOutMsgCtx.isSOAP11() != response.isSOAP11()) {
-            	if(axisOutMsgCtx.isSOAP11()) {
-            		SOAPUtils.convertSOAP12toSOAP11(response);
-            	} else {
-            		SOAPUtils.convertSOAP11toSOAP12(response);
-            	}
-            }
-
-            if (axisOutMsgCtx.getMessageID() != null) {
-                response.setRelationships(
-                        new RelatesTo[]{new RelatesTo(axisOutMsgCtx.getMessageID())});
-            }
-
-            response.setReplyTo(axisOutMsgCtx.getReplyTo());
-            response.setFaultTo(axisOutMsgCtx.getFaultTo());
-
-            if (axisOutMsgCtx.isPropertyTrue(NhttpConstants.IGNORE_SC_ACCEPTED)) {
-                response.setProperty(NhttpConstants.FORCE_SC_ACCEPTED, Constants.VALUE_TRUE);
-            }
-
             // create the synapse message context for the response
             Axis2MessageContext synapseInMessageContext =
-                    new Axis2MessageContext(
-                            response,
-                            synapseOutMsgCtx.getConfiguration(),
-                            synapseOutMsgCtx.getEnvironment());
+                    createSynapseMessageContext(response, synapseOutMsgCtx);
 
-            synapseInMessageContext.setResponse(true);
-            synapseInMessageContext.setTo(
-                new EndpointReference(AddressingConstants.Final.WSA_ANONYMOUS_URL));
-            synapseInMessageContext.setTracingState(synapseOutMsgCtx.getTracingState());
-
-            // set the properties of the original MC to the new MC
-
-            for (Object key : synapseOutMsgCtx.getPropertyKeySet()) {
-                synapseInMessageContext.setProperty(
-                        (String) key, synapseOutMsgCtx.getProperty((String) key));
-            }            
-
             // If this response is related to session affinity endpoints -Server initiated session
             Dispatcher dispatcher =
                     (Dispatcher) synapseOutMsgCtx.getProperty(
@@ -356,6 +280,128 @@
     }
 
     /**
+     * Create a new message context and copy the properties
+     *
+     * @param response the response message context
+     * @param synapseOutMsgCtx the synapse message context
+     * @return the new synapse message context
+     */
+    private Axis2MessageContext createSynapseMessageContext(MessageContext response,
+                                              org.apache.synapse.MessageContext synapseOutMsgCtx) {
+        Axis2MessageContext synapseInMessageContext =
+                new Axis2MessageContext(
+                        response,
+                        synapseOutMsgCtx.getConfiguration(),
+                        synapseOutMsgCtx.getEnvironment());
+
+        synapseInMessageContext.setResponse(true);
+        synapseInMessageContext.setTo(
+                new EndpointReference(AddressingConstants.Final.WSA_ANONYMOUS_URL));
+        synapseInMessageContext.setTracingState(synapseOutMsgCtx.getTracingState());
+
+        // set the properties of the original MC to the new MC
+        for (Object key : synapseOutMsgCtx.getPropertyKeySet()) {
+            synapseInMessageContext.setProperty(
+                    (String) key, synapseOutMsgCtx.getProperty((String) key));
+        }
+        return synapseInMessageContext;
+    }
+
+    /**
+     * Populate the Axis2 message context with the properties. This prepares this
+     * message context for the out path.
+     *
+     * @param response the response message context
+     * @param synapseOutMsgCtx the synapse message context
+     * @throws AxisFault if an error occurs while creating
+     */
+    private void populateResponseContext(MessageContext response,
+                          org.apache.synapse.MessageContext synapseOutMsgCtx) throws AxisFault {
+        MessageContext axisOutMsgCtx =
+                ((Axis2MessageContext) synapseOutMsgCtx).getAxis2MessageContext();
+
+        //Processes 'Accept-Encoding'
+        ResponseAcceptEncodingProcessor.process(response, axisOutMsgCtx);
+
+        response.setServiceContext(null);
+        response.setOperationContext(axisOutMsgCtx.getOperationContext());
+        response.setAxisMessage(axisOutMsgCtx.getAxisOperation().getMessage(
+                WSDLConstants.MESSAGE_LABEL_OUT_VALUE));
+
+        // set properties on response
+        response.setServerSide(true);
+        response.setProperty(SynapseConstants.ISRESPONSE_PROPERTY, Boolean.TRUE);
+        response.setProperty(MessageContext.TRANSPORT_OUT,
+                axisOutMsgCtx.getProperty(MessageContext.TRANSPORT_OUT));
+        response.setProperty(Constants.OUT_TRANSPORT_INFO,
+                axisOutMsgCtx.getProperty(Constants.OUT_TRANSPORT_INFO));
+        response.setTransportIn(axisOutMsgCtx.getTransportIn());
+        response.setTransportOut(axisOutMsgCtx.getTransportOut());
+
+        // If request is REST assume that the response is REST too
+        response.setDoingREST(axisOutMsgCtx.isDoingREST());
+        if (axisOutMsgCtx.isDoingMTOM()) {
+            response.setDoingMTOM(true);
+            response.setProperty(
+                    Constants.Configuration.ENABLE_MTOM,
+                    Constants.VALUE_TRUE);
+        }
+
+        if (axisOutMsgCtx.isDoingSwA()) {
+            response.setDoingSwA(true);
+            response.setProperty(
+                    Constants.Configuration.ENABLE_SWA,
+                    Constants.VALUE_TRUE);
+        }
+
+        // when axis2 receives a soap message without addressing headers it users
+        // DISABLE_ADDRESSING_FOR_OUT_MESSAGES property to keep it and hence avoid addressing
+        // headers on the response. this causes a problem for synapse if the original message
+        // it receivs (from client) has addressing and the synaspse service invocation has not
+        // engage addressing. in this case when synapse receives the response from the server
+        // addessing In handler dissable addressing since that response does not have addressing
+        // headers. synapse sends the response to its orignal client using the same message
+        // context. Then this response does not have addressing headers since it already
+        // disable. to avoid this we need to set the DISABLE_ADDRESSING_FOR_OUT_MESSAGES
+        // property state to original state.
+        if (axisOutMsgCtx.getProperty(
+                AddressingConstants.DISABLE_ADDRESSING_FOR_OUT_MESSAGES) != null) {
+
+            response.setProperty(AddressingConstants.DISABLE_ADDRESSING_FOR_OUT_MESSAGES,
+                    axisOutMsgCtx.getProperty(
+                            AddressingConstants.DISABLE_ADDRESSING_FOR_OUT_MESSAGES));
+        } else {
+            response.removeProperty(AddressingConstants.DISABLE_ADDRESSING_FOR_OUT_MESSAGES);
+        }
+
+        // copy the message type property thats used by the out message to the response message
+        response.setProperty(Constants.Configuration.MESSAGE_TYPE,
+            axisOutMsgCtx.getProperty(Constants.Configuration.MESSAGE_TYPE));
+
+        // compare original received message (axisOutMsgCtx) soap version with the response
+        // if they are different change to original version
+        if(axisOutMsgCtx.isSOAP11() != response.isSOAP11()) {
+            if(axisOutMsgCtx.isSOAP11()) {
+                SOAPUtils.convertSOAP12toSOAP11(response);
+            } else {
+                SOAPUtils.convertSOAP11toSOAP12(response);
+            }
+        }
+
+        if (axisOutMsgCtx.getMessageID() != null) {
+            response.setRelationships(
+                    new RelatesTo[]{new RelatesTo(axisOutMsgCtx.getMessageID())});
+        }
+
+        response.setReplyTo(axisOutMsgCtx.getReplyTo());
+        response.setFaultTo(axisOutMsgCtx.getFaultTo());
+
+        if (axisOutMsgCtx.isPropertyTrue(NhttpConstants.IGNORE_SC_ACCEPTED)) {
+            response.setProperty(NhttpConstants.FORCE_SC_ACCEPTED, Constants.VALUE_TRUE);
+        }
+    }
+
+    /**
      * It is possible for us (Synapse) to cause the creation of a duplicate relatesTo as we
      * try to hold onto the outgoing message ID even for POX messages using the relates to
      * Now once we get a response, make sure we remove any trace of this before we proceed any
