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:
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.
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:
String fromAccount
String toAccount
double amount
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.
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.
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>
<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.
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:
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.
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.
<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.
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 serviceService serviceModel = new ObjectServiceFactory().create(IBankingService.class);log.debug("callSoapServiceLocal(): got service model." );//Create a proxy for the deployed serviceXFire 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 serviceString 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 responsereturn 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 ReceivedCOMPLETED: 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.
This checklist summarizes the steps required to expose a Java method as Web service:
That‘s all that‘s needed. Yes, it‘s that simple.
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:
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.
XFire has some important limitations you should be aware of:
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.
聯(lián)系客服