Chapter 6. Building Web-Based Services with Java

Image

6.1 JAX-WS

6.2 Java Implementation of WS-* Standards

6.3 JAX-RS

JAX-WS and JAX-RS represent, by far, the most common implementation mediums for services as part of contemporary Java-based service-oriented technology architectures. This chapter is dedicated to exploring the technology behind these industry standards and further highlighting related and relevant Java-based technology advancements.

6.1 JAX-WS

SOAP-based Web services support in Java EE 5, 6, and 7 is based on the Java API for XML Web Services (JAX-WS) standard, which is an evolution of the Java API for XML-based RPC (JAX-RPC) standard from the previous versions of Java EE. In keeping with the contract-first service approach advocated by SOA, SOAP-based Web services are described by WSDL. Top-down service development starts from the WSDL to the generated service implementation. JAX-WS must process WSDL and generate Java artifacts that developers can work with. Conversely, bottom-up development creates a Web service and WSDL service description from an existing artifact, such as a Java class.

Bottom-up development is facilitated by many tools to enable the creation of Web services with a few clicks of a button, and early implementations emphasized this aspect of Web service development. However, the tools often provide insufficient control over the artifacts generated, and not all language-specific types map well to XML schema-type definitions. In such cases, bottom-up development can create an undesirable coupling between the service contract and an implementation technology. While many tools provide the option of working in either direction, top-down or bottom-up, using a contract-first service development approach can prevent any implementation technology-specific dependencies.

JAX-WS supports the following:

• SOAP 1.1, SOAP 1.2, WSDL 1.1, and WSDL 2.0

• compliance with WS-I Basic Profile 1.1, which precludes the use of any encoding other than literal (JAX-WS only supports literal encoding)

• asynchronous invocation provided by the service consumer programming model, which supports both polling and callback

• dynamic client- and dynamic server-side programming models

• MTOM, which has replaced SwA as the interoperable standard for handling attachments to SOAP messages

• use of JAXB for all type mapping, which is simpler than the mapping approach taken by JAX-RPC, with support for greater schema constructs

JAX-WS utilizes annotations to simplify the programming model, using an approach similar to EJB 3.0. Annotations remove the need for complex deployment descriptors. JAX-WS also simplifies XML-to-Java binding by delegating the data marshaling/unmarshaling to JAXB. JAX-WS-based code generation maps WSDL portTypes to a Java interface called the service endpoint interface (SEI). Recall that portTypes are renamed interfaces in WSDL 2.0. SEI provides a Java abstraction of the service, which removes the need to manage the details of SOAP messages and leaves the service developer free to focus on service implementation.

Within SEI, WSDL operations are mapped to Java methods. Faults are mapped to Java exceptions, which inherit from javax.xml.ws.soap.SOAPFaultException. WSDL service elements are mapped to a service class. SEI is used in service implementations and service consumer implementations in JAX-WS. For service implementations, JAX-WS provides static and dynamic programming models.

With the static model, a SEI is generated at development time, which can be accomplished using a wsimport tool within many JAX-WS implementations. Using the top-down approach, the SEI is generated by specifying the location of a WSDL file as a parameter to wsimport. The service developer is left to provide the implementation of the SEI.

With the JAX-WS dynamic programming model, instead of implementing an SEI that relates to a specific WSDL, the service developer implements the generic javax.xml.ws.Provider interface. This requires greater development effort than the static implementation method. The developer must deal directly with the XML payload, including working out which operation has been called. However, dynamic programming allows the developer to avoid situations where the complexities of some XML schema constructs may not be satisfactorily handled by a data binding framework, such as JAXB. The developer can choose to handle the entire protocol message (the SOAP envelope) or just the message payload (the SOAP body).

The static and dynamic programming models offered by JAX-WS also benefit Web service consumers. With the static model, a proxy class is generated from the SEI. The service consumer calls Web service operations by invoking methods on the proxy. This has similar advantages to the static service model in providing a simple Java-centric abstraction of the service and shielding the developer from the details of the SOAP message. The proxy is created by calling the getPort() method of the Service class generated at build-time from the WSDL using wsimport or a similar tool.

The dynamic client or dispatch client model uses javax.xml.ws.Dispatch, which requires no SEI or WSDL. The invocation is performed by building the relevant objects dynamically using methods that accept qualified names as parameters. The generic javax.xml.ws.Service class acts as the factory for dispatch-based service consumers, and offers several overloaded createDispatch methods to return appropriate dispatch instances for the caller. The dispatch-based service consumer has a more labor-intensive programming model than the static alternative and exposes the developer to the details of SOAP messages. However, the dynamic model offers a more flexible, albeit complex, option of bypassing the XML-to-Java mapping, which is preferable in situations involving extremely complex mapping requirements that cannot be completely addressed by frameworks, such as JAXB.

Beyond service implementation and development, JAX-WS employs annotations to call Java Web services from a Java EE application. With JAX-RPC, calling a J2EE Web service from Java code running on the application server or in a client container is achieved via a resource reference or by performing a JNDI lookup. In the JAX-WS implementation of Java EE, resource injection uses a @WebServiceRef annotation within the Web service consumer. The annotation tells the container to look up the referenced resource and inject it into the annotated instance variable. The Java platform defines a rich set of annotations which allow a degree of control when developing Web services.

