Asynchronous Web Services
Hi,
I would like to implement an asynchronous web service.
Here is my plan:
1. Client call the web service with some input and a URL for reporting
2. Web service check the input, and returns an error (synchroniusly) to the client if needed. If there is no error, it will start a new thread and return an OK return code to the client.
3. The new thread, will call an EJB object to actually do the business, and report back to the client, according to the URL given at step 1.
4. If I would like to limit the number of threads working at the same time, I will probably use the "producer-consumer" design pattern, which will be implemented in a "singletone" class, to create a queue of web-service calls.
My questions are:
1. Is this plan OK?
2. Is it OK to call an EJB object within a thread?
3. Is it OK to use "singletone" class within a web-server? How will it behave when using clustering? or multiple web-servers for scalability?
4. Do you have any other, easier, better ideas how to implement this?
Thanks
Guy Hudara
# 1
that's not even asynchronous...Why start those threads at all, the server does that for you already...Your client will still be waiting for a response, there is no other way (you can't implement callback systems, which is what you're really interested in I guess).
# 2
Hi,
I think I was not clear enough.
1. My services methods should perform a lengthy operations. Some of them can take up to 30 minutes. During this operation I would like to send to the client a "progress" information indicating the percentage completed.
2. In this way, the client will be able to call more than one service, each one of them will return immediatly with a unique correlator ID, and start listening to the information comming from the service using the correlator ID to display the progress information.
After all those clarifications does the plan now seems reasnoble for you? Do you think it is feasible?
What did you mean when you say: "the server does that for you already" and "you can't implement callback systems"?
Thanks
Guy
# 3
You can do this with the JAX-WS 2.x APIs. This is exactly what they do, the client runtime kicks off a thread to do a synchronous invocation of the web service and immediately returns to the client. You have a choice of using either polling or callback. Check out JAX-WS which is part of project Metro (http://metro.dev.java.net). You can download the JAX-WS spec and javadocs at: http://jcp.org/en/jsr/detail?id=224.
Check out the "async" sample included with JAX-WS to see how this can be done both ways.
Message was edited by:
dkohlert
# 4
I have a sample Asynchronous Client program that does polling. I have used JAX-WS
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.io.StringReader;
import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import javax.xml.ws.Dispatch;
import javax.xml.ws.Response;
import javax.xml.ws.Service;
public class AsyncPollingWS {
/**
* @param args
*/
public static void main(String[] args) {
try {
QName serviceName = new QName("TestWSOne", "http://testws/");
String wsdl = "http://localhost:8888/TestWSOne-TestWS-context-root/TestWSOneSoapHttpPort?WSDL";
URL address = new URL(wsdl);
QName portQName = new QName("TestWSOne", "TestWSOneSoapHttpPort");
String xmlMessage = "<ns1:getDateHence xmlns:ns1=\"http://testws/\"><ns1:daysHence xmlns:ns1=\"http://testws/\">5</ns1:daysHence></ns1:getDateHence>";
Dispatch smDispatch = null;
Service service = Service.create(address, serviceName);
service.addPort(portQName, null, address.toString());
smDispatch = service.createDispatch(portQName, Source.class, Service.Mode.PAYLOAD);
//Response<Source> response = smDispatch.invokeAsync(new StreamSource(new FileInputStream("C:\\Documents and Settings\\prashantp\\Desktop\\soapInput.xml")));
Response<Source> response = smDispatch.invokeAsync(new StreamSource(new StringReader(xmlMessage)));
while (!response.isDone()) {
System.out.println("RESPONSE PENDING...");
}
Source result = response.get();
String xmlResult = sourceToXMLString(result);
System.out.println("RESPONSE DONE !!");
System.out.println("Received Response Is : " + xmlResult);
}catch(Exception ex){
ex.printStackTrace();
}
}
private static String sourceToXMLString(Source result) {
String xmlResult = null;
try {
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
transformer.setOutputProperty(OutputKeys.METHOD, "xml");
OutputStream out = new ByteArrayOutputStream();
StreamResult streamResult = new StreamResult();
streamResult.setOutputStream(out);
transformer.transform(result, streamResult);
xmlResult = streamResult.getOutputStream().toString();
} catch (TransformerException e) {
e.printStackTrace();
}
return xmlResult;
}
}
# 5
This is another program which is based on Callback mechanism of Asynchronous invocation. This is with JAX-WS.
public class AsyncWS {
private static Service service;
public static void main(String[] args) {
try {
System.setProperty("javax.xml.soap.MessageFactory", "com.sun.xml.messaging.saaj.soap.ver1_2.SOAPMessageFactory1_2Impl");
QName serviceName = new QName("TestWSOne", "http://testws/");
String wsdl = "http://fs-sys-352:8888/TestWSOne-TestWS-context-root/TestWSOneSoapHttpPort?WSDL";
URL address = new URL(wsdl);
QName portQName = new QName("TestWSOne", "TestWSOneSoapHttpPort");
SOAPMessage message = null;
MessageFactory factory = MessageFactory.newInstance();
message = factory.createMessage();
message.getSOAPPart().setContent((Source) new StreamSource(new FileInputStream("C:\\Documents and Settings\\Desktop\\soapInput.xml")));
message.saveChanges();
Dispatch<SOAPMessage> smDispatch = null;
service = Service.create(address, serviceName);
service.addPort(portQName, null, address.toString());
smDispatch = service.createDispatch(portQName, SOAPMessage.class, Service.Mode.MESSAGE);
SOAPMessage response=null;
response = factory.createMessage();
response = smDispatch.invoke(message);
String xmlString = null;
Source result = response.getSOAPPart().getContent();
xmlString = sourceToXMLString(result);
System.out.println("Received response: " + xmlString);
}catch(Exception ex){
ex.printStackTrace();
}
}
private static String sourceToXMLString(Source result) {
String xmlResult = null;
try {
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
transformer.setOutputProperty(OutputKeys.METHOD, "xml");
OutputStream out = new ByteArrayOutputStream();
StreamResult streamResult = new StreamResult();
streamResult.setOutputStream(out);
transformer.transform(result, streamResult);
xmlResult = streamResult.getOutputStream().toString();
} catch (TransformerException e) {
e.printStackTrace();
}
return xmlResult;
}
}
And the Handler Class is :
public class MyAsyncHandler implements AsyncHandler{
public void handleResponse(Response resp) {
System.out.println("Inside MyAsyncHandler/handleResponse() !!");
try{
Source result=(Source) resp.get();
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer();
OutputStream out = new ByteArrayOutputStream();
StreamResult streamResult = new StreamResult();
streamResult.setOutputStream(out);
transformer.transform(result, streamResult);
String xmlResult = streamResult.getOutputStream().toString();
System.out.println("Output After Invoking WS -->"+xmlResult);
}catch(java.util.concurrent.ExecutionException ex){
System.out.println("ExecutionException Caught !!" + ex.getCause().getMessage());
}catch(Exception ex){
ex.printStackTrace();
}
}
# 6
Hi,No need of doing this much of hectic thing. Use Ajax call while invoking webservice.It is effective ans simpler compared with remaining.