关闭

JBoss-ws4ee Hello World Example

2375人阅读 评论(0) 收藏 举报

JBoss-ws4ee Hello World Example

This builds a simple example showing what can be done
with JBoss-4.0.x

Updated 25 October 2005

This example works with the newest builds of JBoss-4.0.x and its Web Services programming model for J2EE 1.4 using Apache axis 1_1 for its core. This is different from the jboss-net model used under JBoss-3.2.x.

In any case you need to download the Axis version so that you can code to the correct API, and have the Axis docs for details about the utilities, which come with Axis.

This example also uses Eclipse 3.1 with the 0.7 build of the Web Tools Project, which you can download from here.

This assumes a number of things are already set up on your machine.

  1. That you have a running version of JBoss-4.0 with JBoss-ws4ee. If not then you first need to go here to get the distribution.

  2. That you have Jakarta Ant installed and ready to use, as discussed here.

  3. That you have added the axis.jar from the relevant axis distro to your classpath. You need this for three things:

    1. to use the tcpmon for debugging

    2. to have the documentation and AP

    3. to copy the wsdl4j.jar (which might be missing from your jboss distro) to under jboss-home/server/default/deploy/jboss-ws4ee-sar

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 Exercise

This 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:

  1. create a Java interface and its implementation

  2. write, and generate the deployment description file

  3. put these into a war archive

  4. deploy on JBoss

  5. access the service via a client application.

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:

files and directories

The web directory just has a placeholder index page, as this is to be a console application.

The wsdl directory is where the axis generated WSDL file will be placed, and MUST sit under the WEB-INF directory to comply with J2EE 1.4.

The main/src directory will hold the Java application files, while main/client will hold our client classes.

The

  • axis-ws4ee.jar (under jboss-home/server/default/deploy/jboss-ws4ee.sar),

  • jboss-jaxrpc.jar (under jboss-home/server/default/lib) and

  • namespace.jar (under jboss-home/lib)

are there just to keep the build path in Eclipse complete.

Add web service libraries

You could also add either the Axis 1.2 libraries or the Web Services 1.0 libraries. The later is available if you've added in the JBoss-IDE components for Eclipse.

The Build File

First, 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=".">
<property name="app.name" value="simple-ws4ee" />
<property environment="env" />
<property name="jboss.home" value="C:/java/jboss-4.0.3" />
<property name="deploy.home" value="${jboss.home}/server/default/deploy" />
<property name="dist.home" value="${deploy.home}" />
<property name="dist.src" value="${app.name}.jar" />
<property name="dist.wsr" value="${app.name}.wsr" />
<property name="dist.war" value="${app.name}.war" />
<property name="dist.ear" value="${app.name}.ear" />
<property name="build.dir" value="${basedir}/build" />
<property name="build.classes.dir" value="${basedir}/build/classes" />
<property name="build.war.dir" value="${build.dir}/war" />

<!-- need to add in details of src.dir -->
<property name="src.dir" value="${basedir}" />

<!-- the other jars for axis, servlets, etc are added to the classpath
-->

<path id="base.libraries">
<pathelement location="${build.classes.dir}" />
<fileset dir="${jboss.home}/lib">
<include name="*.jar" />
</fileset>
<fileset dir="${jboss.home}/server/default/lib">
<include name="*.jar" />
</fileset>
<fileset dir="${jboss.home}/server/default/deploy/jboss-ws4ee.sar">
<include name="*.jar" />
</fileset>
</path>

<path id="client.classpath">
<pathelement location="${build.classes.dir}" />
<fileset dir="${jboss.home}/client">
<include name="*.jar" />
</fileset>
</path>

<target name="clean">
<delete dir="${build.dir}" />
</target>

<target name="validate">
<available property="classpath_id" value="base.libraries" file="${jboss.home}/server/default/lib/javax.servlet.jar" />
</target>

<target name="fail_if_not_valid" unless="classpath_id">
<fail message="jboss.home=${jboss.home} is not a valid JBoss dist directory " />
</target>

<target name="prepare" depends="clean, validate, fail_if_not_valid">
<mkdir dir="${build.classes.dir}" />
<mkdir dir="${build.classes.dir}/client" />
<mkdir dir="${build.classes.dir}/WEB-INF" />
<mkdir dir="${build.classes.dir}/WEB-INF/classes" />
<mkdir dir="${build.classes.dir}/META-INF" />