Annotations are covered by a number of Java Specification Requests (JSRs). JSR 181 (Web Services Metadata) defines annotations that allow control over the various elements defined in the WSDL, such as the names of portTypes, operations, and namespaces used. JSR 224 (JAX-WS) annotations are specific to JAX-WS, and allow control over artifacts generated for JAX-WS Web services, including specification of bindings, request/response wrappers, faults, and handlers. JSR 222 (JAXB) annotations are specific to JAXB classes generated for data binding of Java Web Services. Finally, JSR 250 (Common Annotations) defines a number of annotations used to control resource injection, of which JAX-WS makes use for resource injection.

The Java Web Services platform keeps the implementation of services separate from the runtime requirements, such as security and transactionality, which are defined at deployment or assembly time through deployment descriptors without changing the code that provides the service implementation. JAX-WS is used to support top-down development, when a tool like wsimport is used to generate the SEI from the WSDL document. Wsimport also generates the JAXB implementation classes mapped from various WSDL constructs. A dynamic proxy or javax.xml.ws.Dispatch-based service consumer can use JAXB implementation classes or a raw XML payload-based message to invoke the service. On the server side, a statically generated SEI implementation or javax.xml.ws.Provider-based service implementation can handle JAXB implementation classes or a raw XML-based payload that represents the incoming message.

SAAJ

The SOAP with Attachments API for Java (SAAJ) operates at a lower level than JAX-WS and offers APIs for managing SOAP messages with or without attachments. SAAJ uses a DOM-based model targeted specifically at SOAP, instead of generic XML messages. SAAJ has evolved from SOAP attachment management to be useful in scenarios where attachments are not involved, such as when a dynamic client is used and no stubs are available or when navigating the tree of a SOAP message directly is a requirement. The classes required to manipulate SOAP messages using SAAJ are included in the javax.xml.soap package.

SAAJ does allow SOAP messages to be sent to a service using the SOAPConnection class, but is more commonly used for the actual manipulation of SOAP messages themselves. Message transport is left to JAX-WS. The JAX-WS specification uses SAAJ 1.3, which has improved upon SAAJ 1.2 with added support for SOAP 1.2 messages. Example 6.1 illustrates the code required to implement an Account Enquiry service. The JAX-WS @WebService annotation allows the service name, port name, and other names for the service to be defined to match the names defined in the service WSDL. The service is implemented as a stateless session EJB, which requires the addition of the @Stateless annotation.

package com.novobank.services.personalbanking;

// imports required to allow use of @WebService and @Stateless
  annotations
import javax.ejb.Stateless;
import javax.jws.WebService;
// import JAXB binding classes (included in sample code for chapter)
import personalbanking.services.novobank.com.accountdetails.
  AccountEnquiry;
import personalbanking.services.novobank.com.accountdetails.
  AccountInformation;

@WebService(serviceName = "AccountDetailsService",
  portName = "AccountDetailsPort",
  endpointInterface = "personalbanking.services.novobank.com.
  accountdetails.AccountEnquiry",
  targetNamespace = "http://com.novobank.services.personalbanking/
  AccountDetails/", wsdlLocation = "META-INF/wsdl/AccountDetails/
  AccountDetails.wsdl")

// Deploy service endpoint as a stateless session EJB
@Stateless
public class AccountDetails implements AccountEnquiry {
  public AccountInformation getAccountInformation(AccountIdaccountId)
  {
    AccountInformation info = lookupAccount(accountId.
      getAccountNumber());
      return info;
  }

  public AccountInformationlookupAccount(String accNo){
    AccountInformation info = new AccountInformation();
    // placeholder for business logic to retrieve account info
    return info;
  }
}


Example 6.1

Implementing a JAX-WS service requires a few lines of code in the WSDL, as highlighted in Example 6.1. Developing a service consumer using JAX-WS is just as straightforward. Example 6.2 shows the code required to call the Account Enquiry service using a JAX-WS dynamic proxy generated from the service WSDL with an IDE.

import com.novobank.services.personalbanking.client.AccountId;
...
AccountId id = new AccountId();
id.setAccountNumber(accId);
id.setBranchNumber(brNumber);
AccountDetailsService service = new AccountDetailsService();
AccountEnquiry port = service.getAccountDetailsPort();
AccountInformation result = port.getAccountInformation(id);
float balance = result.getAccountBalance();
float available = result.getAvailableFunds();
...


Example 6.2

Calling the service with a JAX-WS Dispatch service consumer, as seen in Example 6.3, requires greater development effort and more lines of code. The SAAJ API manipulates the SOAP request/response directly.

import javax.xml.namespace.QName;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPBodyElement;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPMessage;
import javax.xml.ws.BindingProvider;
import javax.xml.ws.Dispatch;
import javax.xml.ws.Service;
import javax.xml.ws.soap.SOAPBinding;
import org.w3c.dom.Node;
...
public static final String SERVICE_URI="http://com.novobank.services.
  personalbanking/AccountDetails";
public static final String SERVICE_NAME = "AccountDetailsService";

QNameserviceName = new QName(SERVICE_URI,SERVICE_NAME);

QNameportName = new QName(SERVICE_URI, "AccountEnquiry");

String  endpointAddress =  "http://localhost:8090/
  AccountDetailsService/AccountDetails";
Service service = Service.create(serviceName);
service.addPort(portName, SOAPBinding.SOAP11HTTP_BINDING,
  endpointAddress);
Dispatch<SOAPMessage> dispatch = service.createDispatch(portName,
  SOAPMessage.class, Service.Mode.MESSAGE);
BindingProviderbp = (BindingProvider) dispatch;
MessageFactory factory =((SOAPBinding) bp.getBinding()).
  getMessageFactory();

try{
  SOAPMessage request = factory.createMessage();
  SOAPBody body = request.getSOAPBody();
  SOAPElement operation = body.addChildElement("AccountId",
    "ns1","http://com.novobank.services.personalbanking/
    AccountDetails/");
  SOAPElementaccNo = operation.addChildElement("AccountNumber", "ns1",
    SERVICE_URI);
  accNo.addTextNode(accId);
  SOAPElementbranchNo = operation.addChildElement ("BranchNumber",
    "ns1", SERVICE_URI);
  branchNo.addTextNode(brNumber);
  request.saveChanges();
  SOAPMessage reply = null;
  reply = dispatch.invoke(request);
  body = reply.getSOAPBody();
  QNameresponseName = new QName(SERVICE_URI, "AccountInformatio n");
  QNamebalanceName = new QName(SERVICE_URI, "AccountBalance");
  QNameavailableFundsName = new QName(SERVICE_URI,"Available Funds");
  SOAPBodyElementbodyElement = (SOAPBodyElement) (body.
    getChildElements (responseName)).next();
  String balance = SOAPElement)bodyElement.getChildElements
    (balanceName).next()).getTextContent();
  String availableFunds = (SOAPElement)bodyElement.getChild
    Elements(availableFundsName).next()).getTextContent();
} catch(Exception ex){
  ex.printStackTrace();
}
...


