Chapter 6. Create a web service client for a SOAP based web service 6.1. Create a standalone client
6.1.2. Create a client application using these artifacts
Int egers are defined as basic t ypes provided w it h XML Schema; t hey are not cust om t ypes t hat you have w rit t en t hat require somet hing special. T he complex t ype t hat w raps t hese t w o int egers is creat ed in order t o mat ch your W SDL, w hich uses t he document/literal st yle. Here is t he port ion of t he W SDL t hat t ells you t his:
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"></soap:binding>
<operation name="add">
<soap:operation soapAction=""></soap:operation>
<input>
<soap:body use="literal"></soap:body>
</input>
...
</operation>
Had you been using RPC and not document , t he values w ould have been passed separat ely t o t he operat ion invocat ion just like met hod paramet ers.
T he @RequestWrapper and @ResponseWrapper annot at ions capt ure informat ion t hat JAXB needs t o perform t he marshaling and unmarshaling operat ions. If your service is defined as using document/literal mode, t his annot at ion also serves t o resolve overloading conflict s.
6.1.2. Create a client application using these artifacts.
Here are t he st eps in t heir simplest form.
First , w rit e t he invoker called CalculatorInvoker.java. Navigat e t o t he t op-level direct ory t hat you passed t o t he wsimport t ool earlier. T his w as "/home/mz". You w ill w rit e your client t here.
import org.me.calculator.*;
public class CalculatorInvoker {
public static void main(String... arg) {
CalculatorWSService service = new CalculatorWSService();
CalculatorWS port = service.getCalculatorWSPort();
int result = port.add(2, 3);
System.out.println("Result: " + result);
} }
T he class in ecxample above simply creat es a service inst ance, uses it t o get t he port , and uses t he port t o call t he business met hod, add. Let 's compile it , making sure t he generat ed classes in t he current direct ory are on your classpat h:
>javac -cp . CalculatorInvoker.java
T hen you can run it :
>java -cp . CalculatorInvoker Result: 5
T here are a few considerat ions t o keep in mind w it h using generat ed client s:
T he client cannot creat e or dest roy w eb service implement at ions and has no view int o it s life cycle, w hich is handled ent irely on t he server.
A port object has no ident it y. It cannot meaningfully be compared t o ot her port object s. You cannot ask for a specific inst ance of a port . Treat service invocat ions as st at eless. T here is no mechanism w it hin Service t o handle st at e across request s.
All dat a binding is performed by JAXB.
6.1.2.1. Invoke web service synchronously or asynchronously.
Synchronous client s
By using t he synchronous model, you can develop SOAP-based w eb service client code w it hout w orrying about t he underlying prot ocol det ails. Example below show s generat ed Service subclass:
package by.boot.java;
import java.net.MalformedURLException;
import java.net.URL;
import javax.xml.namespace.QName;
name = "HelloMessengerService",
targetNamespace = "http://java.boot.by/",
wsdlLocation = "http://localhost:9999/Hello?wsdl") public class HelloMessengerService extends Service {
private final static URL HELLOMESSENGERSERVICE_WSDL_LOCATION;
static {
HELLOMESSENGERSERVICE_WSDL_LOCATION = url;
}
public HelloMessengerService(URL wsdlLocation, QName serviceName) { super(wsdlLocation, serviceName);
}
public HelloMessengerService() {
super(HELLOMESSENGERSERVICE_WSDL_LOCATION,
new QName("http://java.boot.by/", "HelloMessengerService"));
}
@WebEndpoint(name = "HelloMessengerPort") public HelloMessenger getHelloMessengerPort() { return (HelloMessenger) super.getPort(
new QName("http://java.boot.by/", "HelloMessengerPort"), HelloMessenger.class);
}
@WebEndpoint(name = "HelloMessengerPort")
public HelloMessenger getHelloMessengerPort(WebServiceFeature... features) { return (HelloMessenger) super.getPort(
new QName("http://java.boot.by/", "HelloMessengerPort"), HelloMessenger.class,
features);
} }
You can t ell t hat class above is a JAX-W S-generat ed client because of it s class-level @WebServiceClient annot at ion. T he class has t w o const ruct ors:
T he first const ruct or is t he default const ruct or. It configures t he service so t hat any dynamic proxies creat ed from it are produced by using t he W SDL document t hat w as used t o generat e t he client code.
In t he HelloMessenger example, t he t ool w as not inst ruct ed t o creat e a local copy of t he W SDL document . T his is w hy t here is an absolut e reference t o t he act ual URL at w hich t he Endpoint publisher makes t he W SDL document available. Because t his is not recommended, make sure t hat you generat e t he w eb service client code so t hat it is copied t o t he client .
One of t he implicat ions of not having a local W SDL document is t hat t he const ruct or t hrow s an except ion in cases w here t he JAX-W S run t ime cannot connect t o t he server t hat is exposing t he document .
T he second const ruct or init ializes t he service by using a specified W SDL document .
In addit ion t o t hese t w o const ruct ors, t he generat ed client has a couple of getHelloMessenger met hods w it h w hich you can get a dynamic proxy t hat binds t o t he specified w eb service endpoint . T he client uses t he default const ruct or t o connect t o inst ant iat e t he w eb service:
HelloMessengerService service = new HelloMessengerService();
T his approach can present a problem w hen you w ant t he client applicat ion t o sw it ch from t he t est environment 's w eb service endpoint t o t he product ion environment 's w eb service endpoint . T here are a couple of w ays t o override t his endpoint locat ion from your client code:
Use t he overloaded const ruct or of t he generat ed javax.xml.ws.Service subclass t hat t akes anot her W SDL document locat ion. T his supplied W SDL document can, in t urn, specify t he service endpoint locat ion of int erest .
Use t he default const ruct or, but specify t he endpoint locat ion on t he dynamic proxy ret urned by t he service.
Aft er t he HelloClient applicat ion has obt ained a HelloMessengerService inst ance, it uses t hat inst ance t o obt ain a dynamic st ub, w hich binds t o t he act ual w eb service endpoint . Example below show s t he generat ed w eb service client t ype t hat is implement ed by t he st ub:
import javax.xml.bind.annotation.XmlSeeAlso;
@WebResult(targetNamespace = "") @RequestWrapper(localName = "sayHello", targetNamespace = "http://java.boot.by/", className = "by.boot.java.SayHello")
@ResponseWrapper(localName = "sayHelloResponse", targetNamespace = "http://java.boot.by/", className = "by.boot.java.SayHelloResponse") public String sayHello(
@WebParam(name = "arg0", targetNamespace = "") String arg0);
}
T he HelloMessenger t ype is an ordinary Java int erface w it h some JAX-W S-specific annot at ions. Alt hough t he ret urn t ype of t he HelloMessengerService is of t his int erface t ype, in realit y w hat is ret urned is a dynamic st ub t hat implement s t his int erface.
Example below show s a HelloMessenger client applicat ion t hat explicit ly specifies, on t he dynamic st ub, a new w eb service endpoint locat ion:
import by.boot.java.HelloMessenger;
import by.boot.java.HelloMessengerService;
import javax.xml.ws.BindingProvider;
public class HelloClientCustomEndpoint {
public static void main(String... args) throws Exception { HelloMessengerService service = new HelloMessengerService();
HelloMessenger port = service.getHelloMessengerPort();
((BindingProvider)port).getRequestContext().put(
BindingProvider.ENDPOINT_ADDRESS_PROPERTY, "http://hello.com:69693/Hello"
);
String message = port.sayHello("Mikalai");
System.out.println(message);
} }
T he client -relevant code is highlight ed in bold. T he applicat ion cast s t he dynamic w eb service port proxy t o a javax.xml.ws.BindingProvider. T he BindingProvider is implement ed by t he dynamic client proxies and gives you access t o t he request and t he response cont ext s. T he applicat ion specifies t he endpoint address on t he request cont ext using t he BindingProvider.ENDPOINT_ADDRESS_PROPERTY propert y.
Asynchronous client s
T he asynchronous client programming model in JAX-W S is merely a convenient funct ionalit y for developing w eb service client s. It does not refer t o real asynchronous message exchanges. You can creat e asynchronous client s by configuring t he t ool t hat you use t o generat e JAX-W S w eb service client code.
JAX-W S offers t w o asynchronous programming models:
Polling client s.
Callback client s.
T hese approaches merely different iat e, in t he Java met hod, signat ures t hat are generat ed on t he client -side w eb service port int erface. W hen you enable asynchronous client s in your t ool, JAX-W S generat es t hree met hods for every operat ion t hat is defined in t he w eb service portType:
One-w ay asynchronous met hod.
An asynchronous polling met hod.
An asynchronous callback met hod.
Example below show s t he HelloMessenger client -side endpoint int erface t hat is generat ed w hen asynchronous met hod generat ion is act ivat ed by t he JAX-W S t ool:
package by.boot.java;
@WebService(name = "HelloMessenger", targetNamespace = "http://java.boot.by/")
@XmlSeeAlso({
ObjectFactory.class })
public interface HelloMessenger {
@WebMethod(operationName = "sayHello") @RequestWrapper(localName = "sayHello", targetNamespace = "http://java.boot.by/", className = "by.boot.java.SayHello")
@ResponseWrapper(localName = "sayHelloResponse", targetNamespace = "http://java.boot.by/", className = "by.boot.java.SayHelloResponse") public Response<SayHelloResponse> sayHelloAsync(
@WebParam(name = "arg0", targetNamespace = "") String arg0);
@WebMethod(operationName = "sayHello") @RequestWrapper(localName = "sayHello", targetNamespace = "http://java.boot.by/", className = "by.boot.java.SayHello")
@ResponseWrapper(localName = "sayHelloResponse", targetNamespace = "http://java.boot.by/", className = "by.boot.java.SayHelloResponse") public Future<?> sayHelloAsync(
@WebParam(name = "arg0", targetNamespace = "") String arg0,
@WebParam(name = "asyncHandler", targetNamespace = "") AsyncHandler<SayHelloResponse> asyncHandler);
@WebMethod
@WebResult(targetNamespace = "") @RequestWrapper(localName = "sayHello", targetNamespace = "http://java.boot.by/", className = "by.boot.java.SayHello")
@ResponseWrapper(localName = "sayHelloResponse", targetNamespace = "http://java.boot.by/", className = "by.boot.java.SayHelloResponse") public String sayHello(
@WebParam(name = "arg0", targetNamespace = "") String arg0);
}
T he met hod signat ures are highlight ed in bold. T he first signat ure is used t o creat e asynchronous polling client s. T he second signat ure is used t o creat e asynchronous callback client s. T he t hird signat ure is used t o creat e synchronous client s and is t he signat ure t hat is used by t he HelloClient applicat ion.
Polling clients
T he polling client programming model refers t o t he usage of t he asynchronous met hod t hat ret urns a t yped javax.xml.ws.Response. Example below show s an asynchronous HelloMessenger w eb service client applicat ion:
import javax.xml.ws.Response;
import by.boot.java.HelloMessenger;
import by.boot.java.HelloMessengerService;
import by.boot.java.SayHelloResponse;
public class HelloAsyncPollingClient {
public static void main(String... args) throws Exception { HelloMessengerService service = new HelloMessengerService();
HelloMessenger port = service.getHelloMessengerPort();
Response<SayHelloResponse> sayHelloAsync = port.sayHelloAsync("Mikalai");
while ( ! sayHelloAsync.isDone() ) { // Do something useful for now }
// Web service endpoint has now responded:
SayHelloResponse sayHelloResponse = sayHelloAsync.get();
String message = sayHelloResponse.getReturn();
System.out.println(message);
} }
T he relevant code is highlight ed in bold. T he client applicat ion invokes t he sayHelloAsync met hod, w hich ret urns a response object . T his object provides met hods t o query for response arrival, cancel a response, and get t he act ual response. T he applicat ion, in t his case, performs a busy w ait , looping unt il t he Response.isDone() met hod ret urns true, w hich indicat es t hat t he response has been received. T he applicat ion t hen fet ches t he response by using t he get() met hod. T his met hod ret urns t he response w rapper element t hat cont ains t he act ual met hod ret urn value, w hich in t his case is a simple java.lang.String object . If an endpoint t hrow s a service except ion, t he get() met hod can t hrow a java.util.concurrent.ExecutionException, w hich can t hen be queried for t he cause.
Callback clients
T he callback client programming model refers t o t he usage of t he asynchronous met hod t hat accept s an input paramet er of a t yped javax.xml.ws.AsyncHandler. Example below show s an asynchronous callback HelloMessenger w eb service client applicat ion:
import by.boot.java.HelloMessenger;
import by.boot.java.HelloMessengerService;
import by.boot.java.SayHelloResponse;
import javax.xml.ws.AsyncHandler;
import javax.xml.ws.Response;
public class HelloAsyncCallbackClient {
public static void main(String... args) throws Exception { HelloMessengerService service = new HelloMessengerService();
HelloMessenger port = service.getHelloMessengerPort();
port.sayHelloAsync("Mikalai", new AsyncHandler<SayHelloResponse>() { public void handleResponse(Response<SayHelloResponse> res) { try {
SayHelloResponse response = res.get();
String message = response.getReturn();
System.out.println(message);
} catch (Exception e) { e.printStackTrace();
} } });
} }
T he applicat ion passes in an anonymous inner class of t ype AsyncHandler. T his class has a met hod called handleResponse t hat is invoked by t he JAX-W S runt ime w hen t he message is received. T he argument t o t his met hod is of t he same t ype t hat is used for t he polling met hod, a t yped response object .
Example above does not show t hat you can save t he ret urn value of t he asynchronous met hod invocat ion int o a java.util.concurrent.Future:
Future<?> future = port.sayHelloAsync("Mikalai", ...);
As is t he case w it h t he polling response object , you can query t his object t o obt ain st at us and possibly cancel t he operat ion.