<!-- set the classpath for compiling files -->
<property name="classpath" refid="${classpath_id}" />

<!-- now copy across the files -->

<copy todir="${build.classes.dir}">
<fileset dir="${src.dir}/web">
<include name="**/*" />
</fileset>
</copy>

<copy todir="${build.classes.dir}/WEB-INF">
<fileset dir="${src.dir}/WEB-INF">
<include name="**/*" />
</fileset>
</copy>
</target>

<!-- complie the code -->
<target name="compile" depends="prepare">
<javac srcdir="main" destdir="${build.classes.dir}" classpath="${build.classes.dir}"
debug="on" optimize="off" deprecation="on">
<classpath path="${classpath}" />
</javac>
<copy todir="">
<fileset dir="${src.dir}/main/src">
<include name="main/src/testHelloWorld.*" />
</fileset>
</copy>
</target>

<target name="javadoc" depends="prepare">
<javadoc sourcepath="src" packagenames="*" destdir="${javadoc.home}" />
</target>
<!-- now build the wsdl file -->
<target name="wsdl" depends="compile">
<mkdir dir="${build.classes.dir}/WEB-INF/wsdl" />
<java classname="org.apache.axis.wsdl.Java2WSDL" fork="yes" dir=".">
<classpath path="${classpath}" />
<arg value="-lhttp://localhost:8080/ws4ee/services/HelloWorld" />
<arg value="-sHelloWorld" />
<arg value="-oWEB-INF/wsdl/hello.wsdl" />
<arg value="-uLITERAL" />
<arg value="HelloWorld" />
<!-- This last arg value may need to be com.myapp.HelloWorld in order for the class to be found -->
</java>
</target>

<!-- now build the war file -->
<target name="war" depends="wsdl">
<war destfile="${build.dir}/${dist.war}" webxml="WEB-INF/web.xml">
<fileset dir="web" />
<webinf dir="WEB-INF">
<exclude name="web.xml" />
<include name="*.xml" />
<include name="wsdl/*.*" />
</webinf>
<classes dir="${build.classes.dir}">
<include name="com/myapp/*.class" />
</classes>
</war>
<copy file="${build.dir}/${dist.war}" todir="${build.classes.dir}" />
</target>

<!-- for ease of checking that all of the contents are correct -->
<target name="unwar" depends="war">
<mkdir dir="${build.war.dir}" />
<unwar src="${build.dir}/${dist.war}" dest="${build.war.dir}" />
</target>

<!-- now deploy the war file -->
<target name="dist" depends="unwar">
<copy file="${build.dir}/${dist.war}" todir="${deploy.home}" />
</target>

<!-- run the client -->
<target name="run_client">
<copy file="${src.dir}/main/client/log4j.xml" todir="${build.classes.dir}" />
<java classname="com.myapp.wsdlClient" fork="yes" dir=".">
<classpath refid="client.classpath" />
</java>
</target>

<target name="main" depends="dist">
</target>

</project>

The Interface and Implementation

Second, 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;
import java.rmi.RemoteException;

public interface HelloWorld extends Remote {
public String getHelloWorld(String name) throws RemoteException;
}

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;
import javax.xml.rpc.*;
import javax.xml.rpc.server.ServiceLifecycle;

public class HelloWorld_Impl implements HelloWorld, ServiceLifecycle {

public String getHelloWorld(String name)throws RemoteException {
return "Hello world to " + name;
}

public void init(Object arg0) throws ServiceException {
// TODO Auto-generated method stub

}

public void destroy() {
// TODO Auto-generated method stub

}

}

The Deployment Descriptors

Fourth, 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"?>
<!DOCTYPE jboss-web PUBLIC "-//JBoss//DTD Web Application 2.2//EN" "http://www.jboss.org/j2ee/dtd/jboss-web.dtd">

<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"?>
<web-app
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://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="2.4">

<servlet>
<servlet-name>HelloWorldServlet</servlet-name>
<servlet-class>com.myapp.HelloWorld_Impl</servlet-class>
</servlet>

<servlet-mapping>
<servlet-name>HelloWorldServlet</servlet-name>
<url-pattern>/exactpath/jse</url-pattern>
</servlet-mapping>

<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>

