Chapter 6. Web Services in Mule

Another set of transports in use in Mule are those related to web services. First we're going to see how Mule can host or connect to web services using the new CXF transport. Mule still also includes support for Axis, but the default transport for web services is CXF; it replaces the XFire transport, which in Mule 2.0 has been moved to MuleForge.

We do recommend using CXF for web services unless your project requires that you use the RPC/Encoded method. If this is the case then Apache Axis is the way to go. We'll examine the features inside this transport in the second part of this chapter.

Overview

Web services are nothing more than services that are available over a network—be it an internal network or the Internet—that adhere to the Simple Object Access Protocol (SOAP) and Web Services Descriptive Language (WSDL) protocols. A client application that wants to make use of these services can invoke them by using XML messages that are crafted on the SOAP standard. Such a request is understandable to a web service and it will return a response back to the client. If a client does not know what operations a web service provides, the WSDL for the service can be queried to see what operations are supported before the request is made.

Web services can be created using any technology—Axis, CXF, and .NET being the most popular—and clients can invoke web services using any technology too. Mule allows us to use web services by providing an Axis and a CXF transport.

Simple Object Access Protocol

The Simple Object Access Protocol (SOAP) defines the three parts described here to every message:

  • An envelope describes what is in the message and how it can be processed. Each SOAP message is an envelope together with one body and zero or more headers.

  • The encoding rules define a serialization mechanism to allow application-defined data types to be exchanged between different applications. Normal SOAP encoding is not supported by international standards, so interoperable web services are encouraged to avoid using any encoding. This is referred to as "literal encoding."

  • The communication style is either RPC or message oriented. RPC is typically used with SOAP, while "document" style requires more programming work but offers a lower layer of abstraction.

Mule and Web Services

Figure 6-1 shows how Mule can interact with web services. On the left side of the diagram we can see that a third-party item (such as an application) is making a web service call, which refers to a service that is hosted in Mule. This web service call is nothing more than an inbound endpoint for the service. By using inbound web service endpoints Mule can host web services that are accessible to any other application.

On the right side of the diagram we can see that a service in Mule is making a web service call to a third-party item. This web service call is nothing more than an outbound endpoint for the service. By using outbound web service endpoints, Mule can connect to web services hosted by any other application.

In Mule you can configure a component to have a web service as an inbound endpoint. This will cause the component to be hosted as a web service; it will be visible to outside applications as a web service automatically. When a request is received, your component will be invoked.

A component can also be configured to have a web service as an outbound endpoint. This will cause Mule to transform the original request into a SOAP request and route it to a web service. The web service can be hosted either locally or remotely.

Mule and Web Services

Figure 6.1. Mule and Web Services

The web service may also be hosted inside a Mule instance or it could be an external web service. External web services can be constructed using any technology that implements the web services standards, for example Axis, XFire, or .NET. These all require different configurations as we shall see.

Data is transferred through an XML packet across the HTTP transport, which is implicitly used when you define web service endpoints. SOAP can also be used across other transports such as JMS.

The CXF Transport

Apart from Axis, Mule provides the CXF transport for SOAP support. In previous versions of Mule this was called the XFire transport and was implemented as the XFire engine. After looking at the evolution of the XFire transport to CXF, we will see how this protocol can be used inside a Mule application.

From XFire to CXF

XFire is a Java SOAP framework that provides an easy-to-use API to build web services. It uses a low-memory model based on STaX (Streaming API for XML) that delivers high performance and can be used over HTTP, JMS, XMPP, and VM transports. An XFire transport is included with Mule 1, but as mentioned previously, for Mule 2 it has been moved to MuleForge.

In 2006, the Celtix and XFire communities merged to provide a single web service platform, CXF (the name is based on the merging of Celtix and XFire). The result is an Apache project that provides an easy-to-use API that lets you build services that can communicate using SOAP, RESTful HTTP, or CORBA over HTTP, JMS, VM, or JBI.

