XFire: The easy and simple way to develop Web services

Expose your POJO methods as Web services

Web services enable us to build distributed systems where application components on a network can be accessed in a platform-neutral, language-agnostic, and implementation-independent way. It doesn't matter how an application is developed, what language it uses, or what OS platform it runs on. If it is available as a Web service and designed addressing interoperability issues, your application, developed in any language or platform, will be able to utilize its services. That's the main concept of Web services.

To achieve the platform-neutral and implementation-independent accessibility of Web services, the software industry has agreed on a few technologies as standards. Some of them are:

  • XML: The default data format used across all layers of Web services environment.
  • SOAP: The default protocol for packaging and exchanging messages. When first introduced, it was an acronym for Simple Object Access Protocol. But now SOAP is considered a proper noun, a name in itself, as most people now realize it is a misnomer: SOAP is not really for accessing objects. Plus, it is not simple any more.
  • WSDL (Web Services Description Language): The language that describes Web services. Although based on XML and understandable by humans, WSDL is mainly for machine consumption, to be read and understood by client programs.

The following high-level diagram, based on the document "Web Services Architecture" published by the World Wide Web Consortium, shows how all these technologies are engaged in a working environment:

The process showing how core technologies engage in Web services. Click on thumbnail to view full-size image.

Here, Provider is the application component that would provide the service, and Requester is the client program that would consume it. Many other technologies may participate in the interactions, but this figure shows the core components that must be in a Web services environment.

XFire is a free and open source SOAP framework that not only enables you to implement such an environment with great ease and simplicity, but also provides you many advanced features identified in Web services specifications, but not yet available in most commercial or open source tools. You read the words correctly: great ease and simplicity. In this article, you'll see how simple it is to build a Web service with XFire.

If your Web application has a Java class and you want its methods to be exposed as Web services, you may not have to write a single line of additional Java code when you use XFire. Just work on the deployment descriptors and you'll get a Web service. Yes, it's that easy. Let's look at an example.

A simple Java class

Our example is a banking application hosted in Apache Tomcat 5.5.7 and running under J2SE 1.4.2_07. I assume you already know how to write Web applications in Java and deploy onto Apache Tomcat servers. Our Web application is simple; it does just one thing—transfer funds from one account to another. A plain-old Java class BankingService containing a method named transferFunds() does the job for us. It needs four input parameters:

  1. String fromAccount
  2. String toAccount
  3. double amount
  4. String currency

Here is the code:

 

package com.mybank.xfire.example;

import java.text.NumberFormat; import java.text.DecimalFormat;

