I'm building a middleware based on Mule ESB, implementing Asyncronous Web Services.
I have a client who sends Soap requests to my ESB endpoint implemented with CXF Jax-ws service with WS-Addressing feature enabled, via SoapUI. I send the response string "Hello" and start processing the input parameters to make the asyncronous reply to the client, who has a callBack web service endpoint.
The request has the correct Soap Header, with the tag ReplyTo, which has the address of the callBack endpoint in the client.
Here is my server jax-ws web service code:
#WebService(serviceName = "OrderReceive")
#Addressing
public class OrderReceive {
public String perform(String id, long creditCardNumber, List<Product> products) {
//Save values to process the async reply
setSessionVariable(id,creditCardNumber,products);
return "Hello, i will send the response soon";
}
}
The thing is my web service is autorespoding to the ReplyTo address and i don't have any control of the response.
Is it possible to intercept that response, and set the correct body of it?
Why is my web service autoresponding?
Regards
this is why I love stackoverflow. I have never heard about this!!!
Your "automatic response" can be caused by a behavior in mule:
If mule detects the reply_to property in the message , launches an automatic response to that endpoint. This is for request-reply funcionality in jms, but maybe is affecting the http connector.
Source of this :
Automatic response when sending message
-------------------*------------------------
After my researching I found that the proper behaviour of ws-addressing is:
client -- SOAP request ( on port A ) --> server
client <-- HTTP 202 ( "Hello, i will send the response soon" HTTP body ) --- server
client <-- SOAP response ("Response is ready!!" on port B ) --- server
Source :jax-ws 2.2.8 and ws-addressing
To make this possible , we need:
1.- Server Endpoint : mule/cxf
2.- Client of service : soapui
3.- Callback Endpoint : to recieve the async response (I think this is in mule)
Understood this, the offical documentation about it is sad :
MULE 3.7 Enabling WS-Addressing
I think you need the CallBack Enpoint to create and execute the async response. I have not found anything in mule :(.
Here some links of java implementation, no mule:
Asynchronous web services with WS-Addressing
Invoke a single port async service using JAX-WS and WS-Addressing
-------------------*------------------------
An alternative solution could be :
1.- Web Service in mule/cxf without addressing.
2.- Inside operation method :
public Response operation ( Request requestPayload ) {
MuleClient client = new MuleClient(muleContext);
client.dispatch("jms://my.queue", requestPayload , null);// this is async
return new Response("Hello, i will send the response soon.");
}
Reference : Using the Mule Client
3.- Create a jms inbound endpoint listen to : jms://my.queue
<flow>
<jms:inbound-endpoint queue="my.queue" >
<do something>
<launch a response to client>
</flow>
This could be :
a.- By email to client
b.- Consume a service published by client
c.- SMS notification
d.- Whatever
This approach can be more flexible and support future crazy requirements.
If you need some help with mule cxf service or jms, let me know to help you!!
http://jrichardsz.github.io/
Related
I'm using Apache Camel 2.19.2 DSL and trying to consume a soap service hosted in a different server. My camel code is -
SoapJaxbDataFormat soap = new SoapJaxbDataFormat("<Service Class Package Path>");
soap.setContextPath("Root element package path");
soap.setVersion("1.1");
from("direct:invokeSOAPService")
.process(new Processor1()) //Constructs the main message body that will be set as body of the soap-Envelope
.removeHeaders("*")
.setHeader(Exchange.SOAP_ACTION, simple("Soap Action of the service from ASDL"))
.setHeader(Exchange.HTTP_METHOD, simple("POST"))
.setHeader(Exchange.CONTENT_TYPE, constant("text/xml"))
.marshal(soap)
.log(LoggingLevel.DEBUG, LOG, "Request xml===========>${body}")
.log(LoggingLevel.DEBUG, LOG, "Posting request to server url")
.to("cxf://http://<ip>:<port>/<wsdl server location without ?wsdl>?serviceClass=<qualified service class name without .class extension>&dataFormat=MESSAGE&synchronous=true&continuationTimeout=100000&serviceName={<target-name-space-name>}<service-name>&endpointName={<target-name-space-name>}<service port name>")
.log(LoggingLevel.DEBUG, LOG, "Posted request successfully to server url")
.log(LoggingLevel.DEBUG, LOG, "Received response from server ==========>${body}")
.end();
Application is able to generate the soap-request and able to post the same to the server and server is sending back the soap response (as confirmed by the owner of the soap server) but I can't see the response at my application end.
it is printing the request xml using below log:
Request xml===========> <soap request xml>
Posting request to server url
**org.apache.camel.component.cxf.feature.AbstractDataFormatFeature.removeInterceptors><removing the interceptor org.apache.cxf.interceptor.ClientFaultConverter#58811c5b
org.apache.camel.component.cxf.feature.AbstractDataFormatFeature.removeInterceptors><removing the interceptor org.apache.cxf.jaxws.interceptors.WrapperClassInInterceptor#1d25437
org.apache.camel.component.cxf.feature.AbstractDataFormatFeature.removeInterceptors><removing the interceptor org.apache.cxf.jaxws.interceptors.HolderInInterceptor#4451805d
org.apache.camel.component.cxf.feature.AbstractDataFormatFeature.removeInterceptors><removing the interceptor org.apache.cxf.jaxws.interceptors.WrapperClassOutInterceptor#2514dd3d
org.apache.camel.component.cxf.feature.AbstractDataFormatFeature.removeInterceptors><removing the interceptor org.apache.cxf.jaxws.interceptors.HolderOutInterceptor#75a76e00**
Posted request successfully to server url
Received response from server ==========> **PRINTING THE REQUEST XML**
Could you please help me to understand the issue, why camel is not able to capture the response! It is because of those camel internal remove methods?
Could you please help me to capture the response.
My task is to develop async/sync responses using spring-ws. Im using JMS(ActiveMQ) for request processing and return DefferedResult<?>. The response from Endpoint should be following:
FOR ASYNC REQUEST
1.
Client (Request)--> EndPoint(Server
Client <--(Response) HTTP.202 Endpoint(Server)
2. Processing request via JMS
Client(Endpoint) <--(Response) Endpoint
FOR SYNC REQUEST
1.
Client (Request)--> EndPoint(Server)
Client(Endpoint) <--(Response) Endpoint
P.S. If im trying to return DefferedResult in SYNC request case - it's not work
If im trying to use ReplyTo:Client(Endpoint) - it's not work
What's the best approach to solve my problem? Is there any examples?
I have to invoke several webservices using WS-Addressing.
When invoking a webservice, the ReplyTo is set to a callback endpoint implemented by me.
The client is generated from the target WSDL using async with
<enableAsyncMapping>true</enableAsyncMapping>
which generates the Async version for each webservice with the following signature:
javax.xml.ws.Response<SampleWebServiceOutput> sampleWebService(SampleWebServiceInput input)
When invoking sampleWebService like,
Response<SampleWebServiceOutput> response = clientWsPort.sampleWebService(input);
if the request is sucessful, the server will return 202 Accepted however I can't figure out how to get it.
If I use response.get(), it will block forever since the response is sent to my callback url (WSA-Addressing Reply To)
Any clues how to know for sure if the server successfully accepted the request ?
Thank you.
Apparently the response returned when you set a different reply-to address results in a null response, which could explain why it is hanging when you call response.get().
The recommended solution is to use something like getResponseContext(), which is called from the binding.
I`m looking answer to question how it is possible to check what exacly request body and headers i send to restful webservice using restful client. For example and following code bellow:
// client object
Client client = javax.ws.rs.client.ClientBuilder.newClient();
// Web target
WebTarget webTarget = client.target(BASE_URI)
// Sending a request
webTarget
.request(MediaType.APPLICATION_XML)
.cookie(cookie)
.post(Entity.entity(params,MediaType.APPLICATION_XML));
how to debug, monitor or overview this request? It is possible?
Might be easiest to use something like Postman extension for Chrome: https://chrome.google.com/webstore/detail/postman-rest-client/fdmmgilgnpjigdojojpjoooidkmcomcm?hl=en
This will allow you to set all relevant headers and the request body and easily debug API calls.
I am using com.sun.httpserver.HttpServer and javax.xml.ws.Endpoint to publish a JAX-WS web service, which was generated by running wsimport on an existing WSDL and implementing the genereated service interface. All this was part of JDK 1.6 (JAX-WS RI 2.1.6). My web service, running as a Java program without an additional Web container is supposed to simulate an existing SOAP service that was implemented using Apache Axis, running on Tomcat. Existing clients are likewise implemented using Apache Axis.
The problem I am having is that Soap operation calls from the clients to my JAX-WS service hang for a while, and then end with socket time-out on the client's side. This occurs even though the JAX-WS service is returning the SOAP response right away.
Inspecting the packets with tcpdump and wireshark, I noticed that with the existing Axis web service, after the SOAP response is sent from the server to the client, the server sends a "FIN ACK" packet, to which the clients responds with "FIN ACK". This concludes all packets pertinent to the SOAP operation. On the other hand, when running with the JAX-WS service, the server does not send a "FIN ACK" after the SOAP response is sent to the client. And the client seems to continue reading the socket input stream for it.
This leads me to believe that the JAX-WS web service stack is somehow keeping the socket open, even after the response to a SOAP call has been sent. And it appears that the client is expecting the socket to close at the end of a SOAP operation. Unfortunately, I cannot modify the client to behave differently.
Is there a way to configure the Endpoint or the HttpServer instances that I am using to publish the JAX-WS service to always close a socket after each SOAP operation?
I tried setting the system property http.keepAlive to false, but this did not seem to make any difference.
Thanks in advance for your help.
I found a way around this problem, but it's not very elegant. Essentially I get the HttpHandler object from the HttpContext after it's been created by the Endpoint.publish operation. And I call its handle() method from another HttpHandler class I wrote, which follows it up by sending a HttpHeader with "Connection" set to "close". Something like this:
...
HttpServer server = HttpServer.create(myInetSocketAddress, 5);
HttpContext context = server.createContext(mySoapPath);
Endpoint endpoint = Endpoint.create(mySoapImpl);
endpoint.publish(context);
MyHandler handler = new MyHandler(context.getHandler());
server.removeContext(mySoapPath);
server.createContext(mySoapPath, handler);
server.start();
...
private class MyHandler implements HttpHandler {
private HttpHandler h;
public MyHandler(HttpHandler in) {
h = in;
}
public void handle(HttpExchange t) throws IOException {
h.handle(t);
t.getResponseHeaders().set("Connection", "close");
t.sendResponseHeaders(200, 0);
t.close();
}
}
It works for my current needs, but it just seems like there's got to be a better way. Please do post if you have another solution. Thanks!
When I had this problem in Java 8 all requests from JAX-WS RI 2.2.9 had header: Connection: keep-alive
To force closing TCP connection after each request I had to change this header to Connection: close
I had done it by:
SoapService service = new SoapService(url);
SoapPort port = service.getSomePort();
Map<String, List<String>> requestHeaders = new HashMap<>();
requestHeaders.put("Connection", Collections.singletonList("close"));
BindingProvider bindingProvider = (BindingProvider)port;
bindingProvider.getRequestContext().put(MessageContext.HTTP_REQUEST_HEADERS, requestHeaders);
where:
public static final String HTTP_REQUEST_HEADERS = "javax.xml.ws.http.request.headers";