</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>
<webservice-description-name>HelloWorldService</webservice-description-name>
<wsdl-file>WEB-INF/wsdl/hello.wsdl</wsdl-file>
<jaxrpc-mapping-file>WEB-INF/jaxrpc-mapping.xml</jaxrpc-mapping-file>
<port-component>
<port-component-name>HelloWorld</port-component-name>
<wsdl-port>HelloWorld</wsdl-port>
<service-endpoint-interface>com.myapp.HelloWorld</service-endpoint-interface>
<service-impl-bean>
<servlet-link>HelloWorldServlet</servlet-link>
</service-impl-bean>
</port-component>
</webservice-description>
</webservices>

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.

Parts of wsdl file

<?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 client

With 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;
import javax.xml.rpc.Call;
import javax.xml.rpc.Service;
import javax.xml.rpc.JAXRPCException;
import javax.xml.rpc.ServiceFactory;
import javax.xml.rpc.ParameterMode;

public class DIIClient {

// modified from sun j2ee jaxrpc example

private static String endpoint = "http://localhost:8070/simple-ws4ee/exactpath/jse";
private static String qnameService = "HelloWorldService";
private static String qnamePort = "HelloWorld";
private static String ENCODING_STYLE_PROPERTY =
"javax.xml.rpc.encodingstyle.namespace.uri";
private static String NS_XSD =
"http://www.w3.org/2001/XMLSchema";
private static String URI_ENCODING =
"http://schemas.xmlsoap.org/soap/encoding/";

public static void main(String[] args) {

System.out.println("Endpoint address = " + endpoint);

try {
ServiceFactory factory = ServiceFactory.newInstance();
Service service = factory.createService(new QName(qnameService));

QName port = new QName(qnamePort);

Call call = service.createCall(port);
call.setTargetEndpointAddress(endpoint);

call.setProperty(Call.SOAPACTION_USE_PROPERTY,
new Boolean(true));
call.setProperty(Call.SOAPACTION_URI_PROPERTY, "");
call.setProperty(ENCODING_STYLE_PROPERTY, URI_ENCODING);
QName QNAME_TYPE_STRING = new QName(NS_XSD, "string");
call.setReturnType(QNAME_TYPE_STRING);


call.setOperationName(new QName(BODY_NAMESPACE_VALUE,
"getHelloWorld"));
call.addParameter("String_1", QNAME_TYPE_STRING,
ParameterMode.IN);
String[] params = { "jboss!" };

String result = (String)call.invoke(params);
System.out.println(result);

} catch (Exception ex) {
ex.printStackTrace();
}
}
}

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.

JBoss-ws4ee menu

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.

Open Window->Preferences in Eclipse to call up the window to the right, which is under Run/Debug.

Eclipse's TCP/IP monitor

Click the 'add' button to bring up these details to set. Then click the 'start' button to begin monitoring the port.

Now change the 'depends' for the 'main' target in the build file to 'run_client' and run the build file.

New TCP/IP monitor details

After the build runs you should see a new window appear next to your console and server windows in Eclipse. You have details about time, format of requests and responses too. You can right-click on the page listing to send a new request, and you'll find that the first request takes awhile, but subsequent ones are quick.

TCP/IP monitor in action

 

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.

Axis tcpmon

The Eclipse Client Tool

As noted above Eclipse has a tool for testing web services.

Use 'Run->Launch Web Services Explorer' from the main menu of Eclipse. After a few moments the window below should appear. You may want to maximise it for best effect.

If you are having problems getting the Web Services Explorer launched, then check the following

a) that you've not configured your proxy to ignore requests to localhost (as the explorer starts up Tomcat on a dynamic port)

b) that you've not got two different instances of org.eclipse.wst.ws.explorer_0.7.0 (and org.eclipse.wst.ws.explorer_0.7.1) under eclipse/plugins, as they seem to conflict with each other.

run web services explorer

Select the second icon from the right for 'WSDL Page' to open the window below after the explorer starts. 

Don't forget to turn OFF the Internet proxy in Eclipse via Window->Preferences->Internet (or set it to ignore your PC name and localhost), or this will not work.

Select WSDL explorer
Enter the URL to the wsdl file as http://localhost:8080/simple-ws4ee/exactpath/jse?wsdl and you should then see the 'getHelloWorld' listed on the right. Enter something the input box on the top, and press 'go' to see the reply on the bottom.
Test WSDL web service

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

 
0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:1351065次
    • 积分:19031
    • 等级:
    • 排名:第457名
    • 原创:583篇
    • 转载:87篇
    • 译文:1篇
    • 评论:609条
    最新评论