Example 6.3

Handlers

JAX-WS and JAX-RPC both provide a handler framework that allows processing to be performed on inbound and outbound messages. Handlers can access the contents of a message, perform processing based on the framework, and modify the contents of messages that are on the client side and server side or chained in a sequence.

JAX-WS includes protocol handlers and logical handlers. Protocol handlers allow access to protocol-specific aspects of service requests and responses and only protocol-specific parts. For example, a SOAP handler is a protocol handler that might be used to manipulate headers within a SOAP message. Logical handlers provide a means of accessing data within the body or payload of a service request or response without access to message headers, independent of the protocol and transport used for communication between the service consumer and invoked service. A logical handler can provide separation between protocol-agnostic handler logic that might be reused if an exposed service uses multiple protocols and protocol-specific logic.

Developing a JAX-WS handler involves extending SOAPHandler or LogicalHandler within the javax.xml.ws.handler package. In each case, a message context object is passed to the implementation providing access to the protocol-specific parts of the message or payload. To deploy handlers, a handler chain is defined to specify the order in which handlers are invoked. In JAX-RPC, the handler chain is defined in a deployment descriptor, while the @HandlerChain annotation can be used in JAX-WS with Java EE. Logical and protocol handlers can be mixed in a handler chain. For outbound messages, logical handlers are invoked before protocol handlers, while the reverse applies for inbound messages.

JAX-WS handler APIs make the development of custom handlers a viable option for meeting many requirements. In general, any processing that must be performed on messages that are sent or received by a Web service and not part of the core business or technical function of the service are candidates for implementation in a handler. Handlers can separate the functionality provided by the service and other peripheral functionality required to support the service. However, implementing business logic in a logical handler breaks the encapsulation of the service logic.

Common examples of handlers include logging messages for debugging/audit and generating events collated by a centralized end-to-end message tracking infrastructure. Handlers are also used within a number of Web service runtimes and commercial products for monitoring Web service infrastructures and to enforce WS-* standards compliance, such as the processing of WS-Security headers.

Web Services Engines and Toolkits

The Java specifications and JSRs define a set of standard APIs for working with Web services in Java that include service development and deployment in a server and client environment. A suitable runtime is required to deploy services that are developed using these APIs, and tooling that can assist with development, such as wsimport, is useful.

Several Web services toolkits are available and commonly used to provide development and tooling capabilities. The Java SE Development Kit 7 includes an implementation of JAX-WS APIs. Oracle also provides a Web services runtime and development kit as part of their Java Web Services reference implementation codenamed Project Metro, which includes the implementations of several WS-* standards. The GlassFish Enterprise Server bundles the Metro libraries. Metro can also be bundled with other application servers, although this can sometimes require application configuration changes. Several open-source Web services, runtimes, and toolkits, such as the Apache Web service projects, have also proven popular.

Apache Axis2 provides full support for JAX-WS and JAX-RPC APIs. Axis2 is a complete Web services runtime and toolkit extensible via pluggable modules that allow support for future standards. JAX-RPC and JAX-WS compliance is only one aspect of its functionality. Significant performance enhancements built on the previous Axis version can be attributed to the use of the Apache Axiom, which provides a DOM-like object model for manipulating XML structures in Java and uses the Streaming API for XML (StAX) to implement on-demand parsing. StAX parses XML documents only as data within the document is referenced in code, and only as far as required.

