JBoss-ws4ee Hello World ExampleThis builds a simple example showing what can be done |
|||||||||||||||||||
This assumes a number of things are already set up on your machine.
You can skip putting Axis into your classpath if you're using Eclipse with the Web Tools Project components added as it provides tools for monitoring SOAP messages, as we'll see later. |
|||||||||||||||||||
The ExerciseThis exercise assumes that you are using JBoss-4.0.x versions. This has jboss-ws4ee.sar under the 'default' server option. If you did the jboss.net version of the application, then you'll notice that it is more complex to set up and implement, due to extra deployment descriptors and the interface plus implementation model of programming. I'm sure that given time some of these extra details will be simplified with XDoclet or other tools, so be patient with the examples. But if you first want to get your head around web services, then this will get you going on a smaller scale. In any case the principles are the same:
Now for the sample application, which uses Ant to build the files for the project. Ok, it might be considered overkill, but as always Ant speeds up the edit, compile, copy, jar, deploy routine. You can download the code and build files in a zip file from here If you put your project into Eclipse, then create a plain 'Java Project' because if you use the 'Dynamic Web Application' project, then you will have extra folders created for JavaSource and WebContent which will get in the way. The directory structure that you need to create looks like this in Eclipse:
|
|||||||||||||||||||
The Build FileFirst, the build.xml script, which is simple and short. You will need to make sure that you have set jboss.home correctly for your system. All other properties hang off of this one so should work ok. |
|||||||||||||||||||
<project name="jboss-ws4ee-HelloWorld" default="main" basedir="."> <!-- need to add in details of src.dir --> <!-- the other jars for axis, servlets, etc are added to the classpath <path id="client.classpath"> <target name="clean"> <target name="validate"> <target name="fail_if_not_valid" unless="classpath_id"> <target name="prepare" depends="clean, validate, fail_if_not_valid"> <!-- set the classpath for compiling files --> <copy todir="${build.classes.dir}/WEB-INF"> <!-- complie the code --> <target name="javadoc" depends="prepare"> <!-- now build the war file --> <!-- for ease of checking that all of the contents are correct --> <!-- run the client --> <target name="main" depends="dist"> </project>
|
|||||||||||||||||||
The Interface and ImplementationSecond, actual Java classes that are to be exposed need to do so via a public interface detailing the available methods and their signatures. You'll see that it must extend java.rmi.Remote. This is HelloWorld.java |
|||||||||||||||||||
package com.myapp; import java.rmi.Remote; public interface HelloWorld extends Remote { |
|||||||||||||||||||
Third, the implementation class for the interface, implements our interface plus javax.xml.rpc.server.ServiceLifecycle. As you can see Eclipse added the requisite destroy() and init(Object arg0) methods for us. This is HelloWorld_Impl.java. | |||||||||||||||||||
package com.myapp; import java.rmi.RemoteException; public class HelloWorld_Impl implements HelloWorld, ServiceLifecycle { public String getHelloWorld(String name)throws RemoteException { |
|||||||||||||||||||
The Deployment DescriptorsFourth, the web service needs to have a number of descriptors in order to successfully deploy on a J2EE 1.4 server. All of them must be deployed under the WEB-INF directory of your war file. You'll already be familiar with the web.xml and jboss-web.xml files, which detail the servlets and enterprise resources being used in the application. The new ones are webservices.xml, jaxrpc-mapping.xml and the hello.wsdl file under the 'wsdl' directory, which is in lowercase. As our's is a simple application, there is nothing in the jboss-web.xml file. However, if you were using jndi to connect to a database, or to an EJB, then the details would go in here. |
|||||||||||||||||||
<?xml version="1.0" encoding="UTF-8"?> <jboss-web> <!-- Resource references --> <!-- EJB References --> </jboss-web> |
|||||||||||||||||||
The web.xml file is more interesting. You see a 'HelloWorldServlet' listed there, but we've not written a servlet. However, you'll see that the servlet class is listed as our implementation class above. This is the magic of JAXRPC web services, and why we need to implement the ServiceLifecycle. This passes our implementation to the JAXRPC servlet to expose our class via its interface at the specified servlet mapping in the web.xml file. The welcome file is there as a placeholder, as this is a console app. The other interesting point is that the web-app tag at the start points to web-app_2_4.xsd instead of a DTD as in the past. In othere words, DTD declarations are a thing of the past for J2EE 1.4 apps, as they are moving to XML Schemas, which allow more validation power. |
|||||||||||||||||||
<?xml version="1.0" encoding="UTF-8"?> <servlet> </web-app> |
|||||||||||||||||||
The webservices.xml file explains which webservice you're exposing and its details. This includes the name and location of the WSDL file, the name of the interface class, the name of the servlet class, and the name of the jaxrpc-mapping file, as well as the name of the endpoint for your web service. As you can see, if there were more than one web service in the application, then it would comprise another 'webservice-description' set of tags. |
|||||||||||||||||||
<?xml version='1.0' encoding='UTF-8' ?> <webservices xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:impl="http://com.myapp/ws4ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://www.ibm.com/webservices/xsd/j2ee_web_services_1_1.xsd" version="1.1"> <webservice-description> |
|||||||||||||||||||
The jaxrpc-mapping.xml file does not have to be called by this name, but must match the name specified in the 'jaxrpc-mapping-file' tag in the webservices.xml file. The file here is about as simple as it can be, and will often end up being more complex. The main points here are that the file details the name of the Java package for the service, and the URI were it is located. The jaxrpc-mapping.xml file is there to help the JAXRPC compiler make sense of the objects detailed in the WSDL file. It helps the conversion from WSDL to Java objects, and if the Java objects are complex, then this file will be too. |
|||||||||||||||||||
<?xml version='1.0' encoding='UTF-8' ?> <java-wsdl-mapping xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://www.ibm.com/webservices/xsd/j2ee_jaxrpc_mapping_1_1.xsd" version="1.1"> <package-mapping> <package-type>com.myapp</package-type> <namespaceURI>http://myapp.com/HelloWorld</namespaceURI> </package-mapping> </java-wsdl-mapping> |
|||||||||||||||||||
The hello.wsdl file does not have to be called that, but will probably reflect the name of the application. It MUST be placed in a 'wsdl' directory (note lowercase) under the WEB-INF (or META-INF) directory of your application. You do not need to write this file by hand, as it can be generated by the Java2WSDL application which comes with Axis. We generate it in the Ant build file under the wsdl task. The main sections in the file are the services, bindings, and port types. With these details you can use any WSDL file to generate a Java client using the WSDL2Java tool that comes with Axis. The image below shows how the different parts of the WSDL file fit together. This is generated from one of the web service components that is included as part of the Eclipse Web Tools project. The downloads are at the bottom of the page. |
|||||||||||||||||||
<?xml version="1.0" encoding="UTF-8"?> <wsdl:definitions targetNamespace="http://DefaultNamespace" xmlns:impl="http://DefaultNamespace" xmlns:intf="http://DefaultNamespace" xmlns:apachesoap="http://xml.apache.org/xml-soap" xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns="http://schemas.xmlsoap.org/wsdl/"> <wsdl:message name="getHelloWorldResponse"> <wsdl:part name="getHelloWorldReturn" type="xsd:string"/> </wsdl:message> <wsdl:message name="getHelloWorldRequest"> <wsdl:part name="in0" type="xsd:string"/> </wsdl:message> <wsdl:portType name="HelloWorld"> <wsdl:operation name="getHelloWorld" parameterOrder="in0"> <wsdl:input name="getHelloWorldRequest" message="impl:getHelloWorldRequest"/> <wsdl:output name="getHelloWorldResponse" message="impl:getHelloWorldResponse"/> </wsdl:operation> </wsdl:portType> <wsdl:binding name="HelloWorldSoapBinding" type="impl:HelloWorld"> <wsdlsoap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> <wsdl:operation name="getHelloWorld"> <wsdlsoap:operation soapAction=""/> <wsdl:input name="getHelloWorldRequest"> <wsdlsoap:body use="literal" namespace="http://DefaultNamespace"/> </wsdl:input> <wsdl:output name="getHelloWorldResponse"> <wsdlsoap:body use="literal" namespace="http://DefaultNamespace"/> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="HelloWorldService"> <wsdl:port name="HelloWorld" binding="impl:HelloWorldSoapBinding"> <wsdlsoap:address location="http://localhost:8080/ws4ee/services/HelloWorld"/> </wsdl:port> </wsdl:service> </wsdl:definitions> |
|||||||||||||||||||
The Client |
|||||||||||||||||||
We'll do two clients. One showing you the code to write your own, and then a simple 'easy' client done on-the-fly with Eclipse which is useful for testing web services. The handwritten clientWith all of our code and deployment descriptors sorted out, we can now develop the client to use the application. There are three different types of clients, which we could develop with JAXRPC; those using generated stubs from the WSDL file, those using dynamic proxies, and those which use a dynamic invocation interface (DII). We'll use a DII type of client even though it is the trickier type of client to build, as it doesn't take advantage of the WSDL to make writing the client easier. The other reason to start using DII clients is that it means we can avoid configuring Axis client-side files. If you're just wanting to connect plain ordinary Java objects (POJO) JAX-RPC stub derived clients to web services deployed under JBossWS, then you need to take the axis-client-config.xml file from under jboss/server/default/deploy/jboss-ws4ee.sar/META-INF and place it in the directory from which your client will be run, and rename it to the default name that axis uses, client-config.wsdd. If you don't do this, then you will receive an error message complaining about axis not finding 'No engine configuration file'. This is because when you run wsdl2java, it uses the org.apache.axis.client.Service class, which then looks for a configuration file. |
|||||||||||||||||||
package com.myapp; import javax.xml.namespace.QName; public class DIIClient { public static void main(String[] args) { System.out.println("Endpoint address = " + endpoint); try {
String result = (String)call.invoke(params); } catch (Exception ex) { |
|||||||||||||||||||
With all of the files in their right spot, open a console in the same directory as the build.xml file and enter this command: ant (or run it from your IDE such as Eclipse). This assumes that Apache Ant is in your environment path. If not, then you need to add it. This will process the main target, which will compile the class files, build the war file, and copy the compiled client class back to the client directory. It also puts the war file into the deploy directory of your JBoss server. You should see some output in the console window telling you what is happening. Any errors that you encounter are probably due to missing items in your classpath, as the build.xml script checks that all of the Axis required jars are in your classpath. If jars are missing, then they will appear as errors, class not found. Open a browser and navigate to http://localhost:8080/ws4ee/ where you should see a list of items as shown below. Your screenshot may look different from the one above, which was done with jboss-4.0.0RC1. Check that the 'validate' page works ok. If you go to the 'View' page our service should be listed in the available services, along with the link to its WSDL file. Some of you will realise that the client goes to http://localhost:8070/simple-ws4ee/exactpath/jse, and wonder what gives. Well, it's an excuse to introduce another debug tool, the tcpmon which comes with Axis. The tcpmon intercepts messages on one port (ie 8070), shows them in one window, and then redirects the message to its designated port (ie 8080) and picks up the response. Use either these next steps to use Eclipse for the monitoring, or skip down below to use the one bundled with Axis.
If you don't have Eclipse installed, then you can use the method below to call up the tcpmon tool that comes with Axis.Open another console window and enter this command (assuming that you have added the axis.jar to your classpath. Unfortunately, I have found that this ONLY works if the axis-ws4ee.jar under jboss/server/default/deploy/jboss-ws4ee.sar is in your system classpth.): java org.apache.axis.utils.tcpmon You should have a Swing application open up. Put 8070 in the 'Listen Port #' textfield, put localhost in the 'Target hostname' textfield, and 8080 in the 'Target Port #' textfield. The radio button for 'Act as a listener' should be selected. Now click 'add' and a new tab 'Port 8070' should appear. Select it. Open another console window and navigate to the main/client directory and run the command: ant run_client If you have a 'connection refused ' error, then check that you have the tcpmon started as noted above, and that the app has deployed correctly to JBoss. You should see "Hello World to jboss!" appear in your client console window, and both the sent and received SOAP messages in the tcpmon windows. The Eclipse Client ToolAs noted above Eclipse has a tool for testing web services.
That's it, you've done it. You built a simple JAXRPC application and deployed it on JBoss-ws4ee, and also seen how Eclipse can help you test and manage application deployment. You can also go through the ws4ee examples from the wiki files at JBoss to also browse through. Go to:http://www.jboss.org/wiki/Wiki.jsp?page=JBossWS |