/** XFire WebServices sample implementation class. */ public class BankingService implements IBankingService { //Default constructor. public BankingService(){ } /** Transfers fund from one account to another. */ public String transferFunds( String fromAccount, String toAccount, double amount, String currency){ String statusMessage = ""; //Call business objects and other components to get the job done. //Then create a status message and return. try { NumberFormat formatter = new DecimalFormat("###,###,###,###.00"); statusMessage = "COMPLETED: " + currency + " " + formatter.format(amount)+ " was successfully transferred from A/C# " + fromAccount + " to A/C# " + toAccount; } catch (Exception e){ statusMessage = "BankingService.transferFunds(): EXCEPTION: " + e.toString(); } return statusMessage; } }

Do you see anything exceptional here? Probably not, except the default constructor, which is public. It is required. Otherwise, XFire would not be able to instantiate the class.

Since designing with interfaces is good practice, our Java class also implements an interface named IBankingService. The code is simple:

 

package com.mybank.xfire.example;

public interface IBankingService {

public String transferFunds( String fromAccount, String toAccount, double amount, String currency); }

In actual implementation, such a method may include all kinds of complex calls, queries, and processing operations. But our example code is bare minimum so that we can focus on our main objective: exposing the method as a Web service.

You can see that BankingService is a plain Java class, with no code whatsoever to tell whether it should be used in Web services. And that's fine. We don't need to add anything here. All our work will be done in the deployment descriptors.

Deployment descriptors of the Web application

In Java, Web applications are usually configured using at least one deployment descriptor, named web.xml. XFire itself is a servlet-based application. Hence, we need to add necessary references to this file. Then we have to configure the Web service we are creating. We will use a new file named services.xml to do that.

web.xml

First, let's work on web.xml. We need to add the following XFire servlet-related entries:

 

<servlet> <servlet-name>XFireServlet</servlet-name> <display-name>XFire Servlet</display-name> <servlet-class>org.codehaus.xfire.transport.http.XfireConfigurableServlet </servlet-class> </servlet>

<servlet-mapping> <servlet-name>XFireServlet</servlet-name> <url-pattern>/servlet/XFireServlet/*</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>XFireServlet</servlet-name> <url-pattern>/services/*</url-pattern> </servlet-mapping>

services.xml

Now we have to say what our Web services consist of. This is done in a file named services.xml, which is placed under the META-INF/xfire directory. This whole directory is placed under the WEB-INF/classes folder, which is in the standard classpath of Web applications. Here are the basic configuration entries in services.xml:

 <beans xmlns="http://xfire.codehaus.org/config/1.0">
  
  <service>
    <name>Banking</name>
    <namespace>mybank</namespace>
    <serviceClass>com.mybank.xfire.example.IBankingService</serviceClass>
    <implementationClass>com.mybank.xfire.example.BankingService</implementationClass>
  </service>  
  
</beans>

Let's see what we have here. The definition of our Web service is contained inside a <service> element, which contains a few child elements. The first child element is <name>, which can be any valid XML name you provide. This will be used by client programs and other components to locate your service. For example, after the service is up, you'll use this name on a browser to see the WSDL.

The next child element is <namespace>. Any valid XML name is fine. <namespace> will be used to uniquely identify various parameters of your service.

The <serviceClass> element contains the Java class name that specifies the method signature. In our example, it is the interface IBankingService. If your Java class does not implement any interface, you'll put that class name here. You may have several methods in your Java class or interface. Just one entry is needed to expose them all as Web services.

The <implementationClass> holds the Java class name that has the method implementations. This is an optional element. If the previous element <serviceClass> contained an interface, the corresponding implementation class must be named here.

That's it. Configuration of our Web service is complete.

XFire and other libraries

Now we come to the last step, which is to get all necessary library files. How do we get them? Go to the XFire Website, download xfire-distribution-1.0.zip, and unzip it in a local folder. Copy the following jar files from the distribution and its lib directory into the WEB-INF\lib:

  • activation-1.0.2.jar
  • commons-codec-1.3.jar
  • commons-httpclient-3.0.jar
  • commons-logging-1.0.4.jar
  • jaxen-1.1-beta-8.jar
  • jdom-1.0.jar
  • log4j-1.2.x.jar
  • mail-1.3.3_01.jar
  • spring-1.2.x.jar
  • stax-api-1.0.jar
  • wsdl4j-1.5.2.jar
  • wstx-asl-2.9.jar
  • xbean-2.1.0.jar
  • xbean-spring-2.2.jar
  • xfire-all-1.0.jar
  • XmlSchema-1.0.jar

We are done. Let's deploy and start the application. To deploy the example application, just copy websvc.war into the webapps directory in your Apache Tomcat environment and wait a few seconds. It should start automatically. The application's complete source code is also contained in this war file. Our program is now ready as a Web service.

How do we know the Web service is working?

To see if the Web service is working, we'll have to test. First, we test to see if the WSDL is available. Let's type the URL on a browser. Which URL? Since our application's war file is websvc.war and the service name given in services.xml is Banking, the WSDL URL would be: http://localhost:8080/websvc/services/Banking?wsdl.

Please note: The first part of your URL, i.e., http://localhost:8080, may differ depending on your application server's setup. Regardless, as you type the URL, you'll see an XML document whose root element is <wsdl:definitions>. This document is called the service's WSDL. If you see it, this is the first verification that your application is available as a Web service.

But this test is not enough. Situations may arise where you could see the WSDL, yet the service may not be accessible from clients. So to verify whether the service is up, we must go for a real test using a client program that makes an actual call to the service.

Developing a client

You can create clients with any SOAP tool, such as .Net or Apache Axis, in a variety of ways: using stubs generated from WSDL, using dynamic proxy, etc. In our example, we use a dynamic proxy in a simple servlet named WsClient.java. To keep coding efforts minimum, all screen building elements are put inside the doGet() method. The actual call to the Web service is made in the callWebService() method, which is pretty simple. It looks like this:

 

/* Call the Web service * */ public String callWebService( String fromAccount, String toAccount, double amount, String currency) throws MalformedURLException, Exception { //Create a metadata of the service Service serviceModel = new ObjectServiceFactory().create(IBankingService.class); log.debug("callSoapServiceLocal(): got service model." ); //Create a proxy for the deployed service XFire xfire = XFireFactory.newInstance().getXFire(); XFireProxyFactory factory = new XFireProxyFactory(xfire); String serviceUrl = "http://localhost:8080/websvc/services/Banking"; IBankingService client = null; try { client = (IBankingService) factory.create(serviceModel, serviceUrl); } catch (MalformedURLException e) { log.error("WsClient.callWebService(): EXCEPTION: " + e.toString()); } //Invoke the service String serviceResponse = ""; try { serviceResponse = client.transferFunds(fromAccount, toAccount, amount, currency); } catch (Exception e){ log.error("WsClient.callWebService(): EXCEPTION: " + e.toString()); serviceResponse = e.toString(); } log.debug("WsClient.callWebService(): status=" + serviceResponse);

//Return the response return serviceResponse; }

What's going on in this code? Let me explain: First, we create a service model, which contains the service specifications—in other words, the service's metadata. We create this model from the interface IBankingService.class using XFire's ObjectServiceFactory.

The next step is to get a proxy factory object for XFire, which involves routine code, and is pretty simple and straightforward. There is nothing application-specific in this step. From this proxyFactory, using the service model and the service endpoint URL (used to get the WSDL), we get a local proxy for the service.

That's it. This proxy is the actual client. We can now invoke its transferFunds() method to get the Web service we want.

Once the example application is deployed and started, try the servlet URL: http://localhost:8080/websvc/ws.

The servlet uses default parameters to call the Web service and displays the response received. The last two lines of the page should read:

 Response Received
COMPLETED: CDN$ 500.00 was successfully transferred from A/C# 11111-01234 to A/C# 99999-05678

Now you can be sure that the Web service is up and running.

To try with different input values, you could also use a full URL like this: http://localhost:8080/websvc/ws?from=11-2345&to=77-9876&amt=250.00&cur=EUR.

Basic Web services development checklist

This checklist summarizes the steps required to expose a Java method as Web service:

  1. Check that the Java class's method and the default constructor are public
  2. Add XFire servlet-related entries to web.xml
  3. Create services.xml and put it under the WEB-INF/classes/META-INF/xfire directory
  4. Add the XFire and third-party libraries into your Web application's WEB-INF/lib directory

That's all that's needed. Yes, it's that simple.

Other advanced features of XFire

XFire may be simple to use, but in terms of features and functionalities, it is at the leading edge. Some of its advanced features are:

  • Native data binding support for plain-old Java objects (POJOs), XMLBeans, Java Architecture for XML Binding (JAXB), Castor, etc. Data binding specifies how the XML requests coming to the Web service and the XML responses going out are mapped to Java objects.
  • Use of the Streaming API for XML (StAX) to process XML documents. In contrast with the Document Object Model's tree-based approach and the Simple API for XML's event-driven approach, StAX uses a pull-based mechanism, which makes it much faster and more memory-efficient.
  • Support for various transport protocols such as HTTP, Java Message Service, and in-JVM transport.
  • Embeddability, which is one of XFire's core strengths. You can embed this SOAP engine into your application and completely hide all XFire-specific references, as all configurations are program-driven.
  • Rich API, which makes it highly customizable and allows developers to intercept requests at various stages and handle them as required.
  • Compliance with latest standards such as SOAP 1.1 (no encoded remote procedure call, or RPC) and 1.2, WSDL 1.1, the Web Services Interoperability Organization's Basic Profile 1.0, Web Services Addressing, and WS-Security.

Most importantly, XFire belongs to a new generation of Web services engines. Not just a marketing phrase, "new generation" has some significance. Apache Axis was one of the first Web services engines in Java and became a benchmark for all tools that came later. Axis and these other tools have been field-tested in many production environments over the last few years. One of the key lessons learned is that Web services are not best suited for RPC-style communications. For performance and efficiency, document-oriented messaging-style is the way to go. But Apache Axis and most other Web services engines are, by design, RPC-oriented (although they support the document style). The industry is now in the process of developing a new generation of SOAP engines, which are, by design, document-oriented. Apache has already announced the end of development for the old Axis engine and is now working on Axis2, which is now on its prerelease version of 0.95. XFire had its first production release (1.0) in February this year. Its next release (1.1) is slated to be available in just a few weeks.

Performance

Web services consume many resources, but they are not known to be attractive in terms of performance. XFire breaks that trend. It consumes significantly less memory (in part because of the use of StAX), but performs much better than most comparable SOAP engines. You can see a few comparative results in the links provided in Resources.

Additionally, XFire also provides ways to optimize performance further. One such approach uses the in-JVM transport. If you know that the Web service is running in the same JVM as the client, you could choose to use a local transport that would make your services scream. In the example's client code, look at the line where the service endpoint URL is specified:

       String serviceUrl = "http://localhost:8080/websvc/services/Banking";

Replace it with:

       String serviceUrl = "xfire.local://Banking";         

You'll see a dramatic increase in performance as the whole network layer is bypassed.

Limitations

XFire has some important limitations you should be aware of:

  • A good practice in developing Web services is to start from the WSDL. Most SOAP engines provide tools to generate service stubs from WSDL. XFire also provides such a tool. But it is annotations-based and hence needs J2SE 5.0. It's not a show-stopper for people like me who are still stuck in J2SE 1.4.x, because we have other ways to write clients, one of which was illustrated in this article's example.
  • Support for attachments, which is slated for a future release.
  • Easy-to-follow user guide; the XFire team has a lot of work to do here.

Conclusion

The current trend in Java is to simplify the usage of technologies. Thus, we are seeing a wave of POJO-based development efforts. At the same time, service-oriented architecture (SOA) and Web services have become hot topics in the industry. XFire truly fits this scenario. It enables POJOs to be exposed as Web services with minimum effort. Thus, it greatly smoothes the learning curve for novice developers who want to use this technology. At the same time, with its up-to-date standard compliance and rich API, XFire opens up many more opportunities for advanced users.

Shahid Ahmed is a software architect now consulting with a major wireless carrier in the U.S. He started developing software about 22 years ago, when Kaypro, Osborne, Apple II, and TRS-80s ruled the earth. For the last seven years, his focus has been mostly on Java. His current works involve SOA, Web services, messaging, POJOs, Spring, Ajax, etc. Shahid is a software addict who strives everyday to balance between a fascination for technology and love for social life.

Learn more about this topic

Join the discussion
Be the first to comment on this article. Our Commenting Policies