JAXR

The Java API for XML Registries (JAXR) standard allows Java applications to access different types of XML registries using a standard API. Contemporary Java-based service implementations have emphasized proprietary registry technologies and specifications, such as UDDI, ebXML, and JAXR that have declined in practical relevance. This is reflected in how JAXR support has become an optional feature in Java EE 7.

The JAXR specification works in terms of registries and repositories. A repository is a storage space, such as a bank vault where money is stored. Alternatively, a registry is a place to store information about things. Reusing the bank vault example, a registry might be a ledger providing a record of the money stored within the vault. In the context of services and SOA, a registry is used to store metadata about repository items. The metadata could include information about the repository items, and be used for classification and categorization of services. Both registries and repositories can store schemas and WSDLs.

Although JAXR does not allow direct connection to a repository, it assumes that the repository always has an associated registry that enables access to repository items, in addition to holding item-related information. The JAXR model provides extensibility via a provider model that allows access to different types or classes of registries. The JAXR specification provides access to UDDI, ebXML, XML, and SPI registries. The Electronic Business using XML (ebXML) is a set of OASIS specifications defining common standards to facilitate business-to-business interactions via the Internet. The ebXML standards relating to registries are the ebXML Registry Services and Protocols (RS) and Registry Information Model (RIM).

The RS specification defines a set of interfaces used to access an ebXML registry implemented as SOAP/HTTP Web services, while RIM defines a standard metadata model used to describe the entities contained in the registry and their relationships. The UDDI specification similarly defines a different set of interfaces implemented as SOAP/HTTP Web services that provide access to a UDDI directory. The JAXR providers for ebXML registries and UDDI directories use the respective Web services to access the registry.

The ebXML RIM specification has greater relevance beyond the use of ebXML registries, since the JAXR information model is based on the model defined within the specification. The JAXR specification defines a detailed mapping between its own information model and those defined respectively by ebXML and UDDI. The JAXR information model classifies registry objects according to taxonomies defined either externally or as part of the JAXR provider.

The JAXR API follows a style that is consistent with other APIs used to access external enterprise systems from Java. Parameters defining the connection to the registry are encapsulated in a ConnectionFactory object that is typically retrieved via a JNDI lookup and used to establish a connection. Once a connection is established, JAXR provides methods for searching the registry (using a SQL-like syntax), navigating associations between objects, and managing the lifecycle of objects.

6.2 Java Implementations of WS-* Standards

Let’s explore how the following basic WS-* extensions are handled within JAX-WS and other core Java Web Services specifications.

Addressing – Project Metro is one of the most prominent Web services stacks in the Java platform, including a WS-Addressing implementation as part of the core technologies. The Metro Web services stack is bundled with the Java EE 5, 6, and 7 reference implementations and in the GlassFish application server.

MTOM – Axis2 and JAX-WS reference implementations support the MTOM, which is used to achieve interoperable implementation of SOAP attachments well supported by non-Java Web Services implementations.

Reliable Messaging – The WS-ReliableMessaging specification is supported in the WSIT project that provides support for reliability, security, and transactions. Apache also provides an open-source implementation of the 2005 pre-OASIS WS-ReliableMessaging specification with the Sandesha project. The Sandesha 2 project provides WS-ReliableMessaging support for Axis2 and for the OASIS WS-ReliableMessaging 1.1 specification.

Transactionality – The WSIT project supports WS-Coordination and WS-AtomicTransaction. Axis2 support for WS-Coordination and WS-AtomicTransaction is provided by Apache Kandula 2.

Security – The XML and Web Services Security (XWSS) project, also part of Project Metro, supports various WS-Security standards, such as the Username Token Profile, X509 Token Profile, and SAML Token Profile. In addition, Project Metro implements WS-Trust, WS-SecureConversation, and WS-SecurityPolicy. Within the Apache Web services stack, Axis2 includes WS-Security support through a module provided by the Rampart project, which is based on the WSS4J implementation of WS-Security. The module provides support for Username tokens, X.509 certificates, and SAML tokens.

Advanced Web Services Standards and Frameworks

The following sections briefly describe notable industry standards and frameworks relevant to Java support of WS-* standards.

Service Component Architecture

Service Component Architecture (SCA) and the associated Service Data Objects (SDO) specification were conceived and informally incubated by major software vendors including IBM, Oracle, and SAP, with a number of additional vendors joining as the specifications matured. Although subsequent attempts to drive standardization/adoption through OASIS have proven unsuccessful, SCA remains relevant with implementations included within vendor products such as IBM and BPM, and provided by Apache in the form of the Tuscany project.

SCA describes a model for the assembly of services implemented using different technologies, with an invocation framework providing support for locating and invoking services at runtime. SDO provides a standard means of manipulating language-agnostic data structures within service-based applications in a uniform manner.

