I intercept the incoming and outgoing soap messages using a SoapHandler like this:
#Override
public boolean handleMessage(SOAPMessageContext context) {
boolean isResponse = (Boolean)context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if(!isResponse){
logger.debug("MySoapHandler.handleMessage(): this is a soap request");
SOAPMessage soapMsg = context.getMessage();
SOAPMessage = createNewSoapRequest(soapMsg);
context.setMessage(newSoapMsg);
}
else {
logger.debug("MySoapHandler.handleMessage(): this is a soap response");
SOAPMessage soapMsg = context.getMessage();
SOAPMessage newSoapMsg = createNewSoapResponse(soapMsg);
context.setMessage(newSoapMsg);
}
return true;
}
I receive the incoming soap message and replace it with a new one and send it on its way. I can monitor the incoming message and its replacement and everything looks right. If I comment out the incoming part and test the outgoing part by sending the correct request using SoapUI, the outgoing soap response is intercepted and replaced with a new message. That too seems to work ok.
When I un-comment the incoming portion and let er' rip, the incoming one is triggered correctly, but the outgoing response seems to get triggered prematurely, before the main code for generating it has completed. Can anyone shed some light?
Related
I'm trying to implement a soap service consumer in Java, using spring WebServiceGatewaySupport.
When I'm using curl to consume the service as below, it is giving proper response.
curl -d #request.xml -H 'SOAPAction:abc:mnEvent#DoAction' https://myhost.org/cd/doAction.jsp
I'm trying to implement the same using JAVA, by adding following HttpHeaders in a template class inheriting from WebServiceGatewaySupport
public O callWebService(String url, I request) {
return (O) getWebServiceTemplate().marshalSendAndReceive(url, request, new WebServiceMessageCallback() {
#Override
public void doWithMessage(WebServiceMessage message) {
TransportContext transportContext = TransportContextHolder.getTransportContext();
HttpComponentsConnection connection = (HttpComponentsConnection) transportContext.getConnection();
connection.getHttpPost().addHeader("SOAPAction", "abc:mnEvent#DoAction");
}
});
}
With this code, I'm getting an error message like below.
SOP-330006 The method 'DoAction, ""' is not defined in SOAP service 'abc:mnEvent'.
What do I miss here when moving curl command to JAVA?
The error message SOP-330006 The method 'DoAction, ""' is not defined in SOAP service 'abc:mnEvent'. indicates, there are two soap actions in the request.
Explicit SoapAction added in HttpHeader
Implicit SoapAction in SoapMessage
To avoid this issue, we need to remove the soapAction from header and set it in SoapMessage.
SaajSoapMessage soapMessage = (SaajSoapMessage) message;
soapMessage.setSoapAction("abc:mnEvent#DoAction");
I will be extremely grateful if someone share his experience in solving the following problem.
I have a SOAP service in the JDK implementation (which is Metro, I believe).
For the logging purpose we need to extract the body of both the incoming request and generated response.
I try to fetch it by implementing a SOAPHandler on the server side.
I configure handler as a Spring bean.
All the examples I found essentially replicate the example from the Oracle documentation: https://docs.oracle.com/cd/E23943_01/web.1111/e13734/handlers.htm#WSADV170:
public boolean handleMessage(SOAPMessageContext messageContext)
{
Boolean outboundProperty = (Boolean)
messageContext.get (MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (outboundProperty.booleanValue()) {
System.out.println("\nOutbound message:");
} else {
System.out.println("\nInbound message:");
}
System.out.println("** Response: "+messageContext.getMessage().toString());
return true;
}
Here one reads one of the Boolean properties of the SOAP message context which, as I see it, corresponds to either request or response.
But debugger in my experiments never enters the branch corresponding to response (else-branch). How is such handler supposed to trace both request and response?
I also wonder what message is read as messageContext.getMessage(): is it incoming (request) or outbound (response)
I wonder now is it possible indeed by implementing handleMessage() method to get access to both request and response?
Does a single handler intercepts both request and its response?
Did I misunderstand the example?
And ... SOAPHandler - is it a specific instance for every request (request-response pair)?
Thank you
Try this for SoapHandler:
Boolean isRequest = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (isRequest) {
//handle request
} else {
//handle response
}
And this for LogicalHandler:
Boolean outboundProperty = (Boolean)
messageContext.get (MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (outboundProperty.booleanValue()) {
System.out.println("\nOutbound message:");
} else {
System.out.println("\nInbound message:");
}
Some background: This is a Weblogic Web Services created Service client creates via Eclipse. I believe this uses clientgen behind the scenes.
I'm trying to make a SOAP call that requires preemptive Basic Authentication. The request is being sent but the Mimeheaders I'm setting are not going with it. The recipient of the call has informed me that the request itself is coming through but any mimeheaders I set are not.
The service call is rather simple.
DescriptionService service = new DescriptionService(wsdlLocation, new QName("urn:descriptionService.service.company.com", "DescriptionService"));
service.setHandlerResolver(new HandlerResolver() {
#SuppressWarnings("rawtypes")
#Override
public List<Handler> getHandlerChain(final PortInfo portInfo) {
final List<Handler> handlerList = new ArrayList<Handler>();
handlerList.add(new SOAPDescriptionServiceHeaderHandler());
return handlerList;
}
});
DescriptionServicePortType portType = service.getDescriptionServicePort();
DescriptionRequest request = new DescriptionRequest();
request.setId(id);
DescriptionResponse description = portType.describe(request);
The handler is where I set the Mimeheaders:
#Override
public boolean handleMessage(final SOAPMessageContext context) {
final Boolean outboundProperty = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
final SOAPMessage message = context.getMessage();
if (outboundProperty.booleanValue()) {
try {
MimeHeaders mimeheaders = message.getMimeHeaders();
String encodedAuth = Base64.encode(new String("un:pw").getBytes());
mimeheaders.addHeader("Authorization", "Basic " + encodedAuth);
this.logMessage(message, outboundProperty.booleanValue(), false);
} catch (final Exception e) {
// Log Error
}
} else {
this.logMessage(message, outboundProperty.booleanValue(), false);
}
return true;
}
It does hit this handler and set the mimeheaders. If I set a break point and look at the mime headers before it leaves the handleMessage method, I can see that they are set.
I'm able to call the request and get a response in SoapUI. I set up preemptive basic auth and it works fine. When I send the request through the Java Client, I get no response and actually get an error that says it's the incorrect content type. I believe this error is referring to the fault response as I don't actually get the response (doesn't hit the handleMessage() method in the handler either) and I know the request is going through with text/xml which is what the error is asking for.
I'm unsure if it has something to do with the "preemptive" requirement? Is there a way to set basic auth set up this way as preemptive?
Thoughts?
Any assistance would be appreciated.
Basic Auth is done at the HTTP layer, not the SOAP layer, so you need to configure the underlying HTTP library. (MIME headers have nothing to do with it)
For example for CXF, have a look at this question HTTP basic authentication through CXF interceptor not working
I need to get the SOAP message from exchange object I receive in my spring bean.
I have a camel route, which routes from service endpoint to my java bean. Java Bean and Camel route declared in spring looks like this:
<bean id="processor" class="com.groupgti.esb.camel.wrapper.gradireland.userregistration.UserRegistrationProcessor">
<camel:route id="route">
<camel:from uri="cxf:bean:myListenerEndpoint?dataFormat=PAYLOAD&synchronous=true" />
<camel:bean ref="processor" />
<camel:to uri="cxf:bean:myTargetEndpoint"/>
</camel:route>
In my java bean I receive the exchange object:
#Override
public SOAPMessage processMessage(Exchange exchange) {
Object object = exchange.getIn().getHeaders().get("CamelCxfMessage");
LOGGER.debug("Object: " + object);
SOAPMessage message = null;
if (object instanceof SOAPMessage) {
message = (SOAPMessage) object;
LOGGER.debug("Got message: " + message);
}
LOGGER.debug("Sending message...");
return message;
}
The problem is that I can not get the SOAP message out of the exchange. I camel web site, here I found that I have to use this to get the SOAP message:
SOAPMessage soapMessage = (SOAPMessage) exchange.getIn().getBody(List.class).get(0);
But his gives me NullPointerException somewhere deep in exchange.
I have tried to debug and see the object tree. I found that I can get the message like this:
SOAPMessage soapMessage = (SOAPMessage) exchange.getIn().getHeaders().get("CamelCxfMessage");
But this gives me this exception:
org.apache.camel.ExpectedBodyTypeException: Could not extract IN message body as type: interface javax.xml.transform.Source body is: null
I am stuck here. Maybe someone know where can be the problem?
PAYLOAD mode is not quite the easy way, maybe you should try the POJO mode for CXF, and get rid of SoapMessage. You will have to declare a POJO with JAXB annotations, like
#XmlAccessorType(XmlAccessType.FIELD)
public class Registration {
private Long roomNumber;
...
}
This will allow you to work directly on the Registration class in your processors (which I assume is your final goal).
Registration registration = exchange.getIn().getBody(Registration.class);
If you persist with PAYLOAD mode, note that you can write
SOAPMessage soapMessage = exchange.getIn().getHeader(CxfConstants.CAMEL_CXF_MESSAGE, SOAPMessage.class);
I'm trying to a write simple REST Java web-service. I use Provider interface on the server side and Dispatch on the clients. I'm trying to transmit a value in header of POST request but there is some problem.
My client code:
private void invoke(Dispatch<Source> dispatch
Object data) {
Map<String, Object> request_context = dispatch.getRequestContext();
request_context.put(MessageContext.HTTP_REQUEST_METHOD, "POST");
request_context.put("org.kpi.asd", "SOME TEXT");
StreamSource source = make_stream_source(data.toString());
dispatch.invoke(source);
}
My server code:
public Source invoke(Source request) {
// Filter on the HTTP request verb
if (ws_ctx == null) throw new RuntimeException("DI failed on ws_ctx.");
// Grab the message context and extract the request verb.
MessageContext msg_ctx = ws_ctx.getMessageContext();
String aaa = (String) msg_ctx.get("org.kpi.asd");
}
On server: aaa is null. I can't understand why. Help me, please (:
the message context is not where you set arbitrary http headers. there is another property in the message context which contains the http headers, see HTTP_REQUEST_HEADERS.