Axmor Software - Custom Solutions CompanyServicesTechnologiesQualityGanttChartCase StudyContact

Technologies


Realize My Ideas
Requirements Definition Services
Secure My Solution
Software Security Services

Implement and deploy Web services in an Apache Geronimo application


A real-world demonstration of Geronimo's robust Web services support

Ivan Dubrov, System Architect, Axmor
Artem Papkov, IBM
James Smith, Manager and Managing Consultant, IBM

Originally published by IBM developerWorks in November 2005


In the last three years, Web services have taken the world by storm. Today, it does't matter if your enterprise application is deployed at a small mom-and-pop shop or is part of a multidomain enterprise infrastructure -- if your application collaborates with others, it must support Web services. In this article, the IBM Advanced Technology Solutions team gives you a thorough overview of the Apache Geronimo application server's Web services features and a demonstration of how these features can be used to create Web services-enabled enterprise applications. Follow along and find out how to implement and deploy Web services into a Geronimo application using the example, which uses an emulated banking scenario.

The approach

A modern enterprise can be quite a complex system that faces a lot of opportunities and challenges every day. Many such challenges concern the ease of integration or collaboration with other systems and enterprises. Therefore, enterprise developers are wise to ensure that applications are easily accessible by other applications. Web services are a great way to provide this accessibility.

The Apache Geronimo application server supports Web services along with other aspects of the latest Java™ 2 Platform, Enterprise Edition (Java EE) specification. To demonstrate Web services support within the Geronimo application server, the IBM Advanced Technology Solutions team has decided to enhance a software emulator of a simple banking scenario that was developed for a previous developerWorks article titled "Build a secure enterprise infrastructure with Geronimo" (developerWorks, July 2005).

The business scenario used for this article implements a funds transfer use case. The application can be accessed by retail bank customers (users) who need to transfer funds from their accounts and by auditors who supervise all banking transactions. The existing funds transfer application is enhanced to enable a Web service for back-end functionality using the Simple Object Access Protocol/Hypertext Transfer Protocol (SOAP/HTTP) and simple Web service client for service invocation.

What is a Web service?

A Web service is a piece of application business logic that can be executed using ubiquitous Web protocols and data formats, such as HTTP and SOAP. Since the 1.4 release of Java EE, Web services have been in the general Java EE picture. A Web service in the Java EE context is considered a facade to a back-end implementation -- an Enterprise JavaBean (EJB) or servlet. The following artifacts make up a Web service:

  1. The Web Service Definition Language (WSDL) document that describes the service interface and ports (see Resources for a link).
  2. A service endpoint interface that is implemented by the server part and used for invoking service methods on the client. The binding from the WSDL is mapped to this endpoint interface where WSDL binding is a piece of WSDL that defines the protocol of the Web service.
  3. The Java API for XML-based RPC (JAX-RPC) descriptor that contains different mappings from XML to Java technology, such as XML Schema Definition (XSD) types from the WSDL document to the Java types and XML elements to the endpoint interface method parameters.
  4. A service implementation -- an EJB or servlet.
  5. The Web services deployment descriptor, webservices.xml.

The following sections go through the process of developing these artifacts to build a Web services-enabled application for Geronimo.

Create a Web service

First, start by developing the Web service itself. To do that, you must create the following artifacts in the same order. (Details on each step follow shortly.)

  1. Generate or develop the WSDL. In this case, the wscompile tool from the Sun Java EE reference implementation is used (see Resources for more information on the wscompile tool).
  2. Develop the endpoint interface. It's developed based on the EJB remote interface.
  3. Map the WSDL types to the Java types with JAX-RPC mapping. The JAX-RPC mapping is generated using the wscompile tool.
  4. Implement an endpoint interface.
  5. Configure the Web service reference in the deployment descriptor. This includes adding a section to the web.xml deployment descriptor.

The following sections detail each of these steps.

The first step you need to follow is to describe a Web service in the WSDL file. In this case, because the Web service provides the same functionality as the business logic EJB, the WSDL can be generated from the EJB interface and manually edited afterwards. [Note that at the writing of this article, Geronimo lacks elaborated tooling support for building Java EE Web services (not Axis-specific, that could be generated using Axis tooling)].