The SCA model is based on the approach of assembling service components that can be implemented and exposed in a variety of different ways. The service components are exposed using logical interfaces that define input and output parameters without being tied to any particular implementation or transport mechanism. Where one service component must call another, a reference is created on the caller to the interface (described by a WSDL portType or Java interface) on the target service. The services and references are wired together, and the wiring model is captured in a Service Component Definition Language (SCDL) file. Services can be assembled in this way into modules exposed to the outside world via imports and exports that define the technology details of the interface, such as identifying SOAP or POX, and the transport mechanism used.

In addition to defining a model for the assembly/wiring of services, SCA provides an invocation framework used at runtime to determine the location of service endpoints invoked using the most appropriate mechanism, which is based on qualifiers defined at assembly time. If reliable, asynchronous qualifiers are specified at assembly time, the invocation framework will invoke the service endpoint using reliable JMS messaging at runtime. The invocation framework has awareness of the deployment topology of service components, and handles aspects, such as workload balancing, across multiple service endpoint instances where horizontal scaling is used.

The SDO specification provides a standard API and programming model for manipulating data within service components. SDO can be extended with Data Access Service (DAS) that binds to different data stores, such as relational databases and SOAP messages. The SDO specification provides static and dynamic programming models with similar advantages and disadvantages to JAX-WS and JAX-RPC static/dynamic proxies. The dynamic API allows SDOs to be manipulated at runtime even if specifications of the data structure were unavailable at development time, although this involves more programming effort than the static model.

Spring-WS

Spring-WS is based on the popular Spring framework, which led many of the innovations in enterprise Java computing formalized later in Java EE 5, 6, and 7. The Spring-WS framework supports top-down or contract-first development. Creating WSDLs from scratch is unnecessary, as WSDLs can be generated from schemas and other conventions.

Spring-WS provides a framework that runs in a Java SE or Java EE environment, and handles dispatching Web service messages to Web service endpoints by passing an XML message. Implementing a Web service with Spring-WS involves extending an abstract class defined by the framework. Directly coding to the JAX-RPC or JAX-WS APIs is unnecessary. A variety of different Object-to-XML mapping tools can be used to map XML messages to Objects, or directly navigate to the message tree using the SAAJ API.

6.3 JAX-RS

The JSR 311 for Java API for RESTful Web services (JAX-RS) 2.0 specification is HTTP-centric and aims to be Java EE container-independent. Like any JSR, a reference implementation of the specification under the codename Jersey is available. Jersey provides value-added features on top of the JAX-RS API to support Atom integration with the Spring framework and diverse resource representation formats, such as JSON and MIME Multipart. Like JAX-WS, the JAX-RS 2.0 specification relies on annotations to specify URI mappings, HTTP headers, content types, and resources.

The specific goals stated in the JAX-RS specifications are:

POJO-Based – enabling use of simple Java objects through annotations and associated classes/interfaces

HTTP-Centric – leveraging HTTP and the tenets introduced in Chapter 5, such as HTTP methods, headers, and URI

Format Independence – supporting multiple content types or MIME types

Container Independence – running JAX-RS artifacts in many different Web-tier containers

Inclusion in Java EE – defining the environment for a Web resource class hosted in a Java EE container, to specify how to use Java EE features and components within the Web resource class

Implementing JAX-RS

The JAX-RS API implements a Web resource class or annotated POJO with methods that respond to various HTTP operations. Based on the annotations, the JAX-RS runtime determines how to dispatch various HTTP operations to methods exposed on the class and how to choose appropriate format representations for both read and write operations on resources. The JAX-RS runtime leverages annotations to extract URL-related information, such as path information, query parameters, header values, and cookies, to populate method parameters or resource attributes with these values. The use of annotations eliminates the need for low-level HTTP plumbing code.

Let’s consider a REST service that is exposing a list of customers as a resource and the details of an individual customer in Example 6.4.

import javax.ws.rs.*;
...
@Path("/customers/")
public class CustomerResource {
  @Get
  @Produces("application/xml")
  public String getCustomers()
  //return an empty list of customers, for now return "<customers/>";
  }
}


Example 6.4

The top-level JAX-RS package is javax.ws.rs, as highlighted in Example 6.4. To better understand the JAX-RS API implementation, annotations within the listing are defined as follows:

• The javax.ws.rs.Path annotation identifies the URL path for which the CustomerResource class will serve requests. The URL path is in relation to the base URL of the server. The context root of the application and URL pattern to which the JAX-RS implementation servlet is mapped is http://server/services/customers. The @Path annotation can be applied at the resource class level or at an individual method level where it acts in relation to the base URL specified at the class level. The getCustomers method responds to the same @Path URL pattern specified at the class level.

• The javax.ws.rs.GET annotation is a request method designator indicating the getCustomer method will respond to HTTP GET requests. The JAX-RS runtime delegates an HTTP GET request for URL http://server/services/customers to the getCustomers method.

• The javax.ws.rs.Produces annotation indicates the MIME types of resource representation returned to the service consumer are an XML payload. The getCustomers method returns a string, so the @Produces annotation is necessary to tell JAX-RS what the content type of the returned HTTP response will be, such as "application/xml".

An individual customer record often includes a unique identifier that can be used to retrieve further customer details, as seen in Example 6.5.

