Home arrow Java & J2EE arrow Page 9 - Using RPC-Style Web Services with J2EE

The Web Services Deployment Descriptor - Java

Web Services provide functionality to the Internet, and are seen as the wave of the future. In this article, Martin Bond explains how to use Web Services protocols to join J2EE application components with any other software that supports those protocols. This excerpt is from Chapter (Day) 20, from Teach Yourself J2EE in 21 Days, second edition, by Martin Bond, et. al. (Sams, 2003, ISBN: 0672325586)

TABLE OF CONTENTS:
  1. Using RPC-Style Web Services with J2EE
  2. Web Service Overview
  3. Web Service Technologies and Protocols
  4. Web Services for J2EE
  5. RPC-Oriented Web Services
  6. Creating a Simple Service
  7. The WSDL File
  8. Creating the Web Service WAR
  9. The Web Services Deployment Descriptor
  10. Building More Robust Web Services
  11. Exposing EJBs Through Web Service Protocols
  12. Web Service Compiler Configuration File
  13. Configuring the EJB Component
  14. Other Considerations for Web Services
  15. Summary
By: Sams Publishing
Rating: starstarstarstarstar / 13
December 08, 2004

print this article
SEARCH DEV SHED

TOOLS YOU CAN USE

advertisement

The Web Services Deployment Descriptor contains a list of the Web Services being deployed and the ports each one of them contains. The root element is webservices, which contains one or more webservice-description elements. Within the webservice-description element there is some information about the overall service, such as the name of the service, the associated WSDL file, and which mapping deployment descriptor should be used for this particular Web Service:

<webservice-description-name>GreetingService
</webservice-description-name> <wsdl-file>WEB-INF/wsdl/GreetingService.wsdl</wsdl-file> <jaxrpc-mapping-file>mapping.xml</jaxrpc-mapping-file>

Each webservice-description element contains one port-component element for each port in the service. For your simple Greeting service, there is just a single port you can call GreetingPort. This suggested name is intentionally different from the name used in the WSDL document to help you differentiate it:

<port-component>
<display-name>Greeting</display-name>
<port-component-name>Greeting</port-component-name>
...
</port-component>

The wsdl-port element below the port-component element defines the associated port name from the WSDL you generated earlier—GreetingPort—and the namespace in which it is defined—urn:J2EE21Examples:

<wsdl-port xmlns:wsdl-port_ns__="urn:J2EE21Examples">wsdl-port_ns__
:GreetingPort</wsdl-port>

The service-endpoint-interface element within the port-component defines the Java interface associated with this port. In your case, this is the fully qualified name of the interface you are supplying in the WAR file:

<service-endpoint-interface>wsexamples.Greeting
</service-endpoint-interface>

The other useful bit of information in the port-component is the link to the implementation. The service-impl-bean in this case defines a link to the GreetingImplementation defined in the web.xml file:

<service-impl-bean>
<servlet-link>GreetingImplementation</servlet-link>
</service-impl-bean>

Deploying the Service

Now you can deploy the service. Select the wsgreeting WAR in the left-hand pane of deploytool and then select Tools, Deploy from the menus. Provide your administrator user name and password if prompted and ensure that the message "Operation Completed Successfully" is displayed on the Distribute Module screen.

During this deployment, all of the server-side scaffolding, such as the server-side skeletons, will be generated by the container into which you are deploying. Note that there is no need in this case to ask for a client JAR file because you will contact the service over SOAP. The only thing needed to create the artifacts used by the client is the WSDL description (after all, the Greeting Web Service could be implemented in Microsoft .NET if it was developed by someone else).

You can now access the simple Web Service at the URL http://localhost/wsgreeting/GreetingService. Putting this URL directly into a browser will not have much effect as browsers issue HTTP GET commands while Web Services generally use HTTP POST. However, you can test that your service is there by asking it for its WSDL description. To do this, add "?WSDL" onto the end of the URL and type it into your browser:

http://localhost/wsgreeting/GreetingService?WSDL 

This will return the deployed WSDL file as shown in Figure 20.12.

bond

Figure 20.12
Querying the Web Service for its WSDL.

The WSDL document is identical to the one in the Web Service WAR, but it now contains the location information for the deployed service (remember that the original WSDL had its location set to REPLACE WITH ACTUAL URL):

...
<service name="GreetingService">
<port name="GreetingPort" binding="tns:GreetingBinding">
<soap:address xmlns:wsdl=http://schemas.xmlsoap.org/wsdl/
location="http://localhost:8000/wsgreeting/GreetingService"/>
</port>
</service>
...

In the next section, you will use this WSDL file to generate stubs through which a client application can contact the Web Service.

Consuming the Simple Greeting Service

To use your Web Service you need a client. For the purposes of this exercise, this client will be a standard Java class with a main method. However, it could also be a J2EE component such as a JSP or EJB. The differences with such clients are discussed later.

To call the Web Service from a client, you could use low-level APIs to create and send SOAP messages. However, one of the main intentions of JAX-RPC is to provide the developer with a familiar development model. Hence, you will again use the tools to create a stub (or proxy) that represents the service for the client. The stub exposes Java methods that match the SOAP operations supported by the server. The client application can simply call these Java methods to invoke the functionality of the service. The J2EE RI tool used is again wscompile. You can use wscompile to take the WSDL description of the deployed service and create client-side stubs through which to invoke the service.

In this case the configuration file needs client-focused information provided in a wscompile configuration file similar to the one used earlier to generate the WSDL in the section "Web Service Compiler Configuration File." The file still has a root element of configuration, but in place of the service element you use a wsdl element. The packageName attribute of the wsdl element indicates that the generated Java classes and interfaces should reside in the package client. The location attribute specifies that the WSDL file to use should be retrieved from the deployed service. This means that it contains the correct endpoint location information for the service you deployed. The client configuration file is shown in Listing 20.6.

Listing 20.6 wscompile Client Configuration File (config-client.xml)

<?xml version="1.0" encoding="UTF-8"?>
<configuration xmlns="http://java.sun.com/xml/ns/jax-rpc/ri/config">
<wsdl
location=http://localhost:8000/wsgreeting/GreetingService?WSDL
packageName="client"/> </configuration>


Note - Do not use the original WSDL file without the location information when creating your client. Stubs generated from WSDL that do not contain a valid endpoint will fail at runtime unless one is set programmatically. This is a more flexible mechanism, but it makes them more complicated to use. Dynamic endpoint allocation is fine later, but for the time being we will be working with the endpoint URL encoded in the WSDL.


When you call wscompile, you should ask it to generate the client scaffolding you need (-gen:client). If you are working in a development environment that does not provide code completion based on introspection, you should also specify the –keep option so that the .java files are still around for inspection:

wscompile –gen:client -d classes –keep –s build/generatedproxy ws/
config-client.xml

The client-side scaffolding shares many files with the server-side scaffolding, including any complex types, serializers, and a serializer registry to map types to serializers. However, the following client-specific artifacts are also generated:

  • Greeting interface—This is generated from the WSDL port description. It is almost identical to the remote Java Greeting interface from which the WSDL was generated.

  • GreetingService interface—This defines a single method getGreetingPort() that returns a client-side proxy for the service implementing the Greeting interface.

  • GreetingService_Impl class—This is a factory class that represents the Web Service as a whole. You can obtain client-side proxies from instances of this class. For your simple service, this will just serve client-side proxies that implement the Greeting interface.

  • Greeting_Stub class—This is the client-side proxy itself that implements the client-side Java Greeting interface generated from the WSDL.

You can build a Web Service client using these generated classes. To use these classes, you should either import the namespace in which they were generated (client derived from the client configuration file as shown in Listing 20.6) or place your client class in the same namespace:

package client;

You can create your client code in a simple main() method. Don't forget that all these method calls can generate RemoteExceptions, so be sure to place them all inside a try/catch block. The first thing to do is instantiate the factory that represents the Web Service:

GreetingService serviceProxy = new GreetingService_Impl();

From this service proxy, you can then obtain an interface proxy:

Greeting interfaceProxy = serviceProxy.getGreetingPort();

As the interface proxy implements the client-side Greeting interface, you can call the sayHelloTo() method on this, passing the name of the person to greet:

String response = interfaceProxy.sayHelloTo("Fred");

This call will trigger a SOAP request to the simple Greeting Web Service. The service will prepend the message you defined in your implementation and return the result. The full code for a sample simple Web Service client is shown in Listing 20.7.

Listing 20.7 Client for Simple Web Service (GreetingClient.java)

package client;
public class GreetingClient
{
public static void main(String[] args)
{
try
{
GreetingService serviceProxy = new GreetingService_Impl();
Greeting interfaceProxy = serviceProxy.getGreetingPort();
String response = interfaceProxy.sayHelloTo("Fred");
System.out.println("Response from greeting service was: " 
+ response); } catch (Exception ex) { ex.printStackTrace(); } } }

You compile and run your client as you would any other Java application, but ensure that the generated client-side classes are on your classpath. To generate the client-side scaffolding, compile the pre-provided client class and run it, use the following Ant directive:

asant run

This will communicate with the web service you deployed earlier. You should see the following message:

Response from greeting service was: Hi there Fred

So, now you have created, deployed, and invoked a simple Web Service under J2EE using JAX-RPC.

One final question before moving on from here is how to re-target this Web Service client at a different endpoint. By default, the stub uses the endpoint URL encoded into the WSDL document. As you move from development into test, staging, and live environments, the URL of the endpoint will probably change. However, you do not necessarily want to regenerate your proxies at every stage. Instead, you can set the endpoint for the stub to use as follows (in this example "ELEPHANT" is the name of the host on which the service is deployed):

javax.xml.rpc.Stub stub = (javax.xml.rpc.Stub)interfaceProxy;
stub._setProperty(ENDPOINT_ADDRESS_PROPERTY, 
"http://ELEPHANT:8000/wsgreeting/DIFFERENT_NAME");

You can then define the endpoint address as a property that can be picked up by the running program.


Caution - When re-targeting a proxy at a different endpoint, you should ensure that the endpoint supports the same port type—even down to the name of each part of each message. Some services may be forgiving on this (that is, the names could differ and it will still accept the operation invocation), but others are not.


This chapteris fromTeach Yourself J2EE in 21 Days, second edition, byMartin Bond et. al.(Sams, 2004, ISBN: 0-672-32558-6). Check it out at your favorite bookstore today. Buy this book now.



 
 
>>> More Java & J2EE Articles          >>> More By Sams Publishing
 

blog comments powered by Disqus
   

JAVA & J2EE ARTICLES

- More Java Bugs Lead to More Attacks
- Oracle's Java One Brings News, Surprises
- Oracle Patches Java Runtime Environment
- Apple Syncs Java Update with Oracle
- Spring 3.1 Java Development Framework Compat...
- Jelastic Java PaaS Availability and Pricing ...
- NetBeans 7.1 Released, Supports JavaFX 2
- SolarWinds Releases Newest Version of Java M...
- Free Monitoring Tool for Java Apps on Heroku
- Heroku Adds JCloud Platform Support, Java 7 ...
- Java SE 8 Speculation in Full Swing
- Java SE 7 Now Available
- New JVM Language and Java Reporting Tool
- Java 7 Release Update and New Eclipse Toolkit
- The Best Java Netbeans IDE Plugins

Developer Shed Affiliates

 



© 2003-2013 by Developer Shed. All rights reserved. DS Cluster - Follow our Sitemap

Dev Shed Tutorial Topics: