he growing acceptance of loosely coupled services in enterprise application development and the continuing buzz around service-oriented architecture (SOA) has created substantial momentum in enterprises for consumable services, which can be invoked and utilized remotely. The significance and value of SOAP-based web services as a medium for achieving a services-driven architecture have also gained wide acceptance during the past few years.

Web services can be created in several ways, but enterprises typically have a substantial investment in existing applications that house business functions. Therefore, they need a design that allows for their domain functions to be easily, efficiently, and securely exposed as web services.

This article explains how to expose existing POJO-driven J2EE applications as web services using Axis2, while still providing enough room for scalability. It describes leveraging Spring, which already serves as the underlying dependency injection container for many J2EE applications today, to further facilitate the creation and control of these services. Finally, it discusses deployment strategies for Axis2 enterprise web services and lists the specific concerns with certain application servers such as IBM WebSphere.

The Application
A typical J2EE application is usually tiered, with distinct presentation and business/domain tiers. Either custom factories/controllers or frameworks such as Spring are used to tie all the components together. Take, for example, an application with a simple web tier and a domain tier that encapsulates the business logic. For the sake of simplicity, the example application in this article combines the web tier and the domain in the same project structure, even though in reality these are distinct. Figure 1 shows the structure of the sample application, AccountWeb.

The application has a domain function called AccountManager, which serves the front-end. AccountManager is implemented as AccountManagerImpl and uses the domain object Account. Again, for convenience, it has hard-coded logic and returns values based on variable pre-determined input. A typical application would have a full-fledged domain/business tier with data-access and integration components providing data.

The remainder of the article demonstrates how to expose the AccountManager function and both of its methods as externally consumable web services using Axis2 and Spring.

Creating Web Services Using Axis2
A web service consists of provider-side code called skeletons and consumer-side segments called stubs. Stubs and skeletons are used for marshalling and unmarshalling requests. Hence, the first step here is creating producer-side components for your service. You can create a web service using a bottom-up or top-down approach. In a bottom-up approach, you create Java classes and then generate a service descriptor, WSDL, from it. With a top-down approach, you create a WSDL and generate Java classes from it. Since you already have your business function in the form of Java classes in the example application, you will use the bottom-up approach.

Axis2 supports both synchronous and asynchronous services. This example utilizes only synchronous services. The following steps summarize the procedure for creating a web service from existing domain classes using Axis2 and Spring:

Generate WSDL from the current implementation.

Generate producer-side skeletons and client-side stubs from the WSDL.

Configure the Spring wiring and edit the skeleton implementation to hook to the existing classes.

Once the services are created and configured, you will need to do the following.

Deploy the service.

Test it with a client.

Before going any further, you need to download Axis2 binaries and install them in the library directory of the application in the classpath. With certain application servers, such as WebSphere and WebLogic, these libraries can cause conflicts with the default libraries provided by the server. Later sections on deployment will delve into this in a bit more detail. For now, it will suffice to know that you can resolve these conflicts by manipulating the classloaders and other classpath policies. (The accompanying source code provides all the examples.)