...
@GET
@Path("{id}")
@Produces("application/xml")
public String getCustomerById(
  @PathParam("id") Long id){
  return "<customer><name>" + "John Doe</name></customer>";
}


Example 6.5

The javax.ws.rs.PathParam annotation binds a URI template parameter to a resource method parameter, resource class field, or resource class bean property. In Example 6.5, a URI template parameter /customers/{nnnn} is bound to a resource method parameter "id" by the JAX-RS runtime. JAX-RS manages the type conversion between the string in the URI template parameter and the method parameter data type.

The @Produces annotation can be changed to return a JSON-based customer representation, as highlighted in Example 6.6.

@Produces("application/json")
public String getCustomerById(
  @PathParam("id") Long id){
  return "{"name":"John Doe"}";
}


Example 6.6

Returning an XML or a JSON representation to the caller is the same through a change in the @Produces("application/xml", "application/json") annotation. The caller in Example 6.7 can indicate preference for one format over the other by specifying an appropriate accept parameter field in the request, such as a quality factor q.

GET services/customers/1234 HTTP/1.1
Accept: application/xml; q=0.8,application/json


Example 6.7

The q factor value ranges from 0 to 1, with the default value set to 1 for highest priority. A value of 0.8 means the service consumer prefers application/json but will accept application/xml if application/json is not available. To restrict the search criteria for a collection of resources, the criteria can be specified in a query parameter. For example, to retrieve a list of customers whose last names match a certain value, the service consumers can issue the GET request GET services/customers?lastname=perlman.

Like URI path parameters, JAX-RS supports the extraction of query parameters from the URL, binding them to various resource attributes like method parameters, resource class fields, and resource bean properties. In Example 6.8, the parameter lastname would be populated with the value of the query parameter.

@Get
@Produces("application/xml")
public String getCustomersByLastName(
  @QueryParam("lastname") String lastName){
  ...
}


Example 6.8

JAX-RS facilitates the mapping of GET operations. The creation of new customers using the REST method, specifically the HTTP POST request, is shown in Example 6.9.

import javax.ws.rs.core.Response;
@POST
@Consumes("application/xml")
@Produces("application/xml")
public Response createCustomer(
  Customer cust){
    // create customer in the system
    Customer customer = createCustomer(cust);
    return Response.ok(customer).build();
}


Example 6.9

The javax.ws.rs.POSTannotation is a request method designator indicating the createCustomer method will respond to HTTP POST requests. In Example 6.9, the JAX-RS runtime delegates an HTTP POST request for a URL, such as http://server/services/customers, to the createCustomer method. Note the URL path for the creation is the same as the root resource path.

The @Consumes annotation indicates the MIME types of representation that the methods of a resource class can accept from the service consumer. An @Consumes annotation specified at the method level overrides one set at the class level. If a resource is unable to support the MIME type sent in the request data, the JAX-RS runtime returns an HTTP 415 Unsupported Media Type error.

The javax.ws.rs.core.Response class encapsulates any HTTP response metadata that the application chooses to provide. In this case, the Customer entity, a JAXB object, is returned in the response without any metadata. JAX-RS unmarshals HTTP request data into Java object types and Java objects to the appropriate HTTP response bodies. The operations for updating and deleting a customer can be mapped to HTTP PUT and DELETE methods, as seen in the code fragment in Example 6.10.

@Put
@Path("id")
@Consumes("application/xml")
public void updateCustomer(
  @PathParam("id") Long id, Customer cust){
  //...update customer
}
@DELETE
@Path("id")
public void removeCustomer(
  @PathParam("id") Long id){
    //...update customer
}


Example 6.10

Both PUT and DELETE methods can specify a URI template parameter to identify the customer for an update or delete operation. As with the GET operation, the URI template parameter is mapped to the resource method parameters. The updateCustomer method relies on the JAX-RS runtime to unmarshal the customer XML in the HTTP request body to the JAXB object in the resource method parameter.

Implementing REST Services

Although no clear consensus about the need for a formalized REST service contract exists, WADL attempts to establish a format for formalized REST service contracts. The Customer Listing service presented in Example 6.5 can be described using WADL. For simplicity, assume that all representations from the service in Example 6.11 are described as XML.

<?xml version="1.0"?>
<application xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://wadl.dev.java.net/2009/02 wadl.xsd"
  xmlns:tns="http://server/services/service1"
  xmlns:xsd="http:// www.w3.org/2001/XMLSchema"
  xmlns:cst="http://server/schemas/"
  xmlns:customer="http://www.mycompany.com/schema/customers"
  xmlns="http://wadl.dev.java.net/2009/02">
  <grammars>
    <include href="Customer.xsd"/>
  </grammars>
  <resources base="http://server/services/CustomerListing/v1">
    <resource path="all">
      <method href="#listing">
    </resource>
    <resource path="{id}">
      <method href="#customer">
    </resource>
  </resources>
  <method name="GET" id="listing">
    <request/>
    <response>
      <representation mediaType="application/xml"
        element="cst: customers"/>
    </response>
  </method>
  <method name="GET" id="customer">
    <request/>
    <response>
      <representation mediaType="application/xml"
        element="cst: customer"/>
      </response>
  </method>