To generate WSDL from the endpoint interface, you must first develop an interface. This interface declares the methods that a Web service implements. The JAX-RPC specification contains restrictions on this interface. In short, the interface should extend java.rmi.Remote -- all methods are declared to throw java.rmi.RemoteException. And, finally, parameters and return values are JAX-RPC compliant (in our case they are JavaBeans with default constructors and primitive types). Simply stated, in the case of the sample application, it's the remote interface of the EJB with the javax.ejb.EJBObject parent interface substituted with the java.rmi.Remote and the caller name parameters removed.

After the endpoint interface for the Web service is implemented, the WSDL can be generated. The next section describes this process.

Generate WSDL from an endpoint interface

Currently, the Geronimo application server does not provide a standard toolset for generating WSDL documents. However, the tooling available at Sun's site for the Java EE 1.4 spec (see Resources for a link) works nicely for our purposes. The tool for generating different Web service-related artifacts is named wscompile and is located in the bin subdirectory of the Sun Java EE distribution.

To generate a WSDL document, a configuration file for the wscompile should be created. Listing 1 demonstrates this configuration:

Listing 1. Configuration file for wscompile tool
<?xml version="1.0" encoding="UTF-8"?> 
<configuration xmlns="http://java.sun.com/xml/ns/jax-rpc/ri/config"> 
  <service name="BusinessLogic" 
           targetNamespace="http://ibm.com/samples/workdev/v1/wsdl" 
           typeNamespace="http://ibm.com/samples/workdev/v1/types" 
           packageName="com.ibm.workdev.v1.interfaces"> 
    <interface name="com.ibm.workdev.v1.interfaces.BusinessLogicEndpoint"/> 
 </service>  
</configuration>

You can see that the structure of the file is straightforward. It contains declarations for namespaces, packages, and references to a service endpoint interface. Listing 2 demonstrates an invocation string for wscompile:

Listing 2. Invoking wscompile
%SUN_J2EE_HOME%\bin\wscompile -classpath <APP_CLASSES>;
%GERONIMO_HOME%\repository\geronimo-spec\jars\geronimo- spec-j2ee-1.4-rc4.jar -gen:server -f:documentliteral config.xml

SUN_J2EE_HOME in Listing 2 is a home directory for the Sun Java EE SDK. APP_CLASSES is where directories with application classes (including the endpoint interface class) are specified. And GERONIMO_HOME is the home directory for Geronimo. Note that the tool generates not only the WSDL, but also a few support classes.

The next step is to update the WSDL produced so the names of the elements are more understandable within this business context. wscompile does not save method parameter names, but converts them in names like long_2 (the parameter type concatenated with the parameter position), which states for? as the second parameter of the method with long type. For example, the second parameter in the performTransfer operation can be renamed to amount.

Next, make sure that all messages have exactly one part. For methods that return no values, wscompile generates messages without parts. This is an error that needs to be fixed. To fix this, you must declare an XML element containing an empty sequence and add a part to the message with this element. Listing 3 demonstrates how such an XML element can be declared:

Listing 3. XSD response type
<element name="performTransferResponse">
  <complexType>
    <sequence/>
  </complexType>
</element>

And here is the snippet from the message declaration:

Listing 4. WSDL message
<message name="BusinessLogicEndpoint_performTransferResponse">
    <part name="result" element="ns2:performTransferResponse"/>
</message>

Alternatively, the WSDL document can be developed from scratch. Note that the Eclipse WTP project (see Resources for a link) contains a handy editor for WSDL documents.

Create JAX-RPC mapping

After the WSDL is generated, the JAX-RPC mappings file and value classes for the methods parameters, and then return values need to be created. They can be generated with the wscompile tool mentioned previously.

The configuration for the wscompile for this case is shown in the following Listing 5:

Listing 5. Configuration for the wscompile
<?xml version="1.0" encoding="UTF-8"?> 
<configuration xmlns="http://java.sun.com/xml/ns/jax-rpc/ri/config"> 
<wsdl 
    location="file:///BusinessLogic.wsdl" 
    packageName="com.ibm.workdev.v1.interfaces"/> 
</configuration>

The invocation line is the following:

Listing 6. Invoking wscompile
%SUN_J2EE_HOME%\bin\wscompile -s src-gen -keep -mapping 
mapping.xml -classpath <SAMECLASSPATH> -gen:client -f:documentliteral
config.xml

The classpath for the tool is the same as in the case of WSDL generation. The src-gen is the name of the directory where source classes for JAX-RPC beans should be placed. Note that you need to create this directory prior to WSDL generation. It's better to separate it from the application source directory because some value classes can already exist, and wscompile overwrites them.

Not all of the generated files are required -- only the source code for the missing beans. For example, in the case of this application, the source code for the Account JavaBean is not required because it already exists. Other sources for the different serializers are not required either -- they are Sun Java EE implementation specific.

The JAX-RPC generated by the wscompile needs some manual post processing. First, all wsdl-message-part-name elements have a value of parameters. You must rename them to match the corresponding element name from the part element sequence (each part of wrapped document/literal formatting has the element with complex type equal to the sequence of elements).

For example, Listing 7 shows the XSD type:

Lising 7. Snippet from the WSDL showing XSD types
<complexType name="registerUser">
  <sequence>
    <element name="username" type="string" nillable="true"/>
    <element name="password" type="string" nillable="true"/>
  </sequence>
</complexType>

Listing 8 shows the corresponding mapping for the method parameter to the message part:

Listing 8. JAX-RPC mapping for the method parameters
<method-param-parts-mapping>
  <param-position>0</param-position>
  <param-type>java.lang.String</param-type>
  <wsdl-message-mapping>
    <wsdl-message xmlns:wsdlMsgNS="http://ibm.com/samples/workdev/v1/wsdl">
      wsdlMsgNS:BusinessLogicEndpoint_registerUser
    </wsdl-message>
    <wsdl-message-part-name>username</wsdl-message-part-name>
    <parameter-mode>IN</parameter-mode>
  </wsdl-message-mapping>
</method-param-parts-mapping>

Note that wsdl-message-part-name in the document/wrapped style gives the name of the element rather than the name of the message part itself.

Another issue is that wscompile generates JAX-RPC mappings for the return value (that are described in the wsdl-return-value-mapping elements) for methods with a void return type. These wsdl-return-value-mapping elements should be removed (otherwise NullPointerException is thrown during the deployment). The correct behavior is not clear from the Web services for Java EE, Version 1.0 specification (one-way methods are not appropriate here because the result is important for the client, as invocation can fail).

Deploy the Web service

In the next step, the webservices.xml deployment descriptor should be developed. It weaves together WSDL, the JAX-RPC mapping, the handlers, and the back-end implementation bean.

To demonstrate the use of Web service handlers, some subset of WS-Security is implemented. Because the handler is executed after the method-level authorization, the handler could not be used for authentication directly (for example, this Business Logic bean cannot be exposed as a Web service with authentication done via such a custom handler). That's why, in this case, Web services represent the facade, with back-end beans not requiring authorization. When executed, this bean gets the credentials captured by the security handler, performs manual authentication, and calls BusinessLogic EJB methods on behalf of the authenticated client.

The server-side handlers are specified in webservices.xml. The handler is a class that implements the interface javax.xml.rpc.handler.Handler. The instance of the handler class is used to filter all incoming requests, outgoing responses, and faults.

The client-side handlers are specified in the service reference in the web.xml deployment descriptor.

The server handler, WSSecurityServerHandler, which is developed as part of the sample application, extracts the username and password from incoming SOAP requests and places them into the thread local variable. This was identified as the only reliable way to transfer the data to the Web services back-end servlet. The Web services back-end servlet uses these credentials to authenticate and call a BusinessLogic EJB under the identity of an authenticated subject using Geronimo-specific code for authentication [because Java Authentication and Authorization Service (JAAS) authentication only is not enough].

The snippet in Listing 9 shows how to call the EJB method under the identity of a subject whose credentials were received from the security handler:

Listing 9. Invoking business logic as a particular security subject
// username and password are obtained from the security handler