The CXF Connector

CXF uses the Java API for XML Web Services (JAX-WS) standard, which is a series of APIs and annotations that allow you to easily build web services. In Mule it normally operates over HTTP, but it can be used across the other transports too.

The required XML namespace and schema are listed here, and are available from the MuleSource site:

xmlns:cxf=
 "http://www.mulesource.org/schema/mule/cxf/2.0"
xsi:schemaLocation=
 "http://www.mulesource.org/schema/mule/cxf/2.0
  http://www.mulesource.org/schema/mule/cxf/2.0/
     mule-cxf.xsd"

Attributes

One key attribute on the CXF connector is the defaultFrontend attribute, which allows you to specify that your CXF web services do not contain any JAX-WS annotations. By default this is set to jaxws, but you can change it to simple if your classes do not have annotations.

The endpoint attributes are as follows:

  • frontEnd is the endpoint-level attribute for the defaultFrontend attribute.

  • wsdlLocation lets you specify a location for the WSDL file if you do not want the CXF transport to create one automatically for you.

None of these attributes are required.

Hosting a CXF Web Service

Services in Mule can become CXF web services provided they have an inbound CXF endpoint. The most significant consideration is whether you can, or want to, use annotations.

Simple Front-End Implementation

If your classes are POJOs that cannot use annotations, you will need to implement your web service via your Mule configuration. This approach means you do not need to modify any code and makes it the ideal approach for migration from XFire and previous Mule versions. The web service would be configuration-driven since every setting will be included in the Mule configuration file.

Here's an example of a simple front end to any CXF web service implemented in Mule:

<cxf:connector name="CXFConnector"
                defaultFrontend="simple"/>

The preceding code snippet shows how the CXF connector can be configured to use the defaultFrontend attribute so that it will not look for the annotations within the hosted classes. Setting this attribute here will enable it for all endpoints, but you can configure this on an endpoint-by-endpoint basis using the endpoint's frontend attribute as shown in the following example:

<service name="ticketStatus">
   <inbound>
      <cxf:inbound-endpoint frontend="simple"
           address="http://10.0.0.1/status"/>
   </inbound>
   <component class="com.ricstonairways.Ticket"/>
</service>

Warning

A port should always be set. If you do not specify one, a default value of −1 will used.

Using Annotations

You can also use JAX-WS annotations in your classes to describe the CXF web service. You will need to create an interface to the class that you wish to host as a web service and annotate this class according to the JAX-WS API. You can also include references to an existing WSDL if you develop by contract rather than let the CXF transport generate the WSDL for you.

A key benefit of annotations is that they provide you with a short and concise manner in which to describe your web service. This "shorthand" reduces the amount of code that is needed.

Our next example shows an interface to a class that we will then use as a web service. It has a single method that returns the status for an airline ticket represented by the passenger name record (PNR) identifier.

package com.ricstonairways;

import javax.jws.WebService;

@WebService

public interface StatusInterface
   { String getStatus(String paxRecord); }

Note

We are importing the JAX package and annotating the interface by using the @ notation to indicate that this interface will be used as a web service.

The class that implements the previous interface is shown in the next example. It is annotated to show which interface is going to be used and the name of the web service.

package com.ricstonairways;

import javax.jws.WebService;

