The goal here is not to delve into concepts and specifications, but show a way to create web services without the facilites (wizards) of independent tools like NetBeans with GlassFish or Eclipse with Axis.
This post was developed and tested in an environment with the following settings:
- Windows XP
- Java SE 6 (JDK)- Tomcat 6.0
The tools used were:
- Eclipse Ganymede (Java EE)
- Metro 2.1 libraries

1. The server side.
1.1. Create a dynamic web project, the project name and context that I will use is "ws", you are free to use any name of your choice, just remember to make adjustments where necessary.
1.2. Copy the Metro libraries to the WEB-INF\lib folder. The required files are: stax-api, webservices-api, webservices-extra, webservices-extra-api, webservices-rt and webservices-tools.
I'm copying the libraries directly into the project only as an exemplary way of functioning of the JAX-WS 2.2 to create the web service, but the client will work in the Java SE 6 default environment (JAX-WS 2.1). A production environment should be installed according to the instructions you see along with the Metro package libraries.
1.3. No web page in this example is needed, then go straight to the creation of the web service.
Create ws.sample.Agenda class:
package ws.sample;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
@WebService
public class Agenda {
@WebMethod
public String add(@WebParam(name="name") String name) {
return name + " added to agenda";
}
@WebMethod
public String find(@WebParam(name="name") String name) {
try {
Thread.sleep(10000);
} catch(InterruptedException e) {}
return name + " found";
}
}What you should notice in this class are the annotations. That annotations are responsible for defining our web service and will be used by JAX-WS mechanism to publish the service.1.4. Let's publish the service now.
To publish the service we will use the automatic definition documents generation of the JAX-WS 2.2, for this we need to add the definition to the negotiating servlet in the web.xml of our ws application. Add the following lines to web.xml:
<listener>
<listener-class>
com.sun.xml.ws.transport.http.servlet.WSServletContextListener
</listener-class>
</listener>
<servlet>
<servlet-name>agenda</servlet-name>
<servlet-class>
com.sun.xml.ws.transport.http.servlet.WSServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>agenda</servlet-name>
<url-pattern>/services/agenda</url-pattern>
</servlet-mapping>Note in these lines that we are using a servlet available by the JAX-WS implementation, and creating a reply address for this servlet. But we still need that this address be directed to our class created to provide the service, this is done through a standardized file, the sun-jaxws.xml:<?xml version="1.0" encoding="UTF-8"?>
<endpoints
xmlns="http://java.sun.com/xml/ns/jax-ws/ri/runtime"
version="2.0">
<endpoint
name="agenda"
url-pattern="/services/agenda"
implementation="ws.sample.Agenda" />
</endpoints>Create this file in the WEB-INF folder of your ws application and note that, in this file, the settings of the servlet being linked to the created service class. Let's test the web service publishing the ws application and putting the server running. Visit the pages of the service and make sure there were no problems:
http://localhost/ws/services/agenda and http://localhost/ws/services/agenda?wsdl
* remember to add the port if your server is configured with a port other than 80.
2. The client side.
2.1. Create an empty java project, the project name that I will use will be "ws_cliente", you are free to use any name of your choice, just remember to make adjustments where necessary.
2.2. Let's generate the artifacts for connection with our web service.
Create the binding file async-client.xml in the project root:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<bindings
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns="http://java.sun.com/xml/ns/jaxws">
<bindings node="wsdl:definitions">
<enableAsyncMapping>true</enableAsyncMapping>
</bindings>
</bindings>Create wsimport.bat (or sh) file in the project root:%JDK_PATH%\bin\wsimport.exe -s src -d bin -keep
http://localhost/ws/services/agenda?wsdl -b async-client.xmlThe batch file uses the java standard wsimport to the artifacts creation, the reference to the binding file is required to enable the asynchronous methods creation.* Set correctly the location of wsimport.exe which is located in the JDK.
* If the directory structure of source and compiled is not equal, make the necessary corrections.
Run the batch file. Ready, artifacts have been generated and are available for use.
2.3. Create ClienteAgenda class:
import java.awt.Toolkit;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import javax.xml.ws.AsyncHandler;
import javax.xml.ws.Response;
import ws.sample.Agenda;
import ws.sample.AgendaService;
import ws.sample.LocalizarResponse;
public class ClienteAgenda {
private static long start;
public static void main(String[] args) {
AgendaService servico = new AgendaService();
Agenda port = servico.getAgendaPort();
//------------------------------------------------------------------------
start = System.currentTimeMillis();
System.out.println(String.format("\n%06d > Synchronous connection...", 0));
String ret = port.add("John Doe");
System.out.println(String.format("%06d > %s",
System.currentTimeMillis() - start,
ret));
//------------------------------------------------------------------------
start = System.currentTimeMillis();
System.out.println(String.format("\n%06d > Asynchronous connection 1...",
System.currentTimeMillis() - start));
Response<FindResponse> resp =
port.findAsync("John Doe");
System.out.print("Request sent. Wainting for response");
while(!resp.isDone()) {
System.out.print(".");
try {
Thread.sleep(250);
} catch(InterruptedException e) {}
}
System.out.print("\n");
try {
System.out.println(String.format("%06d > %s",
System.currentTimeMillis() - start,
resp.get().getReturn()));
} catch(InterruptedException e) {
e.printStackTrace();
} catch(ExecutionException e) {
e.printStackTrace();
}
//------------------------------------------------------------------------
start= System.currentTimeMillis();
System.out.println(String.format("\n%06d > Asynchronous connection 2...",
System.currentTimeMillis() - start));
Future<?> future = port.findAsync("John Doe",
new AsyncHandler<FindResponse>(){
@Override
public void handleResponse(Response<FindResponse> res) {
try {
System.out.println(String.format("%06d > %s",
System.currentTimeMillis() - start,
res.get().getReturn()));
} catch(InterruptedException e) {
e.printStackTrace();
} catch(ExecutionException e) {
e.printStackTrace();
}
}
});
System.out.println("Request sent. Wainting for response...");
while(!future.isDone()) {
try {
Toolkit.getDefaultToolkit().beep();
Thread.sleep(1000);
} catch(InterruptedException e) {}
}
System.out.println("\nEncerrando cliente");
}
}* The names of the artifacts for the web service may vary, so make the necessary adjustments.Compile and run the ws_cliente application and observe the result.
3. Remarks
In the service add method was made a normal connection (synchronous) where the method returns only after the completion of the execution, and we can observe the time spent for this execution. As the service executes the request quickly, we have no problem.
However the service locate method has a small delay to answer the client, and this delay can be inconvenient, depending on delay and application, since the user will think that your application is "locked", so it's interesting to implement some visual information as a progress bar, and/or release the application usage to the user. Through two examples of asynchronous methods you can verify that the application execution is continued immediately after the request to the time consuming service method, not "locking" the application, and the response is later recovered. Between the two examples of asynchronous methods, you should notice the difference in the way to retrieve value, where there is a control to scan for available response on the first and in the second there are a handler that will be notified immediately when the response is available.

Testing comments style
ReplyDelete