LoginContext ctx = createLoginContext(username, password);
ctx.login();
try {
    Set set = ctx.getSubject().getPrincipals(
        org.apache.geronimo.security.IdentificationPrincipal.class);
    IdentificationPrincipal idp = (IdentificationPrincipal)
    		set.iterator().next();
    Subject subject = 
        org.apache.geronimo.security.ContextManager.getRegisteredSubject(
        		idp.getId());
    org.apache.geronimo.security.ContextManager.setCurrentCaller(subject);
    return (Order[])Subject.doAs(subject, new PrivilegedExceptionAction() {
        public Object run() throws Exception {
            BusinessLogic logic = BusinessLogicUtil.getHome().create();
            return logic.getOrders();
        }
    });
} finally {
    ctx.logout();
}

This snippet cannot be moved to the handler code, because a business method (getOrders in this case) should be run under the different subject (doAs invocation), and handlers are executed before the call to the service method.

Listing 10 shows the sample Web services deployment descriptor developed for the application:

Listing 10. Web services deployment descriptor
<?xml version="1.0" encoding="UTF-8"?>
<webservices xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
    http://www.ibm.com/webservices/xsd/j2ee_web_services_1_1.xsd" 
    version="1.1">
  <webservice-description>
    <webservice-description-name>BusinessLogic</webservice-description-name>
    <wsdl-file>WEB-INF/BusinessLogic.wsdl</wsdl-file>
    <jaxrpc-mapping-file>WEB-INF/jaxrpc-mapping.xml</jaxrpc-mapping-file>
    <port-component>
      <port-component-name>BusinessLogicEndpointPort</port-component-name>
      <wsdl-port xmlns:ns="http://ibm.com/samples/workdev/v1/wsdl">
        ns:BusinessLogicEndpointPort
      </wsdl-port>
      <service-endpoint-interface>
        com.ibm.workdev.v1.interfaces.BusinessLogicEndpoint
      </service-endpoint-interface>
      <service-impl-bean>
        <servlet-link>BusinessLogicServiceServlet</servlet-link>
      </service-impl-bean>
      <handler>
        <handler-name>ServerSecurityHandler</handler-name>
        <handler-class>
          com.ibm.workdev.v1.web.wssec.WSSecurityServerHandler
        </handler-class>
        <soap-header 
        	xmlns:wssec="http://schemas.xmlsoap.org/ws/2003/06/secext">
          wssec:Security
        </soap-header>
      </handler>
    </port-component>
  </webservice-description>
</webservices>

Deploy the Web services client stub

Deploying the Web services client stub is simple and straightforward. Perform the following steps to prepare required deployment descriptors and code:

  1. Acquire the WSDL through the URL http://localhost:8080/workdev/service?WSDL.
  2. Develop the endpoint interface.
  3. Map WSDL types to the Java types with the JAX-RPC mapping.
  4. Configure the Web service reference in the deployment descriptor.

Steps 2 and 3 have already been described above. They are almost the same as for the development of a Web service itself. The difference is to set the gen:client option to the wscompile tool instead of gen:server (this option makes the wscompile tool generate the service interface along with other artifacts) in the third step. In fact, the JAX-RPC mapping and beans can be taken from the Web service implementation. The only additional artifact required is the service interface (that extends javax.xml.rpc.Service).

A service reference is placed in web.xml (note that web.xml should have a version of the specification equal to 2.4). The snippet shown in Listing 11 is the example from the Funds Transfer application:

Listing 11. Referencing a Web service in the web.xml deployment descriptor
<service-ref>
  <service-ref-name>service/BusinessLogicService</service-ref-name>      
  <service-interface>
  	com.ibm.workdev.v1.web.BusinessLogicService
  </service-interface>
  <wsdl-file>WEB-INF/BusinessLogic.wsdl</wsdl-file>
  <jaxrpc-mapping-file>WEB-INF/jaxrpc-mapping.xml</jaxrpc-mapping-file>
  <service-qname xmlns:servicens="http://ibm.com/samples/workdev/v1/wsdl">
    servicens:BusinessLogic
  </service-qname>
  <handler>
    <handler-name>ClientSecurityHandler</handler-name>  
    <handler-class>
    	com.ibm.workdev.v1.web.wssec.WSSecurityClientHandler
    </handler-class>
    <soap-header xmlns:wssec="http://schemas.xmlsoap.org/ws/2003/06/secext">
      wssec:Security
    </soap-header>
  </handler>
</service-ref>