</application>


Example 6.11

The WSDL document outlines the message template Customer.xsd using XML schema, sets up the base URI for the service, and describes the two resource paths all and {id}. The resource path all maps to the relative URI /CustomerListing/v1/all, which retrieves all customers and the resource path specified via a URI path template. The resource path {id} maps to /CustomerListing/v1/{id}, which responds with the customer’s details and identifier id.

Code generation tools generate stubs from a WADL. Notable tools include the plain wadl-cmdline, the Ant-based wadl-ant, and Maven-based wadl-maven-plugin utilities. An XSL style sheet is available on the WADL site to create a more human-readable WADL document. The open-source community also offers tools that consume the WADL document and produce stubs or help visually inspect the WADL document.

Scalability

REST offers scalability through simple abstraction and indirection, support for caching, addressability, statelessness, and replication of resources. Before looking at how these ideas can be applied to the sample Customer Listing service, this section introduces several Web features that contribute to scalability.

Statelessness

Individual HTTP requests are independent of one another and do not maintain conversational state information from any previous HTTP requests. HTTP is stateless by design, meaning REST services that are exposed over HTTP are also stateless by default unless specifically designed to be state-aware. Given any service consumer application, if the application state is maintained by the service consumer, the REST service deals only with the resource states and not the application state. Statelessness enables the REST service to be hosted on several different servers without replicating application state while still providing the same functionality to the service consumer. Resources can be replicated across a farm of servers. Web traffic interceptors, such as load balancers, can be used to distribute traffic to hosts without having to consider which server last served requests for the resource.

Uniform Contract

Supporting the HTTP methods GET, PUT, POST, HEAD, and DELETE and uniformly implementing the semantics for each of the methods across all of the REST services makes creating and supporting new types of service consumers possible. For example, a browser application accesses any Web site serving static HTML pages. Since all Web sites support the uniform interface of GET and POST in the same way, browsers do not have to change to render new Web sites that emerge daily. Similarly, new browsers can access Web pages through the exact same interface. As long as all new services (Webpages) satisfy the uniform interface with consistent semantics, such as how GET is idempotent and safe while PUT is idempotent, new types of services can be offered and additional service consumers can be introduced without changing either the services or the service consumers.

Cacheability

HTTP specification provides specific headers (Expires, Cache-Control, Etag, and Last-Modified) and guidance for caching resources at the service consumer end or in between the service and service consumer. The primary cacheable operations are GET and HEAD, since they are read-only. The intermediaries, such as proxy servers in use with traditional Web sites, can be used to support the caching on the server side for resources accessed using GET or HEAD. In addition, most of the standard HTTP library frameworks in various programming languages support caching on the service consumer side.

Addressability

The ability to have a unique address for each of the resources, and the inter-connections between resources, simplifies the partitioning of resources across hosts while maintaining a way to reach the resource. Partitioning is essential to scalability.

Due to the dynamic nature of customers, the main resource being added, the customer list is dynamic and cannot be cached. However, the customer profile can be cached as it seldom changes within a day. In addition, inter-connections exist between customers who are related or from same family. The design of the REST service is stateless and only supports GET and HEAD operations, since updates are not allowed. With these constraints, caching resources in an intermediary like a caching proxy server or at the service consumer end itself is possible.

Intermediaries are load balancers and caching proxies. Partitioning the primary entry point for the Customer Listing service /customers and subsequent calls to individual customers /{id} on to two sets of service farms with multiple hosts takes advantage of the statelessness and addressability characteristics. Depending on the anticipated load and frequency, the resulting layout can be expanded across data centers. The addressability and inter-connectedness facilitates seamless service operation in spite of the resources being physically spread across hosts.

For example, two service consumers can make calls at various times. A caching proxy determines if the resource must be cached, based on the Cache-Control field in the response header from the service. When the first caller makes a new request, the proxy checks its cache, finds no data in the cache, and forwards the request to the service. The response from the service has a directive to cache this resource for up to 10 hours or 36,000 seconds. When a second service consumer makes the request to the proxy server for the same customer profile, the proxy responds with the cached customer data.

Alternatively, the first service consumer accesses the list of all customers and the proxy forwards to the service. The service responds with the customer list and the Cache-Control field set to no-cache in the response header. Any subsequent calls on the customer list will be forwarded to the service by the proxy, as the service directive for caching was not to cache the customer list.

Security

Authentication and encryption are primary considerations in the securing of services, which must ensure that the resource is inaccessible to unentitled service consumers and that the confidentiality of the data is not compromised. In order to satisfy a variety of service consumers, the service can support several types of user credential formats to perform authentication and support message and transport-level encryption.

In terms of authentication, the HTTP standard specifies basic access authorization and digest authorization as the primary schemes of using the Authorization request header to be sent when the service consumer invokes the service. Both schemes use the same request and response headers to carry information, whether it is the credential payload or an indication of what scheme to use.

When a service consumer requests a protected resource without proper credentials, the server responds with a 401 Unauthorized response code with an appropriate value in the WWW-Authenticate HTTP response header. The service consumer can then construct the appropriate credentials as desired by the service to gain access to the resource. The HTTP standard uses the status code 401 in situations where no credentials are sent with the request or the wrong credentials are sent.

