JBuilder2007 Web Services – Building a Web Service Client from an Existing Web Service

By: Doug Thiele

Abstract: Use JBuilder2007 to create a web client from an existing web service.

Software Required: JBuilder2007 or JBuilder2007 Enterprise

JBuilder2007 makes creating a web client from an existing web service relatively easy. JBuilder2007 does all the heavy lifting of creating the web services infrastructure code, so we just have to worry about creating the web client.

Before we dive into the walkthrough, let’s outline the business problem. The goal is to create a web page that converts currencies. For example, if we have $100 US Dollars, into how many Euros could those dollars be converted (and so on)? There are actually web services out there that can provide the conversion rate, and I happened upon one that we can use to illustrate how JBuilder2007 assists us in making use of the web service, and in creating the client for the service.

The first thing to do is to open JBuilder2007 and create a “Web Service Client from URL” project (Exhibit 1) and click “Next”.

Hide image
Click to see full-sized image
Exhibit 1: The “New Project” Dialog Box

The next screen that comes up is the “Add Web Service from URL” dialog box (Exhibit 2). The web service that we’re going to use is a currency converter web service from webservicex.net at http://www.webservicex.net/CurrencyConvertor.asmx?WSDL. Given two currencies, it returns the conversion factors for those two currencies. For example, the web service converts 1 USD to 1.0019 CAD (i.e. a conversion factor of 1.0019). I’ve chosen to use an Oracle 10g application server, although the code should work with any JEE 5 compliant application server, along with JUnit 4 for unit testing. When setting the options for the client project, the “Specify Client Project Settings” dialog box appears (Exhibit 3). Click “OK” to close the “Specify Client Project Settings” dialog box, and then click “Finish” to complete the “Add Web Service from URL” wizard.

Hide image
Click to see full-sized image
Exhibit 2: The “Add Web Service from URL” Dialog Box

Hide image

Exhibit 3: “Specify Client Project Settings” Dialog Box

All of the web service plumbing code is generated for us. One of the fantastic features in JBuilder2007 is the tooling that is built in for modeling EJBs and web services. JBuilder2007 generated the diagram in Exhibit 4, which also shows the build that was run to generate the web service plumbing code automatically.

Hide image
Click to see full-sized image

Exhibit 4: Web Services modeling work surface

That’s great, because there’s a lot of it. There are whole books that go into detail on Java web services plumbing, and I won’t delve into it here. The important thing for us to note is that we now have access to the web service, and can use the generated test class to exercise the conversionRate() method that’s exposed. The file name of the test class is CurrencyConverterTestCase.java. I immediately changed the last line in the test1CurrencyConvertorSoapConversionRate() method to read:

value = binding.conversionRate(NET.webserviceX.www.Currency.USD,
 NET.webserviceX.www.Currency.EUR);

and added one line of code:

        System.out.println(value);

This way I could see the value that was pulled back from the web service. I got a value of 0.6741 when I ran the test.

Great! We’ve got a connection to a web service that we know works, but we still don’t have a client application. It’s time to start doing something about that. The first thing I did was add a JavaServer Faces facet to my project. I then added a new JSP page to the application called currencyconverter.jsp. The user interface for the page is shown in Exhibit 5. It’s pretty crude, and I would use a style sheet to pretty it up a bit if this were an application that was being developed for a customer. For our purposes, it’s just fine.

Hide image
Click to see full-sized image

Exhibit 5: The user interface for the currency conversion client.

At this point I also created a Java class called ConverterBean. This Java class is meant to act as the managed bean for the application, and I made it a request scoped bean (see faces-config.xml for the source code). This managed bean stores state for the properties (i.e. the chosen currencies, and the amount), performs the conversion, and fills the dropdowns. I used JBuilder2007’s “Encapsulate Field” item on the “Refactor” menu so that I didn’t have to write all of the getters and setters manually. I was also able to make use of the generated test case code to copy and paste into my getCurrencyConversionRate() method so that I didn’t have to write the web service method invocation code by hand.

The dropdowns get filled through the getCurrencyList() method. I’m calling this method out specifically because it highlights one really nice piece of the Java SE 6 API: the Reflection API. This is my first time working with it. The Reflection API always seemed mysterious when reading about it in books, but in fact, it’s really straightforward. Given any Java class, you can pull out all of the methods, fields, etc. In this case, I wanted to get a list of all the currencies used by the web service without hard-coding them. I simply iterate through the list of fields in the Currency class, and discard any that start with an underscore (the generated Currency class creates a static variable to hold the string name of the currency using an underscore). I just iterate through the fields in the Currency class and add them to an ArrayList which is used to populate the dropdowns.

Just a note: I removed my test classes before I deployed the solution so that I didn’t have to worry about whether or not my application server had access to the JUnit libraries.

Finally, when the user presses the “Convert” button, the page refreshes, the getConvertedAmount() method is executed, and the converted currency amount is displayed in an outputLabel JSF component on the web page.

