|
|
| By Krishnamohan (Krishna) Meduri, Marina Sum, August 11, 2006 |
|
This article describes how to build and test Web services that are based on Java API for XML Web Services (JAX-WS) 2.0 with the built-in capabilities of the NetBeans 5.0 IDE and the plug-in for Sun Java System Web Server 7.0 (henceforth, Web Server 7.0), now in Technology Preview 2. In this article, you also learn how to deploy and debug Web services.
This article assumes the following:
Note: Some of the URLs in this article contain localhost and assume that the server instance is running on localhost on port 80. Replace localhost with hostname : portnumber, as appropriate.
Before building a Web service, first create a Web application:
HelloWebService in the Project Name text field, specify the directory in the Project Location text field, and choose Sun Java System Web Server 7.0 from the Server drop-down list.
Figure 1: Creating a Web Application (Click image for larger view.)
|
Now create a Web service, starting from a service endpoint. Eventually, you will turn the Web application you just created into a Web service.
First, create and add a service class to the HelloWebService Web application:
ServiceImpl in the Class Name text field and my.sample.server in the Package text field. Click Finish. ServiceImpl.java under Source Packages to open the file for editing. hello(java.lang.String) operation and specify the portType name, the service name, and the target namespace with JAX-WS 2.0 annotations, as follows.
package my.sample.server;
import javax.jws.WebParam;
import javax.jws.WebService;
import javax.jws.WebMethod;
/**
* A simple Java class that will become a Web service.
*/
@WebService(name="Hello", serviceName="HelloService", targetNamespace="http://example.com")
public class ServiceImpl {
@WebMethod
public String hello(@WebParam(name="name") String s) {
System.out.println("Service received: " + s);
return "Hello "+s;
}
}
|
Next, modify the web.xml file to specify the JAX-WS servlet class and the servlet context listener:
web.xml file and choose Edit from the context menu to open the file for editing.
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://www.oracle.com/webfolder/technetwork/jsc/xml/ns/j2ee/index.html"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.oracle.com/webfolder/technetwork/jsc/xml/ns/j2ee/index.html
#"
version="2.4">
<listener>
<listener-class>com.sun.xml.ws.transport.http.servlet.WSServletContextListener
</listener-class>
</listener>
<servlet>
<servlet-name>my_service</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>my_service</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
<welcome-file-list>
<welcome-file>
index.jsp
</welcome-file>
</welcome-file-list>
</web-app>
|
Next, create a sun-jaxws.xml file, which is used by the JAX-WS runtime to specify the implementation class and relative URL for the service endpoint. Create that file under Web Pages/WEB-INF, as follows:
sun-jaxws in the File Name text field. Click Next. sun-jaxws.xml file for editing. Make its content read as follows:
<?xml version="1.0" encoding="UTF-8"?>
<endpoints xmlns="#" version="2.0">
<endpoint
name="Hello"
implementation="my.sample.server.ServiceImpl"
url-pattern="/hello"/>
</endpoints>
|
As a final step, add the Ant target -pre-dist to the project's build.xml file:
build.xml for editing. -pre-dist Ant target to build.xml, as follows.
<!-- Overrides the build-impl.xml target to create the server artifacts that will be
included in the WAR file. -->
<target name="-pre-dist">
<taskdef name="wsgen" classname="com.sun.tools.ws.ant.WsGen">
<classpath path="${javac.classpath}:${j2ee.platform.classpath}"/>
</taskdef>
<wsgen
debug="true"
keep="true"
destdir="build/web/WEB-INF/classes"
resourcedestdir="build/web/WEB-INF/classes"
sei="my.sample.server.ServiceImpl">
<classpath>
<pathelement path="${javac.classpath}:${j2ee.platform.classpath}"/>
<pathelement location="${java.home}/../lib/tools.jar"/>
<pathelement location="build/web/WEB-INF/classes"/>
</classpath>
</wsgen>
</target>
|
After compiling your service class but before creating the WAR file, the NetBeans IDE calls the -pre-dist target. That target calls the wsgen Ant task, which creates the Java Architecture for XML Binding (JAXB) and JAX-WS files that are required for the Web service. For details on wsgen, see the JAX-WS documentation.
Now build and deploy the project:
HelloWebService.war file. Next, run the Web project by choosing Run > Run Main Project from the main menu. The NetBeans IDE opens http://localhost/HelloWebService in the browser and shows the welcome page ( index.jsp in this case). To see the related information for HelloWebService, go to http://localhost/HelloWebService/hello.
Note this optional but helpful procedure:
/hello in the Relative URL text field. http://localhost/HelloWebService/hello in this case, in a Web browser. That way, you can verify that the Web service has been deployed and browse the Web Services Description Language (WSDL) file. You can also edit the service class and verify the changes in the WSDL file by simply pressing F6 to rebuild and deploy the service.Normally, the Hello service information is displayed in the browser as follows, which indicates that deployment was successful.
|
Port Name
|
Status
|
Information
|
|---|---|---|
|
Hello
|
ACTIVE
|
Address:
http://localhost/HelloWebService/hello WSDL: http://localhost/HelloWebService/hello?wsdl Port QName: {http://example.com}HelloPort Implementation class: my.sample.server.ServiceImpl |
The simplest way to test the Web service is by using the Web Services Registry in the NetBeans IDE. Follow these steps:
http://localhost/HelloWebService/hello?wsdl in this case.
Figure 2: Displaying the Web Service Information
|
hello() operation.
Figure 3: Testing the
hello() Operation |
To test the Web service with a JUnit test as a client, use the test capabilities in the NetBeans 5.0 IDE. Follow these steps:
ServiceTest in the Class Name text field and my.sample.test in the Package text field. Click Finish. ServiceTest.java for editing and implement the testService() method, as follows.
package my.sample.test;
import junit.framework.*;
import my.sample.test.generated.Hello;
import my.sample.test.generated.HelloService;
public class ServiceTest extends TestCase {
public ServiceTest(String testName) {
super(testName);
}
protected void setUp() throws Exception {
}
protected void tearDown() throws Exception {
}
// TO DO: Add test methods here. The name must begin with "test." For example,
public void testService() {
HelloService service = new HelloService();
Hello proxy = service.getHelloPort();
String request = "Sun Java System Web Server 7.0 User";
String response = proxy.hello(request);
System.out.println(response);
}
}
|
build.xml file. localhost with hostname : portnumber, as appropriate, in the -pre-compile-test Ant target below and add the target.
<!-- Overrides the build-impl.xml target to start the server and generate client artifacts
before building the test. -->
<target name="-pre-compile-test">
<taskdef name="wsimport" classname="com.sun.tools.ws.ant.WsImport">
<classpath path="${javac.classpath}:${j2ee.platform.classpath}"/>
</taskdef>
<!-- Use "debug" or "run" here. -->
<antcall target="run"/>
<echo>running wsimport</echo>
<wsimport
debug="true"
keep="true"
destdir="test"
package="my.sample.test.generated"
wsdl="http://localhost/HelloWebService/hello?wsdl"/>
</target>
|
-pre-compile-test. When that target is run, the IDE ensures that the service is built and deployed and, if necessary, rebuilds the service. For details on wsimport, see the JAX-WS documentation. -init-macrodef-junit Ant target and append ${j2ee.platform.classpath} to the classpath, as follows.
<target name="-init-macrodef-junit">
<macrodef name="junit" uri="http://www.netbeans.org/ns/web-project/2">
<attribute name="includes" default="**/*Test.java"/>
<sequential>
<junit showoutput="true" fork="true" dir="${basedir}"
failureproperty="tests.failed" errorproperty="tests.failed">
<batchtest todir="${build.test.results.dir}">
<fileset dir="${test.src.dir}" includes="@{includes}"/>
</batchtest>
<classpath>
<path path="${run.test.classpath}:${j2ee.platform.classpath}"/>
</classpath>
<syspropertyset>
<propertyref prefix="test-sys-prop."/>
<mapper type="glob" from="test-sys-prop.*" to="*"/>
</syspropertyset>
<formatter type="brief" usefile="false"/>
<formatter type="xml"/>
</junit>
</sequential>
</macrodef>
</target>
|
-init-macrodef-junit target of the project's build-impl.xml file. testService() to "World" and run the client again, you will see "Hello World."To debug Web applications, right-click the project name in the NetBeans IDE and choose Debug Project from the context menu. The NetBeans IDE then starts the Web Server 7.0 instance in debug mode.
Alternatively, you can enable debugging as follows:
https://localhost:8989/, assuming that the installation is on localhost with the default settings. Next, in the NetBeans IDE:
7896 in the Port text field. Click OK. See Figure 4.
Figure 4: Debugging in the NetBeans IDE
|
The debugger stops executing the program at the breakpoint you have set in the application.
To set a breakpoint, right-click a Java statement and choose Toggle Breakpoint (Ctrl+F8) from the context menu. You can set breakpoints in both service code and client code.
When debugging is complete, choose Run > Finish Debugger Session from the main menu to end the process.
This appendix describes how to create a Web service from WSDL. As an example, use the AddNumbers.wsdl file in the JAX-WS2.0/samples/fromwsdl directory.
Follow these steps:
AddNumbers.wsdl file to the HelloWebService/web/WEB-INF/wsdl directory. <servlet-mapping> entry to the web.xml file.
<servlet-mapping>
<servlet-name>my_service</servlet-name>
<url-pattern>/addNumbers</url-pattern>
</servlet-mapping>
|
<endpoint> entry to the sun-jaxws.xml file.
<endpoint name="AddNumbers"
implementation="my.sample.server.AddNumbersImpl"
wsdl="WEB-INF/wsdl/AddNumbers.wsdl"
service='{http://duke.org}AddNumbersService'
port='{http://duke.org}AddNumbersPort'
url-pattern="/addNumbers"/>
|
-pre-compile target, to be executed before the compile target, with the wsimport task, as follows.
<!-- Overrides the -pre-compile target in build.xml to create jax-ws java artifacts that
will be created and compiled to the WEB-INF/classes directory. -->
<target name="-pre-compile">
<taskdef name="wsimport" classname="com.sun.tools.ws.ant.WsImport">
<classpath path="${javac.classpath}:${j2ee.platform.classpath}"/>
</taskdef>
<echo>running wsimport</echo>
<!-- wsdl attribute is absolute path, so ${basedir} is included -->
<wsimport
debug="true"
keep="true"
destdir="build/web/WEB-INF/classes"
package="wsimport.generated.addnumbers"
wsdl="${basedir}/web/WEB-INF/wsdl/AddNumbers.wsdl"/>
</target>
|
-pre-compile target calls the <wsimport> task, which generates all the necessary Java artifacts from the WSDL file and the referenced schema files. Those artifacts are generated in the WEB-INF/classes directory with the wsimport.generated.addnumbers package. ServiceImpl class, as follows. wsimport.
package my.sample.server;
import javax.jws.WebService;
import wsimport.generated.addnumbers.*;
/**
* A simple Java class to implement a Web service. Until the endpoint interface is
* generated, the class declaration below will show up as a compiler error.
*/
@WebService(endpointInterface="wsimport.generated.addnumbers.AddNumbersPortType")
public class AddNumbersImpl implements AddNumbersPortType {
public void oneWayInt(int arg0) {
System.out.println("received value "+arg0);
}
public int addNumbers(int arg0,int arg1) throws AddNumbersFault_Exception {
if (arg0<0 || arg1<0) throw new AddNumbersFault_Exception("negative number",
new AddNumbersFault());
return arg0+arg1;
}
}
|
|
Port Name
|
Status
|
Information
|
|---|---|---|
|
Hello
|
ACTIVE
|
Address:
http://localhost/HelloWebService/hello WSDL: http://localhost/HelloWebService/hello?wsdl Port QName: {http://example.com}HelloPort Implementation class: my.sample.server.ServiceImpl |
|
AddNumbers
|
ACTIVE
|
Address:
http://localhost/HelloWebService/addNumbers WSDL: http://localhost/HelloWebService/addNumbers?wsdl Port QName: {http://duke.org}AddNumbersPort Implementation class: my.sample.server.AddNumbersImpl |
The authors are grateful to Bobby Bissett and Milan Kuchtiak for their permission to use some code fragments and JAX-WS related text from their article, Building JAX-WS 2.0 Services With NetBeans 5.0 .
Thanks also to Mukesh Garg for his input during the technical review.