Now Web services deployment descriptors are developed, and a Web service instance can be obtained through the Java Naming and Directory Interface (JNDI). Listing 12 shows an example:

Listing 12. Invoking a Web service
InitialContext ctx = new InitialContext();
BusinessLogicService service = 
    (BusinessLogicService) ctx.lookup(
    	"java:comp/env/service/BusinessLogicService");
BusinessLogicEndpoint endpoint = service.getBusinessLogicEndpointPort();
// Invoke methods on the endpoint interface...

In the Funds Transfer application, there is a dispatcher servlet -- WebServiceClientServlet -- which, together with JavaServer Pages™ (JSP), provides a sample interface for invoking Web service methods.

Why not Eclipse WTP?

At the time of this writing, the Eclipse Foundation has released the WebTools Project 1.0RC1, which provides support for Apache Geronimo (additional plugin from the Geronimo project is required) and Web services. Although it's a very promising initiative, this tool is lacking some important features regarding the Java EE Web Services support. In particular, wizards support only the Axis run time for Web services. This leads to the creation of non-Java EE-compliant Web services and burdens the project sources with a lot of generated files. Moreover, these wizards don't support specifying SOAP handlers for both service and Web service clients. This leads to additional effort and tedious hand editing of handlers.

The better approach when developing Web services and their clients is more thorough support for JSR 109 specification (see Resources). Currently, WTP does not support the specification fully and is limited to presentation of the Web service, Web service clients, and their handlers in the Project Explorer tree; so this information can only be viewed, not edited. It might also help if WTP provides rich editors Web Service deployment descriptors, which are webservices.xml, webservicesclient.xml, and JAX RPC mapping descriptors.

Conclusions

This article has described how to use Web services facilities provided by the Geronimo application server to build Web services-enabled applications. It demonstrates that the application server relies on the Java EE 1.4 specification, providing a number of facilities for building both Web services and their clients.

It's worth noting that, although the Geronimo application server doesn't have an officially released set of development tools at the time of this writing, the Eclipse WTP project has initiated the development of such tooling.

Overall, the application server has demonstrated robust support for Java EE standards and will definitely find its place in small to medium enterprise IT.

Resources

Learn
Get products and technologies
Discuss

About the authors

Ivan Dubrov is a software engineer at Axmor. He holds a bachelor of science (cum laude) degree in computer science from Novosibirsk State University. For the last year he took part in more than five Axmor projects as a system architect and a software engineer.

Artem Papkov is currently a Solution Architect with IBM's Client Innovation Team, working with customers and Business Partners to adopt emerging technologies, such as SOA and Web services. After graduating from the Belarusian State University of Informatics and Radioelectronics in 1998 with a master's degree in computer science, he joined IBM in Research Triangle Park, N.C. in 2000. His experience includes software development of multitier solutions using emerging technologies, architecture design, and integration of Internet-based solutions. For the past three years he has been focused on working closely with customers, helping them adopt Web services as IBM's strategic integration technology and SOA as the integration approach.

James Smith has over 18 years of experience in software development. He started his career at Sandia National Labs, Livermore California, designing high-speed data acquisition systems and distributed computing systems using a myriad of existing legacy code. Having deep experience in Java technology and customer-facing skills, Jim moved to the Emerging Internet Technologies team focusing on "making Java solutions REAL" for IBM customers. Jim was one of the founders of Advanced Technology Solutions (ATS), a global software services and development organization. Its mission is to develop, refine, and franchise advanced technologies and lightweight business processes for IBM, development labs, Business Partners, and customers, resulting in faster adoption and deployment of standard technologies and IBM products. Currently, Jim manages the organization.

Contact Us
Want to know your options? Let's talk about your project.
QUALITY CERTIFICATION

Axmor's Media Presence
BBC News discusses Axmor in "High tech in the «Silicon Forest»"
Axmor authors the article "Tapestry and Wicket compared", published on IBM DeveloperWorksmore publications
Examine Your Values
Custom Software DevelopmentJava Programming.NET ProgrammingMobile DevelopmentSoftware ResourcesSite MapContact

Phone in Russia: +7 383 363 0128, Phone in USA: +1 (877) 772 9667
info@axmor.com
Copyright © 2003-2010 Axmor Software - America Inc.