Using JBuilder2007, I was able to make use of an existing web service, and hook it up to a JSF web client. JBuilder2007 generated all of the web services infrastructure code for me, and I was able to focus on the problem I wanted to solve.

Currencyconvert.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> 
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
"http://www.w3.org/TR/html4/loose.dtd">
<f:view>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; 
charset=ISO-8859-1">
<title>Currency Converter</title>
</head>
<body>
    <h:form>
         <h:outputLabel id="lblFrom" value="From:"/> 
         <h:selectOneMenu id="cboFrom" value="#{converterBean.fromCurrency}"> 
              <f:selectItems value="#{converterBean.currencyList}" />
         </h:selectOneMenu> <h:inputText id="txtAmount" size="10" 
title="Amount to be converted." value="#{converterBean.amount}">
              <f:validateDoubleRange minimum="0" maximum="100000000000" />
              <f:convertNumber />
         </h:inputText>
         <h:message for="txtAmount"/>
         <br/>
         <h:outputLabel id="lblTo" value="To:"/> 
         <h:selectOneMenu id="cboTo" value="#{converterBean.toCurrency}">
              <f:selectItems value="#{converterBean.currencyList}" />
         </h:selectOneMenu>
         <br/>
         <h:commandButton id="cmdConvert" value="Convert"/><br/>
         <br/><br/>
         <h:outputLabel id="lblConvert" 
value="#{converterBean.convertedAmount}" />
    </h:form>
</body>
</html>
</f:view>

Faces-config.xml

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE faces-config PUBLIC
    "-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.1//EN"
    "http://java.sun.com/dtd/web-facesconfig_1_1.dtd">

<faces-config>
    <managed-bean>
         <managed-bean-name>
         converterBean</managed-bean-name>
         <managed-bean-class>
         converter.ConverterBean</managed-bean-class>
         <managed-bean-scope>
         request</managed-bean-scope>
    </managed-bean>

</faces-config>

ConverterBean.java

package converter;

import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.lang.reflect.*;

import javax.faces.model.SelectItem;

import NET.webserviceX.www.Currency;

public class ConverterBean {
    /**
     *  Private variable declarations that are used to get
 and set currency and amount.
     */
    private String fromCurrency = "";
    private String toCurrency = "";
    private double amount = 0.0;

    
    private double getCurrencyConversionRate(Currency fromCurrency,
 Currency toCurrency) throws RemoteException {
         NET.webserviceX.www.CurrencyConvertorSoapStub binding = null;
         try {
              binding = (NET.webserviceX.www.CurrencyConvertorSoapStub)
                      new NET.webserviceX.www.CurrencyConvertorLocator()
.getCurrencyConvertorSoap();
         }
         catch (javax.xml.rpc.ServiceException jre) {
              if(jre.getLinkedCause()!=null)
                   jre.getLinkedCause().printStackTrace();
         }

         // Time out after a minute
         binding.setTimeout(60000);
         return binding.conversionRate(fromCurrency, toCurrency);
    }
    
    
    /** 
     * Do something not-so-fancy here to create a currency.
     * @param currencyCode
     * @return
     */
    private Currency getCurrencyFromString(String currencyCode) {
         Currency c = Currency.fromString(currencyCode);
         return c;
    }
    
    public SelectItem[] getCurrencyList() {
         List<String> al = new ArrayList<String>();
         Field f[];
         
         try {
              Class c = Class.forName("NET.webserviceX.www.Currency");
              f = c.getFields();
              
              // Get the fields of the class that don't start with an "_", 
              // because this is the list of currencies
              for(Field f1 : f) {
                   if(!f1.getName().contains("_")) {
                        al.add(f1.getName());
                   }
              }
         }
         catch (ClassNotFoundException e) {
              System.out.println("Error getting currency list.");
         }
         Collections.sort(al);
         SelectItem[] items = new SelectItem[al.size()];
         for(int i=0; i < al.size(); i++) {
              items[i] = new SelectItem(al.get(i).toString(),
 al.get(i).toString());
         }
         return items;
    }
    
    public String getFromCurrency() {
         return fromCurrency;
    }
    
    public void setFromCurrency(String fromCurrency) {
         this.fromCurrency = fromCurrency;
    }
    
    public String getToCurrency() {
         return toCurrency;
    }
    
    public void setToCurrency(String toCurrency) {
         this.toCurrency = toCurrency;
    }

    public double getAmount() {
         return amount;
    }
    
    public void setAmount(double amount) {
         this.amount = amount;
    }
    
    public double getConvertedAmount() throws RemoteException {
         Double convertedValue = 0.0;
         if(amount != 0)
              convertedValue = amount *
 getCurrencyConversionRate(getCurrencyFromString(fromCurrency),
 getCurrencyFromString(toCurrency));
         return convertedValue;
    }    
}

Server Response from: ETNASC01