A WWW-Authenticate response header sent to the service consumer can indicate that the basic authorization scheme is being used. Digest is another value that can be used in the WWW-Authenticate header, followed by the realm and additional information about the digest.

HTTP basic authentication is Base64-encoded and unencrypted. If the basic authentication scheme is used between the service consumer and service over HTTP, the credentials can be compromised if a malicious third party is monitoring traffic. A simple mechanism to overcome third-party monitoring is to use secure HTTP (HTTPS) and encrypt the communication channel between service consumer and service. Using the HTTP digest authentication scheme is another way to ensure data security.

The digest scheme uses a random string that changes on every request, in addition to a sequence number and the service consumer’s username/password to authenticate the request. Due to the challenge mechanism of including a random string with a username/password known only to the service consumer, the service consumer’s identity is preserved. However, the service consumer is then required to follow the HTTP specification in forming the proper digest token, along with necessary metadata to send to the service to be authenticated.

The HTTP standard allows extension of the standard authentication-related headers to accomplish specialized forms of authentication. By extending the standard, the service breaks the simplicity of REST principles and must provide additional information about the custom authentication scheme. The HTTP specification provides guidance on how to satisfy a requirement to use a custom scheme due to enterprise or other non-functional requirements.

Two means of achieving data confidentiality protection include encrypting the entire message content or portions of the message and the channel of communication between service and service consumer. Either Secure Sockets Layer (SSL) or Transport-Level Security (TSL) is used to encrypt the channel, such as HTTPS, but the message is susceptible once received at the endpoint.

Message-level encryption ensures security even after the message has been delivered to the recipient. The message payload, which is the request to the service or response from the service, can be encrypted either in full or in part. REST and SOAP-based Web services treat XML payloads similarly in that both use the XML Encryption specification. As the encryption mechanism grows in complexity, SOAP-based Web services have WS-Security and related specifications that address various aspects of how to deliver a robust message layer encryption implementation.

WS-Security specifications define how to associate security tokens with messages, reference encrypted XML elements, embed credentials used for decryption in the message headers, and embed other related metadata in the SOAP header. REST services have no clear guidelines or specifications available to provide a similar infrastructure. There are no standardized message-level encryption solutions for non-XML payloads. A JSON representation, for example, is left to the discretion of the developer building the service in terms of how to specify encryption parameters, encryption keys, and algorithms.

Security with REST services does not address the enterprise QoS concerns solved by WS-Security and its related standards.

REST Service Support

Three other aspects of significance to the discussion on REST-related quality of service include reliable messaging, transaction, and asynchronous messaging support.

Reliable messaging transport ensures parties involved in the communication can send and receive messages with a degree of confidence which can be quantified as the number of times and order in which the messages will be delivered. Messages can be delivered at most once, at least once, and only once. An additional delivery guarantee can require messages to be delivered to the receiver in exactly the order they were sent from the sender.

The concept of reliable messaging was introduced in message queuing systems with no equivalent available in the REST-style architecture. Message guarantees can be satisfied by building additional infrastructure on top of the standard HTTP frameworks to accommodate retry, sequencing, and failure-handling logic. However, doing so would require maintaining application state. Relaxation of the statelessness constraint violates REST-style architecture principles and negates the advantages provided by this architecture. Transaction support illustrates what can be achieved by leveraging standard HTTP.

Transaction support in REST services is achieved with HTTP methods. If the REST service is designed following HTTP standards, then most of the HTTP methods, excluding POST, are idempotent. The GET, PUT, DELETE, and HEAD methods can be used more than once and obtain the same result as the first time. If PUT is used to update a customer, the service consumer can call multiple PUT operations and be updated with the same information.

Idempotent REST service invocations alleviate the need for guaranteed delivery with a retry mechanism. An eventually successful method invocation retry will ensure that messages are delivered without any unintended side effects. The retry mechanism does not ensure the ordering of messages, which must still be implemented at the application level if necessary as REST does not provide any solutions for maintaining message order. Reliable HTTP (HTTP-R) is another standard used to address transaction support, although its coverage is beyond the scope of this book.

Since transaction support requires the maintenance of session state and adherence to a set of standard protocols to ensure that the properties of atomicity, consistency, isolation, and durability (ACID) are not violated, there is no viable way to accomplish transaction support in REST services without violating the REST statelessness and cache constraints. Interesting examples of how to use an overloaded POST method to handle the coordination of transactions for REST services can be found online, although they are largely exploratory in nature. Utilizing SOAP-based Web services and the WS-AtomicTransaction or WS-BusinessActivity standards is preferable if there is a need to support distributed transactions spanning multiple systems within the enterprise.

Supporting asynchronous communications is challenging because of the synchronous nature of HEAD, GET, and PUT can be used to create new resources, such as an invocation status and polling the resource, to simulate publish/subscribe, broadcast, and one-way message exchange scenarios. These message exchange scenarios can still be accomplished using the synchronous HTTP protocol. Additional constraints must be placed on the MEPs and associated status codes to accomplish asynchronous communication over HTTP, which require custom engineering effort and a deviation from the standards.

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

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