@WebService(endpointInterface ="com.ricstonairways.
StatusInterface", serviceName = "PNRStatus")

public class statusRetrieval implements StatusInterface
{
   public String getStatus (String paxRecord) {
      return paxList.find (paxRecord).status;
   }
}

The Mule configuration shown here allows us to host this annotated class as a CXF web service. It is similar to the configuration shown earlier but without the frontEnd attribute.

<model name="CxfExample">
   <service name="ticketStatus">
      <inbound>
         <cxf:inbound-endpoint address=
               "http://10.0.0.1/status"/>
      </inbound>
      <component class="com.ricstonairways.
                 statusRetrieval"/>
   </service>
</model>

You can invoke this web service from within a web browser by using the http://host/service/OPERATION/PARAM_NAME/PARAM_VALUE format, which would look like this URL: http://10.0.0.1/status/ticketStatus/flightStatus/flightCode/RA1234.

Programming by Contract

If the WSDL is defined before you start creating classes and services, then this is known as contract-first programming. In such cases, you would not want the CXF transport to generate a WSDL automatically but use an existing one. You also need to be sure that the classes in use match the descriptions in the WSDL file.

Tip

We recommend that you adopt this model as your preferred approach; most people developing web services are moving to contract-first programming.

Using a WSDL-to-Java tool, you can create an interface based on the existing WSDL file and implement this interface in your class. Such a class can then be used in the same way we've just seen.

Alternatively, the external WSDL file can be referred to from within the JAX @WebService annotation or on a Mule endpoint directly. References can be made to a WSDL file that is located on the classpath, somewhere on the file system, or to a resource somewhere in a web application.

@WebService(endpointInterface =
   "com.ricstonairways.StatusInterface",
   serviceName = "PNRStatus",
   wsdlLocation="./Status.WSDL")

In the preceding example, the location of the WSDL file is defined within the @WebService annotation inside the Java class. The next example shows how you can achieve the same effect by referring to the WSDL file from the inbound endpoint of your Mule configuration:

<cxf:inbound-endpoint
   address="http://10.0.0.1/status"
   wsdlLocation="./Status.WSDL"/>

This can be a valid reference to the file system, a file on the classpath, or a resource within your web application.

CXF Outbound Endpoint

The CXF transport allows you to use a CXF-generated client as an outbound endpoint. This client needs to be generated using the WSDL-to-Java tool mentioned earlier. The foreign web service can be local (on the same machine) or remote, and can be built using any web technology. As long as a valid WSDL is available, the CXF outbound endpoint can be used.

These are the attributes to configure on the endpoint:

  • clientClass is a reference to the class that was generated with the WSDL-to-Java tool.

  • wsdlPort is a reference to the WSDL port that you want to use to talk to the service.

  • wsdlLocation is a reference to the WSDL file.

  • operation is the name of the operation to invoke on the web service. The objects passed to the endpoint must match the signature of the method for this operation. If the operation takes in multiple parameters, they must be put in an Object[] array.

In the following example the CXF outbound endpoint has a valid address as before, which refers to the web service to invoke. The clientClass attribute refers to the class generated by the WSDL-to-Java tool for the WSDL file specified in the wsdlLocation attribute. The operation to invoke on this web service is the getTicket method.

<outbound>
   <outbound-pass-through-router>
      <cxf:outbound-endpoint address=
         "http://www.ricstonairways.com/buyTicket"
         clientClass="com.travelagent.buyTicket"
         wsdlLocation=""http://www.ricstonairways.com/
               wsdl/MA_BuyTicket.wsdl"
         operation="getTicket"/>
   </outbound-pass-through-router>
</outbound></service>

The Axis Transport

The Axis transport publishes components as Axis web services, or connects to web services using the Axis engine. In either case Mule uses an HTTP connector with default values and routes messages over HTTP to or from web services. However, SOAP messages can be transmitted over the JMS and VM transports using Axis. E-mail should also be supported but is not working properly at the time of writing.

Axis web services use the RPC/Encoded style by default. You can change this at an endpoint level so that web service invocation will use the correct style, but (on the inbound side) Mule-hosted services cannot be exposed as "Document/Literal" using the Axis connector. The required XML namespace and schema are listed here, and are available from the MuleSource site:

xmlns:axis=
 "http://www.mulesource.org/schema/mule/axis/2.0"
xsi:schemaLocation=
 "http://www.mulesource.org/schema/mule/axis/2.0
  http://www.mulesource.org/schema/mule/axis/2.0/
     mule-axis.xsd"

Axis Connector Attributes

This list of attributes is not exhaustive but these are the most commonly used ones:

  • clientConfig refers to the configuration file to use when building an Axis client. This is used for Axis outbound endpoints only.

  • serverConfig refers to the configuration file to use when building an Axis server. This is used for Axis inbound endpoints only.

  • treatMapAsNamedParams controls how maps are interpreted by the connector. By default, the Axis connector assumes that a map contains multiple named parameters and unpacks them accordingly. If, however, your service expects a map, this will cause problems, so you will need to set this parameter to false.

The Axis connector has the following child element:

  • While Axis can handle the serialization of primitive data types on its own, it would not know how to handle complex data types. Any nested data types need to be declared within the bean-type element. For example; if you had an object called org.mule.student that has an attribute of type org.mule.person.address, you will need to add org.mule.person. address to this list. You can define multiple bean-type elements for a single Axis connector.

Unlike other transports, Axis allows you to set up properties on the endpoints that are not configurable at a connector level.

  • wsdlFile lets you define a WSDL file to use for an inbound endpoint. This makes sense if you want to use an existing WSDL file (for example, if you are developing by contract), as otherwise you could let Axis generate the WSDL automatically for you.

  • style refers to the SOAP style to use and can be set to RPC, DOCUMENT,MESSAGE, or WRAPPED.

  • use refers to the manner in which the SOAP packet will be used and can be set to ENCODED or LITERAL.

Axis endpoints also have child elements that refer to the options for this web service call.

  • The Axis options element lets you include a comma-separated list of allowedMethods to expose. By default this is set to *, meaning "all."

  • You can also configure the bean-type classes as elements on endpoints instead of on the connector.

  • The soap-service child element lets you specify an interface that a Mule-hosted component implements. By listing the interfaces you want to expose, you can restrict which methods can be invoked on this component. It is similar to using the axis:options but here you have the option to specify an interface rather than list methods one by one.

Hosting an Axis Web Service

Here we have a simple Mule service that hosts the com.ricstonairways. environment.weatherService component. It has a single inbound web service endpoint that exposes the component as a web service on http://localhost:81/WeatherService.

<service name="WeatherService">
   <inbound>
      <inbound-endpoint address=
             "axis:http://localhost:81"/>
   </inbound>
   <component class="com.ricstonairways.environment.
                      weatherService"/>
</service>

Note

The WeatherService component must implement an interface. The methods in this interface will be available for clients of this web service.

Clients can then retrieve the WSDL for the web service or invoke any of the methods within this class by adding ?WSDL to the URL as a parameter, as shown here:

http://localhost:81/WeatherService?WSDL

The required parameters can also be encoded on the URL, for example to specify the method to invoke and the location for which weather data is required.

http://localhost:81/WeatherService?method=getWeather&town=London

Connecting to an Axis Web Service

Mule applications can invoke Axis web services by using a web service outbound endpoint as shown here:

<service name="WeatherService">
   <inbound>
      <inbound-endpoint address="vm://fromClient"/>
   </inbound>
   <bridge-component/>
   <outbound>
      <outbound-pass-through-router>
         <outbound-endpoint address=
               "axis:http://10.0.0.1:81/
                  weatherService?method=getWeather"/>
         </outbound-pass-through-router>
   </outbound>
</service>

Warning

The outbound-endpoint address is split over two lines and should be joined into one contiguous URL in a working configuration.

Here, a bridge component is used to forward the message received on the VM fromClient queue to the web service. While the endpoint needs to have the method name included on it, the MuleMessage payload will be used as the parameter for the web service.

In this case the web service may exist locally, that is on the same computer, or on another machine. You will only need to change the IP address or computer name.

Invoking Non-Axis Web Services

If you want to invoke a web service that is not an Axis web service, you will need to adjust the outbound endpoint to handle this. The Axis transport cannot automatically handle non-Axis web services, so most of the properties need to be configured manually. You can get the information about the foreign web service by looking at the WSDL for it

You then need to configure the following:

  • The SOAP action format. This can be done automatically by Mule but needs to be explicitly configured if invoking .NET web services.

  • The namespace. Declare the full name of the method being invoked (including the URL).

  • The parameters used. This is a list of the names and types of all parameters that the method accepts. Some web services expect you to name the parameters and will raise exceptions if you try and invoke them without naming them first.

  • The return type of the method. Similar to the previous point, the return type of the method may also need to be defined.

This example demonstrates how to invoke a non-Axis web service by using an outbound router collection with a single outbound router that will pass the Mule message to an Axis endpoint:

<outbound>
   <outbound-pass-through-router>
      <axis:outbound-endpoint address=
         "axis:http://10.0.0.1:82/weatherService?
         method=getWeather"
         soapAction="http://localhost:82/${method}">
            <axis:soap-method method="getWeather">
               <axis:soap-parameter
                  parameter="city"
                  type="string"
                  mode="IN"/>
               <axis:soap-return type="string"/>
         </axis:soap-method>
      </axis:outbound-endpoint>
   </outbound-pass-through-router>
</outbound>

Note

Note The axis:outbound-endpoint address is split over two lines and should be joined into one contiguous URL in a working configuration.

Because the web service being invoked is not an Axis web service we need to configure the following items:

  • The soapAction attribute for the outbound endpoint. This indicates which method is going to be invoked and can be retrieved from the WSDL. The parameterized value in this example refers to the method encoded in the endpoint address.

  • The soap-method child element for the outbound endpoint. This element describes the method that is going to be invoked. Its name attribute refers to the name of the method and should match the method listed in the soapAction attribute.

  • The soap-parameter child elements for the soap-method element. Each of the method's parameters needs to be listed here. The parameter attribute is the name of the parameter, the type refers to the data type, and the mode refers to whether this parameter is going to be changed by the web service and sent back. Valid values for this attribute are IN, OUT, or INOUT. In our example we have a single string parameter called city that is set to IN. You can have multiple soap-parameter elements.

  • The soap-return child element for the soap-method element. This describes the return value of the web service. Its attribute, type, lets you specify what data type the return value is.

REST

Representational State Transfer, otherwise knows as REST, is receiving a lot of attention as a better way of implementing web services. REST is actually the software architecture on which the world wide web is built and is not really anything new. It offers a simple yet powerful way of exposing and accessing web services that use an interface (HTTP+XML) with which most developers are already familiar, doing away with the need to learn about the SOAP specification and the accompanying baggage (for example tools) typically required to implement it.

Since Mule includes an HTTP transport and support for XML, you could therefore say that it inherently supports REST; however, the MuleSource team has gone one step further and added the Mule RESTpack to provide you with everything you will need to build RESTful applications with Mule.

Since these are not part of the core distribution, and to really do REST justice, we'd need to write an entire chapter on the subject; we cannot cover it in any detail here in this edition of our book. That will come later in the follow-up edition—please be patient! In the meantime you can learn more and download the RESTpack by pointing your browser at the Mule wiki at http://mule.mulesource.org/display/MULE/Mule+RESTpack.

Summary

This chapter focused on how Mule can connect to or host web services using endpoints that match a SOAP protocol. Mule does this using two specific transports—Axis and CXF. CXF is an extension to the XFire transport and is based on the JAX-WS API.

We can make use of the CXF transport to host a web service by using the default front end (mainly for compatibility reasons) or by creating dedicated interfaces and classes that are annotated with JAX-WS API annotations. You can also combine these two approaches with an existing WSDL file if necessary.

Connecting to a web service using the CXF transport is a matter of configuring the outbound endpoint to refer to a class that is generated for you based upon the WSDL file of the foreign web service.

Finally we added a brief reference to REST, the alternative, and many would argue superior, method to implementing and exposing web services building on the core protocols that power the world wide web and make it so scalable and resilient.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset