Login | Register   
RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Expose Your POJO-Based Domain Apps as Web Services : Page 3

Combine Axis2, the next-generation web services API of Apache Axis, with Spring to expose POJO-based, domain-tier applications as both REST- and SOAP-based web services.

Generating Client- and Server-Side Code (Stubs and Skeletons)
With the WSDL generated, the next step is creating the skeletons and stubs for producer and consumer applications, respectively. You again use the Eclipse plug-in to generate the server-side classes using the Axis Data Binding (ADB) option for data binding. Axis2 and the Eclipse plugin support other data bindings such as XMLBeans, etc., but this example uses ADB because of its simplicity. Please note that ADB has limitations. It's not full-featured and may not be sufficient for enterprise applications. A XML-binding tool such as JiBX, which Axis2 supports, might be a more appropriate choice for data binding when you need flexibility and a full set of schema-binding features. Currently, the Axis2 project doesn't provide end-to-end code generation, but the JiBX project provides tools that make things a bit easier.

Figure 3 shows through screenshots the steps for creating producer-side skeletons and client-side stubs.

Click to Enlarge
Screenshot 1
  Click to Enlarge
Screenshot 2
Click to Enlarge
Screenshot 3
  Click to Enlarge
Screenshot 4
Figure 3. Generating Server-side and Client-side Code Using Eclipse Plug-in

At the end of this exercise, the directories for skeletons and stubs should look like those in Figure 4 and Figure 5, respectively.

Figure 4. Generated Server-Side (Skeleton) Code

Figure 5. Generated Client-Side (Stub) Code

Spring Integration
The Spring IoC container has offered substantial flexibility for J2EE applications in terms of class invocation, dependency management, and interception. Since it is already part of the application, it would be nice to extend its usage to deliver Axis2-driven web services. To make this easier, Axis2 comes with Spring support for initializing Spring context and the dependency beans from the Axis classes.

The basic idea of using Spring with Axis2 is to configure Spring so that it injects application beans into the Axis2 Message Receivers of the service. Axis2 recognizes the Spring application context support and identifies the appropriate service implementation bean. The message receivers will then use this bean to delegate implementation. All of these configurations are done in the service deployment descriptor, services.xml. Let's define the Spring applicationContext.xml for your implementation class and create a Spring-aware service class. The following are the edits in the Spring context file:

<beans> <!-- Axis2 web service, but to Spring, its just another bean that has dependencies --> <bean id="springAccountservice" class="com.corp.account.domain.accountmanager.AccountserviceSkeleton"> <property name="service" ref="accountManager"/> </bean> <!-- just another bean/interface with a wired implementation, which is injected by Spring into the web service --> <bean id="accountManager" class="com.corp.account.domain.impl.AccountManagerImpl"> </bean> </beans>

The "accountManager" represents the POJO implementation class and the bean "springAccountservice" defines the producer-side skeleton as a Spring-loaded bean. The goal is to take this "springAccountservice" and make the server message receiver recognize it. You can achieve this by editing the services.xml as follows:

<parameter name="serviceObjectSupplier" locked="false"> org.apache.axis2.extensions.spring.receivers.SpringServletContextObjectSupplier </parameter> <parameter name="SpringBeanName" locked="false"> springAccountservice </parameter>

Here, you have defined a parameter called "serviceObjectSupplier" that takes an object supplier class provided by Axis2 as input. You use the SpringServletContextObjectSupplier class because you are going to initialize the Spring application context as a servlet context in web.xml. This is purely for convenience and demonstration purposes. For scenarios when application context has to be explicitly loaded, Axis2 also provides a SpringAppContextAwareObjectSupplier class. Here is the Spring context configuration in web.xml:

<listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/applicationContext.xml</param-value> </context-param>

The last change you need to make is in the Skeleton implementation class. Given you are now injecting the implementation class, you need to create an empty setter method for Spring to update with a pre-loaded bean. Figure 6 summarizes the general idea and the flow using Spring with Axis2.

Click to enlarge

Figure 6. Axis2 with Spring

Spring provides certain benefits when you use it to implement Axis2 web services. Your applications can easily extend the POJO-based business function implementations to support web service calls and continue to avail the benefits of dependency injection, wiring, and interceptors, which are already part of the application.

Integrating Web Services with Existing Application Domain
Now that you have the web service provider-side structure in place, it's time to integrate it with the existing POJO-driven domain functions. As you saw previously, Spring will inject the POJO class in the Skeleton. Hence, you need to create a setter method in skeleton for it as follows:

public void setservice(AccountManager service) { this.service = service; }

You can now use this object to invoke the methods in the domain class. The domain function will return domain objects, which in this case will be mapped to the web service schema object. You can further optimize this process using tools such as JiBX, which allows you to map directly to your domain objects. Here's the modified server-side code for this:

Account acct = service.getAccount(accountId); GetAccountResponse response = new GetAccountResponse(); com.corp.account.domain.bo.xsd.Account acctXSD = new com.corp.account.domain.bo.xsd.Account(); acctXSD.setAccountId(accountId); acctXSD.setAddress(acct.getAddress()); acctXSD.setFirstName(acct.getFirstName()); acctXSD.setLastName(acct.getLastName()); acctXSD.setStatus(acct.getStatus()); response.set_return(acctXSD);

The last statement in the above code shows the return value as a service response.

Comment and Contribute






(Maximum characters: 1200). You have 1200 characters left.