Andre Tost

Andre Tost

Biography

Andre Tost works as a Senior Technical Staff Member and Software Architect in IBM’s Software Group. He is currently helping to develop and evolve the new PureApplication System cloud platform. Previously, Andre spent 10 years as an SOA consultant for IBM, leading large SOA transformation projects with clients worldwide. His specific focus was on SOA governance and middleware integration using enterprise service bus technology. Andre has co-authored several technical books and has published many articles on SOA and related topics. He is also a frequent conference speaker. Originally from Germany, he now works and lives in Rochester, Minnesota. He likes to watch, coach and play soccer whenever his busy schedule allows. Andre has a degree in Electrical Engineering from Berufsakademie Stuttgart, Germany.

Contributions

rss  subscribe to this author

Thomas Erl

Thomas Erl

Biography

Thomas Erl is a best-selling IT author and founder of Arcitura™ Education Inc. Thomas has been the world's top-selling service technology author for over seven years and is the series editor of the Prentice Hall Service Technology Series from Thomas Erl (www.servicetechbooks.com ). With more than 300,000 copies in print worldwide, his books have become international bestsellers and have been formally endorsed by senior members of major IT organizations, such as IBM, Microsoft, Oracle, Intel, Accenture, IEEE, HL7, MITRE, SAP, CISCO, HP, and many others.

Several of his books, including Cloud Computing Design Patterns, Cloud Computing: Concepts, Technology & Architecture, SOA Design Patterns, SOA Principles of Service Design, and SOA Governance, were authored in collaboration with the IT community and have contributed to the definition of cloud computing technology mechanisms, the service-oriented architectural model and service-orientation as a distinct paradigm. His more recent title, Service-Oriented Architecture: Analysis & Design for Services and Microservices, formally positions and introduces new patterns for the Microservice architectural model as part of SOA.

As CEO of Arcitura™ Education Inc. and in cooperation with SOA School, Cloud School and Big Data Science School, Thomas has led the development of curricula for the internationally recognized SOA Certified Professional (SOACP), Cloud Certified Professional (CCP) and Big Data Science Certified Professional (BDSCP) accreditation programs, which have established a series of formal, vendor-neutral industry certifications obtained by thousands of IT professionals around the world.

Thomas is the founding member of the SOA Manifesto Working Group and author of the Annotated SOA Manifesto (www.soa-manifesto.com). For 10 years, he was the editor of The Service Technology Magazine, and he further oversees the SOAPatterns.org, CloudPatterns.org and BigDataPatterns.org initiatives, which are dedicated to the on-going development of master pattern catalogs for service-oriented architecture, cloud computing and Big Data.

Thomas has toured more than 20 countries as a speaker and instructor, and regularly participates in international conferences. More than 100 articles and interviews by Thomas have been published in numerous publications, including The Wall Street Journal and CIO Magazine.

Philip Thomas

Philip Thomas

Biography

Phil Thomas is an IT Architect in IBM’s Software Group. During his time in the technology sector, he has worked across industries and geographies with a range of organizations as a consultant on technology strategy and on the architecture, design, and implementation of a broad variety of solutions. His expertise spans a number of areas including Java/JEE, SOA, transaction processing systems, messaging/integration middleware, business process management, information management systems, and business analytics. He currently specializes in Big Data and analytics, based out of the UK. Prior to joining IBM in 2000, Phil trained as a physicist and holds a Ph.D. in experimental high-temperature superconductivity awarded by the University of Birmingham.

Contributions

rss  subscribe to this author

Satadru Roy

Satadru Roy

Biography

Satadru Roy is a Technology Architect who has worked for several Fortune 500 companies in the manufacturing, automobile, and telecommunications industries.

He also worked as a Consultant and Product Engineer at one of the leading Java application server vendors, BEA Systems, Inc.

Satadru has extensive background in CORBA, Java, JEE, and Web services technologies. His main interests and areas of specialization are middleware and integration technologies (such as TP monitors, integration brokers, workflow engines, etc.).

Satadru is also a strong believer in the potential of open source in the Java world and is keenly following recent open source SOA initiatives, such as Apache Synapse.

Satadru holds a Master's Degree in Engineering from the Indian Institute of Science.

Contributions

rss  subscribe to this author

Bookmarks



Building Standardized Service Contracts with Java Published: August 1, 2014 • Service Technology Magazine Issue LXXXV PDF

The following is an excerpt from the new book "SOA with Java: Realizing Service-Orientation with Java Technologies". For more information about this book, visit www.servicetechbooks.com/java.

A foundational criterion in service-orientation is that a service have a well-defined and standardized contract. When building Web services with SOAP and WS-*, portable machine-readable service contracts are mandatory between different platforms as WSDL documents and associated XML schema artifacts describing the service data model. The finite set of widely used HTTP verbs for REST services form an implicit service contract. However, describing the entity representations for capture in a portable and machine-independent format is the same as SOAP and WS-*.

For REST services, capturing and communicating various aspects of resources can be necessary, such as the set of resources, relationships between resources, HTTP verbs allowed on resources, and supported resource representation formats. Standards, such as WADL, can be used to satisfy the mandatory requirements. Having a standards-based service contract exist separate from the service logic, with service data entities described in a platform-neutral and technology-neutral format, constitutes a service by common definition. Even the self-describing contract of HTTP verbs for a REST service establishes a standards-based service contract. Recall the standards used for service contracts, such as WSDL/WADL and XML Schema, from Chapter 5.

Top-Down vs. Bottom-Up

Ensuring that services are business-aligned and not strictly IT-driven is necessary when identifying services for a service portfolio in an SOA. Services are derived from a decomposition of a company's core business processes and a collection of key business entities. For a top-down approach, services are identified and interfaces are designed by creating appropriate schema artifacts to model either the operating data and WSDL-based service contracts, or model REST resources and resource methods. The completed service interface is implemented in code.

However, enterprises can have irreplaceable mission-critical applications in place. Therefore, another aspect of finding services is assessing existing applications and components to be refactored as services for a bottom-up approach. This includes creating standard service contracts, such as WSDL definitions or REST resource models, for the existing components.

Tooling provides support for both approaches in a Java world. For SOAP-based Web services, tools play a more prominent role than in Java-based REST services. JAX-WS defines the wsimport tool, which takes an existing WSDL definition as input to generate Java skeletons. These skeletons can be used as the starting point for implementing the actual service logic. Similarly, the wsgen tool generates WSDL from existing Java code. The mapping between WSDL/XML schema and Java is an important function associated with the wsimport tool.

Machine-readable contracts are also necessary for REST services. JAX-RS, if WADL is not used, starts with a resource model to implement the resources in Java. Consider the contract as a logical collection of the resource model, with the supported resource methods, resource representations, and any hyperlinks embedded in the representations allowing navigability between resources. If WADL is used, tools like wadl2java can generate code artifacts. Initiatives exist to help generate WADL from annotated JAX-RS classes for a bottom-up approach, although these recent developments can have limited usefulness.

Some SOA projects will employ both a bottom-up and a top-down approach to identify and design services and service contracts, which often results in a meet-in-the-middle approach. Service definitions and Java interfaces are tuned and adjusted until a good match is found.

Sometimes an XML schema definition developed as part of the service design cannot map well into Java code. Conversely, existing Java code may not easily map into an XML schema. Java code that does not precisely map to a service interface designed as part of a top-down approach can exist. In this case, the Service Façade pattern can be applied to insert a thin service wrapper to satisfy the service interface and adapt incoming and outgoing data to the format supported by the existing Java code.

Mapping Between Java and WSDL

WSDL is the dominant method of expressing the contract of a Java component. While typically related to Web services, the language can also be utilized for other types of services. Formalization and standardization of the relationship between Java and WSDL has made this possible, such as the work completed on the JAX-RPC standard.

The JAX-RPC standard initially defined basic tasks, such as "a service portType is mapped to a Java interface" and "an operation is mapped to a method." However, formalizing allows the definitions described in the JAX-RPC standard to define how an existing Java component (a class or interface) can generate a WSDL definition, and vice versa. Consequently, most contemporary Java IDEs support generating one from the other without requiring any manual work.

JAX-WS, the successor standard for JAX-RPC, builds on top of its predecessor's definitions and delegates all the issues of mapping between Java and XML to the JAXB specification (as discussed in Chapter 6). These sections serve to highlight some of the issues raised when creating standard service contracts from Java or creating Java skeletons from existing service contracts. The majority of the details explained in the next section apply specifically to Web services.

Wrapped Document/Literal Contracts

The WSDL standard identifies a variety of styles for transmitting information between a service consumer and service. Most of the styles are specific for the chosen message and network protocol, and specified in a section of the WSDL definition called the binding. A common binding found in a WSDL definition uses SOAP as the message protocol and HTTP as the network transport. Assume that SOAP/HTTP is the protocol used for the services presented as examples.

The portType is a binding-neutral part of a service definition in WSDL that describes the messages that travel in and out of a service. Reusable across multiple protocols, the portType is not bound to the use of a Web service. Any service, even if invoked locally, can be described by a WSDL portType, which allows service interfaces to be defined in a language-neutral fashion regardless of whether the service logic will be implemented in Java or another language.

As discussed in Chapter 5, the WSDL binding information defines the message format and protocol details for Web services. For SOAP-based bindings, two key attributes known as the encoding style and the invocation style determine how messages are encoded and how services are invoked.

The wrapped document/literal style supported by default in all Java environments for services dictates that an exchange should be literal. Literal means that no encoding happens in the message, so the payload of the message is a literal instantiation of the schema descriptions in the element of the WSDL. The invocation style is document. Document means that the runtime environment should generate a direct copy of the input and output messages as defined in the portType and not just an arbitrary part of the message. Wrapped means that the payload of the message includes a wrapper element with the same name as the operation invoked.

In order to understand how the WSDL standard relates to Java, let's review Example 7.11 to expose the following class as a service and create a standardized contract.

package pack;
import javax.jws.*;
@WebService
public class Echo {
public String echo(String msg) {
return msg;
}
}

Example 7.11

Using the wrapped document/literal style implements a wrapper element called "echo" after the echo() method in the public class. Echo is included in the XML schema associated with this service. An excerpt in the resulting schema is provided in Example 7.12.

...
<xs:element name="echo">
<xs:complexType>
<xs:sequence>
<xs:element name="arg0" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>
...

Example 7.12

Wrapping a message in one additional element named after the operation is prevalent and the default in any commonly used tool. Note that naming the global element after the operation is common practice and not required by the specification.

Implicit and Explicit Headers

Transferring information as part of the <Header> portion of the SOAP message, to be added to the WSDL definition, is another important part of the binding information for SOAP. This section discusses how to bind the information with explicit, implicit, or no headers.

Explicit Headers

Header data is part of the messages referenced in the portType of the service, which is often called an explicit header. The header definition in the SOAP binding refers to a message part either included in the input message or the output message of an operation.

In Example 7.13, assume an Echo service takes a string as input and returns that string as the response. A timestamp must also be added into the header of the SOAP request message, indicating the time at which the request was sent.

<definitions targetNamespace="http://pack/" name="EchoService"
xmlns:tns="http://pack/" xmlns:xs="http://www.w3.org/2001/
XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns="http://schemas.xmlsoap.org/wsdl/">
<types>
<xs:schema targetNamespace="http://pack/">
<xs:element name="echo">
<xs:complexType>
<xs:sequence>
<xs:element name="arg0" type="xs:string"
minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="echoResponse">
<xs:complexType>
<xs:sequence>
<xs:element name="return" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="timestamp" type="xs:dateTime"/>
</xs:schema>
</types>
<message name="echo">
<part name="parameters" element="tns:echo"/>
<part name="timestamp" element="tns:timestamp"/>
</message>
<message name="echoResponse">
<part name="parameters" element="tns:echoResponse"/>
</message>
<portType name="Echo">
<operation name="echo">
<input message="tns:echo"/>
<output message="tns:echoResponse"/>
</operation>
</portType>
<binding name="EchoPortBinding" type="tns:Echo">
<soap:binding transport="http://schemas.xmlsoap.org/ soap/http"
style="document"/>
<operation name="echo">
<soap:operation soapAction=""/>
<input>
<soap:body parts="parameters" use="literal"/>
<soap:header message="tns:echo" part="timestamp"
use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
</operation>
</binding>
...
</definitions>

Example 7.13 - The Echo service WSDL definition with an explicit header contains a timestamp.

Example 7.13 contains an extract of the respective WSDL definition for an Echo service that shows:

  • an additional element in the schema, called "timestamp" of type xs:dateTime
  • an additional part in the input message definition, which refers to the timestamp element
  • an additional definition for the header in the SOAP binding, which indicates that the timestamp element should be carried in the SOAP header of the request message

The header binding shown in Example 7.14 refers to a part also included in the portType of the service, the input message, and the Java service interface generated by the JAX-WS wsimport tool. Note that the import statements are left out.

@WebService(name = "Echo", targetNamespace = "http://pack/")
@SOAPBinding(parameterStyle = ParameterStyle.BARE)
public interface Echo {
@WebMethod
@WebResult(name = "echoResponse", targetNamespace = "http://pack/",
partName = "parameters")
public EchoResponse echo(
@WebParam(name = "echo", targetNamespace = "http://pack/",
partName = "parameters")
Echo_Type parameters,
@WebParam(name = "timestamp", targetNamespace = "http://pack/",
header = true, partName = "timestamp")
XMLGregorianCalendar timestamp);
}

Example 7.14

The service interface includes a parameter for the explicit header and indicates two parameters: one that contains the string wrapped into the Echo_Type class and another that carries the timestamp element. Note that nothing in the interface indicates that the timestamp will go into the SOAP header, as this information is only contained in the WSDL definition.

Implicit Headers

Assume that the header data is not part of the portType but instead uses a message part unused in any input or output message, known as an implicit header. The header information is not included in the portType of the service or in the Java interface. Example 7.15 shows that the WSDL for the Echo service has been changed to include an explicit header.

<definitions targetNamespace="http://pack/" name="EchoService"
xmlns:tns="http://pack/" xmlns:xs="http://www.w3.org/2001/
XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns="http://schemas.xmlsoap.org/wsdl/">
... (this part is as before) ...
<message name="echo">
<part name="parameters" element="tns:echo"/>
</message>
<message name="echoResponse">
<part name="parameters" element="tns:echoResponse"/>
</message>
<message name="header">
<part name="timestamp" element="tns:timestamp"/>
</message>
<portType name="Echo">
<operation name="echo">
<input message="tns:echo"/>
<output message="tns:echoResponse"/>
</operation>
</portType>
<binding name="EchoPortBinding" type="tns:Echo">
<soap:binding transport="http://schemas.xmlsoap.org/ soap/http"
style="document"/>
<operation name="echo">
<soap:operation soapAction=""/>
<input>
<soap:body parts="parameters" use="literal"/>
<soap:header message="tns:header" part="timestamp"
use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
</operation>
</binding>
...
</definitions>

Example 7.15 - A WSDL definition contains an implicit header for an Echo service.

The WSDL definition presented in Example 7.15 is not that much different from Example 7.13, with a separate message defined for the header. The separate message has a significant impact on the Java interface seen in Example 7.16, where the import statements have been omitted again.

@WebService(name = "Echo", targetNamespace = "http://pack/")
public interface Echo {
@WebMethod
@WebResult(targetNamespace = "")
@RequestWrapper(localName = "echo",
targetNamespace = "http://pack/", className = "pack.Echo_Type")
@ResponseWrapper(localName = "echoResponse",
targetNamespace = "http://pack/", className = "pack.EchoResponse")
public String echo(
@WebParam(name = "arg0", targetNamespace = "")
String arg0);
}

Example 7.16 - The service interface does not include the implicit header.

The interface in Example 7.16 takes a simple string parameter, and does not refer to the timestamp element or use the Echo_Type class to wrap the input message. The implicit header definition requires extra work on the service implementer by the service client developer to ensure the appropriate header information is inserted into the message. The implicit header definition cannot simply be passed to the service proxy as a parameter. In both cases, JAX-WS handlers can be leveraged to process the SOAP header, or intermediaries inserted between service consumer and service can manage all header information, such as part of an ESB.

The header portion of a service message should only contain contextual information, omitting any business connotation. The implementations of the service consumer and the service should only deal with business logic and not with infrastructure-level information. The use of implicit headers is common, although extra code to generate and process the headers must be written.

No Headers

A final option is to put no header information in the WSDL definition, which can appear to leave the contract incomplete but is actually preferable. Headers typically contain information independent from the business payload being exchanged between services. Recall a timestamp that had been inserted into the SOAP message presented in Examples 7.13 and 7.15. Inserting a timestamp might be a defined company policy across all services, and a common method for doing so can be established. Adding this detail to each WSDL definition is not required and creates an unnecessary dependency between the business-relevant service contract and technical cross-service policy.

Data Mapping with REST

XML schemas can be used to represent service data elements, with JAXB and JAX-WS generating the mapped Java classes and Web service artifacts for SOAP-style Web service implementations. For REST services, the JAX-RS service implementations are similar. When the convenience of code generation is needed, JAXB annotated POJOs can be used as the service entities in JAX-RS resource classes. Behind the scenes, the JAX-RS runtime will marshal the Java objects to the appropriate MIME-type representations for the entities, such as application/xml. A customer object annotated with JAXB annotations is shown in Example 7.17.

@XmlRootElement(name="customer")
@XmlAccessorType(XmlAccessType.FIELD)
public class Customer {
private int id;
private String name;
public Customer() {}
//...other attributes omitted
//...getters and setters for id and name
//...
}

Example 7.17

The resource methods in the JAX-RS implementation that produce or consume customer information in the form of XML can be seen in Example 7.18.

//...retrieve customer and return xml representation
@Get
@Path("id")
@Produces("application/xml")
public Customer getCustomer(
@PathParam("id") Long id){
Customer cust = findCustomer(id);
return cust;
}
//...create customer with an xml input
@POST
@Consumes("application/xml")
public void createCustomer(
Customer cust){
//...create customer in the system
Customer customer = createCustomer(cust);
//...
}

Example 7.18

The JAX-RS implementation automatically handles the marshaling and unmarshaling of the XML-based resource representation to and from JAXB objects. Generic types, such as a javax.xml.transform.Source, can be handled in the resource class to keep the resource class independent of any specific types defined in the domain, such as a customer type. However, extra work is required to handle the extraction of the customer information from the Source object seen in Example 7.19.

@PUT
@Path("id")
@Consumes("application/xml")
public void updateCustomer(@PathParam("id") Long id,
javax.xml.transform.Source cust) {
// do all the hard work to
// extract customer info in
// extractCustomer()
updateCustomer(id, extractCustomer(cust));
}

Example 7.19

JAX-RS supports alternate MIME types, such as JSON. Just as JAXB handles the binding of XML to and from Java objects, numerous frameworks exist that handle mapping JSON representations to Java objects and vice versa. Some commonly used frameworks for mapping between JSON and Java are MOXy, Jackson, and Jettison.

In the Jersey implementation of JAX-RS 2.0, the default mechanism for binding JSON data to Java objects leverages the MOXy framework. When the Jersey runtime is configured to use MOXy, the runtime will automatically perform binding between Java objects (POJOs or JAXB-based) and a JSON representation. Jackson or Jettison can also perform similar binding with appropriate runtime configuration. A low-level JSON parsing approach can be achieved with the newly introduced JSON-P API (Java API for JSON Processing) in Java EE 7. JSON-P should not be confused with JSONP (JSON with Padding), which is a JavaScript communication technique used to avoid certain types of browser restrictions.

Conversion Between JSON and POJOs

Given the same customer representation as illustrated in Example 7.20, no special code is required to handle an incoming JSON document or return a JSON-based representation.

//...
@GET
@Path("id")
@Produces("application/json")
public Customer getCustomer(
@PathParam("id") Long id){
return findCustomer(id);
}

Example 7.20

The returned customer representation would be a JSON string, such as {"name":"John Doe","id":"1234" ... }.

The same JAXB objects can be used for handling JSON media types that would normally be used for XML representation. The addition of another MIME type in the

@Produces can be seen in Example 7.21.

@GET
@Path("id")
@Produces("application/json", "application/xml")
public Customer getCustomer(
//...

Example 7.21

The JAX-RS runtime returns an appropriate representation (XML or JSON) that is determined by the client's preference. In spite of the convenience offered by JSON binding frameworks like MOXy or Jackson, greater control over the processing of the JSON input and output can be a requirement, as opposed to letting the JAX-RS runtime perform an automatic binding between JSON and Java objects.

For example, REST service operations must consume or produce only selective parts of large JSON documents, as converting the whole JSON document to a complete Java object graph can cause significant resource overheads. In such cases, a JSON parsing mechanism based on a streaming approach can be more suitable. JSON-P APIs allow a developer complete control over how JSON documents are processed. JSON-P supports two programming models, the JSON-P object model and the JSON-P streaming model.

The JSON-P object model creates a tree of Java objects representing a JSON document. The JsonObject class offers methods to add objects, arrays, and other primitive attributes to build a JSON document, while a JsonValue class allows attributes to be extracted from the Java object representing the JSON document. Despite the advantage of convenience, processing large documents with the object model can create substantial memory overheads, as maintaining a large tree of Java objects imposes significant demands on the Java heap memory. This API is similar to the Java DOM API for XML parsing (javax.xml.parsers.DocumentBuilder).

In comparison, the JSON-P streaming model uses an event parser that reads or writes JSON data one element at a time. The JsonParser can read a JSON document as a stream containing a sequence of events, offer hooks for intercepting events, and perform appropriate actions. The streaming model helps avoid reading the entire document into memory and offers substantial performance benefits. The API is similar to the StAX Iterator APIs for processing XML documents in a streaming fashion (javax.xml.stream.XMLEventReader). The JsonGenerator class is used to write JSON documents in a streaming fashion similar to javax.xml.stream.XMLEventWriter in StAX API.

JSON-P does not offer binding between JSON and Java. Frameworks, such as MOXy or Jackson, are similar to JAXB in how they will need to be leveraged to perform conversion between Java objects and JSON.

Case Study Example

SmartCredit launches an aggressive expansion campaign with the intention of offering premium credit cards with cashback offers to high-value customer prospects across a retail chain's locations. After signing an agreement with the retail chain, SmartCredit obtains prospect data from all the retail stores containing prospect names, e-mail addresses, and net transaction values at the end of every month. An internal Prospect Analyzer application will process the data to target prospects with high monthly transaction values and send out e-mails with new premium credit card offers.

The retail chain's IT department sends customer data to SmartCredit in large JSON documents containing prospect information. However, the SmartCredit Prospect Analyzer service is only interested in prospects that spend in excess of 2,000 dollars during the month. A fragment of a typical monthly JSON extract from the retail stores is provided in Example 7.22.

"txnsummary":{
"date":"2014-01-31T23:30:00-0800",
"store":"Fashion Trends #132",
"txn": [
{
"type":"cash",
"amount":235.50,
"e-mail":null
},
{
"type":"credit",
"amount":3565.00,
"e-mail":"jane@doe.com"
}
]}

Example 7.22

SmartCredit IT accepts the prospect and transaction data through an HTTP POST from the retail stores at the end of every month. A REST API that consumes this JSON data and extracts the prospects for marketing campaigns is built. After reviewing the size of the monthly feed, a SmartCredit architect quickly realizes that memory limitations will prevent a typical JSON-Java binding approach from working for

such large payloads. In addition, SmartCredit is only interested in processing selective parts of the payload, such as credit card transactions with amounts greater than 2,000 dollars.

Converting the entire JSON data into Java objects is a waste of time, memory, and resources. The JSON-P streaming API is a suitable option for allowing selective processing of only the data sections meeting the given criteria. A simplified version of the final resource class is illustrated in Example 7.23.

import javax.ws.rs.Consumes;
import javax.ws.rs.Path;
import javax.ws.rs.POST;
import javax.ws.rs.core.MediaType;
import java.io.Reader;
import javax.json.Json;
import javax.json.streaming.JsonParser;
import javax.json.streaming.JsonParser.Event
@Path("upload")
@Consumes(MediaType.APPLICATION_JSON)
public class ProspectFilteringResource {
private final double THRESHOLD = 2000.00;
@POST
public void filter(final Reader transactions) {
JsonParser parser = Json.createParser(transactions);
Event event = null;
while(parser.hasNext()) {
event = parser.next();
if(event == Event.KEY_NAME&&"type".equals(parser.getString()))
{
event = parser.next(); //advance to Event.VALUE_STRING for
the actual value of "type"
if("credit".equals(parser.getString()) {
parser.next(); //Event.KEY_NAME for "amount"
event = parser.next(); //Event.VALUE_NUMBER for amount
value
if(parser.getBigDecimal().doubleValue() > THRESHOLD) {
parser.next(); //advance to Event.KEY_NAME for "e-mail"
parser.next(); //advance to Event.VALUE_STRING for
e-mail info
String e-mail = parser.getString();
addToCampaignList(e-mail);
}
}
}
}
}
private void addToCampaignList(String e-mail) {
// actual logic of adding e-mail to campaign list
}
}

Example 7.23 - The JSON-P streaming API can parse a large JSON document selectively.

The code uses the streaming API to advance the parser to consume only specific events and avoids reading the entire JSON data structure into memory, which would have been the case using the standard JSON-Java binding approach. One drawback to the JSON-P approach is the cumbersome maneuvering of the event stream in the application code, although such trade-offs are often necessary in real-world usage.

Binary Data in Web Services

Candidates looking to utilize a service-oriented solution often require the transfer of large amounts of data kept in some binary format, such as a JPEG image file. The Java language offers support for handling binary data in its JavaBeans Activation Framework (JAF) as well as classes and interfaces in other packages, which depend on the format. For example, the java.awt.Image class hierarchy supports image formats, such as JPEG. The JAXB specification defines how to map certain Java types to XML schema, such as the mapping of a java.awt.Image type to base64Binary.

Binary formats without a special Java type associated can use the javax.activation.DataHandler class defined in JAF. However, byte[] is the most generic way of representing binary data in Java. JAXB defines that a byte[] is mapped to base64Binary and hexBinary.

When generating a WSDL contract from a Java interface, binary data types are mapped using JAXB mapping rules. Generating the reverse is not as straightforward. An XML schema element of type base64Binary can map into multiple different Java types. By default, byte[] is used. Indicating that an element declared as base64Binary in the schema should be mapped to java.awt.Image in the Java service implementation can be performed in a number of ways. Binary data can be transferred in a SOAP message or inline, which means binary data is encoded into text and sent like any other data in the message.

Transferring the data inline maintains interoperability between different vendor environments, but is ineffective when dealing with large pieces of binary data, such as a CAD drawing of an airplane. The text encoding increases the size of the message by an average of 25%. The MTOM is an alternative to text encoding, which describes how parts of a message can be transferred in separate parts of a MIME-encoded multipart message. The binary content is removed from the SOAP payload, given a MIME type, and transferred separately.

JAXB provides support for MTOM, which must be explicitly enabled for the JAX-WS runtime. JAX-WS plugs into this support when building and parsing messages with attachments. An element definition can be annotated in an XML schema document with two specific attributes indicating which MIME type to give the element. When using MTOM, the contentType and expectedContentTypes attributes demonstrate how to MIME-encode the element and determine which Java type the element is mapped to in the Java service interface.

Nothing in the schema or in any of the Java code indicates whether the binary data is transferred as an attachment using MTOM or inserted directly into the SOAP envelope. In JAX-WS, distinguishing the difference is defined either by a setting on the service configuration file or programmatically. The following case study example illustrates a SOAP-based Web service managing attachments via MTOM.

Case Study Example

NovoBank offers a remote method of opening an account from its Web site for customers to download a form, fill it out, and mail or fax it to a branch office. Alternatively, customers can fill out the form in branch and provide the completed form to a bank employee. The forms are scanned in at the branch office for further processing by NovoBank's back-end system before being archived.

To reduce processing time, the bank wants to offer customers and employees a Web application that accepts an uploaded binary image of the form to send to the bank. Internally, the Open Account service uses a Web service that takes the binary image as a parameter. To simplify the implementation of the associated service logic in Java, the service contract uses the expectedContentType attribute in its schema to indicate that the scanned image is formatted as a JPEG document. The resulting WSDL definition is shown in Example 7.24 with parts of the WSDL document omitted for brevity.

<definitions targetNamespace= "http://personalbanking.services.
novobank.com/" name="AccountService"
xmlns:tns="http://personal banking.services.novobank.com/"
xmlns:xsd="http://www.w3.org/ 2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns=http://schemas.xmlsoap.org/wsdl/
xmlns:xmime="http://www.w3.org/2005/05/xmlmime">
<types>
<xsd:schema>
<xs:element name="openAccount" type="ns1:openAccount"
xmlns:ns1="http://personalbanking.services.novobank.com/"/>
<xsd:complexType name="openAccount">
<xsd:sequence>
<xsd:element name="arg0" type="xsd:base64Binary"
xmime:expectedContetTypes="image/jpeg" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
...
</xsd:schema>
</types>
<message name="openAccount">
<part name="parameters" element="tns:openAccount"/>
</message>
<message name="openAccountResponse">
<part name="parameters" element="tns:openAccountResponse"/>
</message>
<portType name="Account">
<operation name="openAccount">
<input message="tns:openAccount"/>
<output message="tns:openAccountResponse"/>
</operation>
</portType>
</definitions>

Example 7.24 - The WSDL for NovoBank's Open Account service with an MTOM content type definition will now accept the JPEG format.

An element of type base64Binary will be mapped to a byte[] in the Java interface. However, the additional annotation of the parameter element, using the expectedContentTypes attribute, leads to the following Java interface presented in Example 7.25.

package com.novobank.services.personalbanking;
import java.awt.Image;
// other imports omitted
@WebService(name = "Account", targetNamespace = "http://
personalbanking.services.novobank.com/")
public interface Account {
@WebMethod
@WebResult(targetNamespace = "")
@RequestWrapper(localName = "openAccount",
targetNamespace = "http://personalbanking.services.novobank.
com/", className = "com.novobank.services.personalbanking.
OpenAccount")
@ResponseWrapper(localName = "openAccountResponse",
targetNamespace = "http://personalbanking.services.novobank.
com/", className = "com.novobank.services.personal banking.
OpenAccountResponse")
public String openAccount(
@WebParam(name = "arg0", targetNamespace = "")
Image arg0);
}

Example 7.25 - The content type is mapped to the appropriate Java type in the service interface.

Note how the parameter passed to the service implementation is mapped to the java.awt.Image type. Defining whether MTOM is used to transfer the form image as an attachment can be performed programmatically using JAX-WS, or in the client or the endpoint configuration for the service endpoint. A sample client for the new Open Account service is shown in Example 7.26.

package com.novobank.services.personalbanking.client;
import java.awt.Image;
import java.awt.Toolkit;
import javax.xml.ws.BindingProvider;
import javax.xml.ws.soap.SOAPBinding;
public class AccountServiceClient {
public static void main(String[] args) {
Image image = Toolkit.getDefaultToolkit().getImage("c:\\temp\\
java.jpg");
Account serviceProxy = new AccountService(). getAccountPort();
SOAPBinding binding = (SOAPBinding)((BindingProvider)
serviceProxy).getBinding();
binding.setMTOMEnabled(true);
String accountNumber = serviceProxy.openAccount(image);
System.out.println("returned account number is
"+accountNumber);
}
}

Example 7.26 - A Java client enables MTOM transport.

After deploying the service and running the test client listed in Example 7.26, the SOAP message sent can be reviewed by executing the client in Example 7.27.

POST /attachment/account HTTP/1.1
Content-Length: 13897
SOAPAction: ""
Content-Type: Multipart/Related; type="application/xop+xml"; boundary="----=_Part_0_14949315.1177991007796"; start-info="text/xml"
Accept: text/xml, application/xop+xml, text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
User-Agent: Java/1.5.0_11
Host: 127.0.0.1:8081
Connection: keep-alive

------=_Part_0_14949315.1177991007796
Content-Type: application/xop+xml; type="text/xml"; charset=utf-8
<?xml version="1.0" ?><soapenv:Envelope xmlns:soapenv=http://schemas.xmlsoap.org/soap/envelope/ xmlns:xsd=http://www.w3.org/2001/XMLSchema xmlns:ns1="http://personalbanking.services.novobank.com/">/"><soapenv:Body><ns1:openAccount><arg0><xop:Include xmlns:xop="http://www.w3.org/2004/08/xop/include" href="cid:f17b4f2b-db2c-4bc5-96d1-2d4857aaa5b8@example.jaxws.sun.com"></xop:Include></arg0></ns1:openAccount></soapenv:Body></soapenv:Envelope>

------=_Part_0_14949315.1177991007796
Content-Type: application/octet-stream
Content-ID: <f17b4f2b-db2c-4bc5-96d1-2d4857aaa5b8@example.jaxws.sun.com>
Content-transfer-encoding: binary_KýÝ_ÔF-¡úÞr*îÉu1_)Š1áñ}K²£Ñ\êKQZ_Ý4Ï¡É)*G'~ªohBïýfÙÈï¦zùì£_Ö(Ö &_Èõmâoå¨\Ó\( ò¹åq€°Ê _W¶èÁh";_ÐÚ'z0"ç5WÃ"_üv|DÜî7IÚù_é6³ÈÚ1lëÉäl›BîöWÈ"ý|›i"ì™Åã]ÓÉÝ9ƒ_"7Üý¶j9{ßáÉ?w(_"86‹ü£Ã_'?_:Ž§òÔŠvM¦éÈë4_ŸÊ"=ƒÑ]™EýÕ×Ès˜Hýå÷©?7‹â""¨r{‹â³¯
Rè<...RשÔ]z_íμÙ4_ÿBîùš_?ÿPé3ê
... the rest of the data omitted ...

------=_Part_0_14949315.1177991007796--

Example 7.27 - A SOAP message with an MTOM-compliant binary part

The request message is divided into the SOAP message, including reference to the binary data, and the binary data sent as an attachment. The message can be handled more efficiently and does not impact the processing of the remaining XML information. Again, whether the data is sent as an attachment or not is not defined in the service contract (the WSDL definition).

Binary Data in REST Services

JAX-RS supports the conversion of resource representations into Java types, such as byte[] or java.io.InputStream, in resource methods. To produce or consume binary data from resource methods, JAX-RS runtime handles the conversion through a number of built-in content handlers that map MIME-type representations to byte[], java.io.InputStream, and java.io.File. If binary content must be handled as a raw stream of bytes in a resource method, the corresponding resource method is seen in Example 7.28.

@Get
@Produces("image/jpg")
public byte[] getPhoto() {
java.io.Image img = getImage();
return new java.io.File(img);
}
@Post
@Consumes("application/octet-stream")
public void processFile(byte[] bytes) {
//...process raw bytes
}

Example 7.28

The java.io.File type can help process large binary content in a resource method, such as an attachment containing medical images, as seen in Example 7.29.

@POST
@Consumes("image/*")
public void processImage(File file) {
//...process image file
}

Example 7.29

The JAX-RS runtime streams the contents to a temporary file on the disk to avoid storing the entire content in memory. For complete control over content handling, JAX-RS offers several low-level utilities which can be useful for custom marshaling/unmarshaling of various content types. The javax.ws.rs.ext.MessageBodyReader and javax.ws.rs.ext.MessageBodyWriter interfaces can be implemented by developers to convert streams to Java types and vice versa.

Back-and-forth conversion is useful when mapping custom MIME types to the domain-specific Java types. The classes that handle the mapping are annotated with the @Provider annotation and generically referred to as JAX-RS entity providers. Entity providers are used by the JAX-RS runtime to perform custom mapping.

A special case of javax.ws.rs.ext.MessageBodyWriter is the javax.ws.rs.core.StreamingOutput callback interface, which is a wrapper around a java.io.OutputStream. JAX-RS does not allow direct writes to an OutputStream. The callback interface exposes a write method allowing developers to customize the streaming of the response entity. Example 7.30 demonstrates the gzip format used to compress a response entity.

import javax.ws.rs.core.StreamingOutput;
...
@GET
@Produces("application/gzip-compressed")
public StreamingOutput getCompressedEntity() {
NOTE
Indicate the MIME type through an appropriate @Produces annotation, such as a JPG image, so that the runtime can set the right content-type for the returned resource representation.
return new StreamingOutput() {
public void write(OutputStream out)
throws IOException, WebApplicationException {
try {
...
GZipOutputStream gz =
new GZipOutputStream(out);
//...get array of bytes
// to write to zipped stream
byte[] buf = getBytes();
gz.write(buf, 0, buf.length);
gz.finish();
gz.close();
...
} catch(Exception e) { ... }
}
};
}

Example 7.30

For mixed content containing both text and binary payload, entity providers can be used to perform custom marshaling, while multipart MIME representations are suitable for dealing with mixed payloads. JAX-RS standards do not mandate support for handling mixed MIME multipart content types apart from multipart FORM data (multipart/form-data), which is useful for HTML FORM posts but has limited use in a system-to-system interaction context. Various JAX-RS implementations, such as Jersey and RESTEasy, provide support for mixed multipart data. Handling mixed content with binary data is common, as seen in the following case study example for SmartCredit's Submit Credit Application service.

Case Study Example

SmartCredit is building a REST service known as the Submit Credit Application service that is intended for service consumers to submit credit card applications. Apart from basic information such as customer details, the supporting information in the form of various collaterals, such as mortgage papers and loan approvals, must be scanned as images and attached to the application.

The SmartCredit application development team considered using Base64 encoding, but moved onto other alternatives after realizing a substantial size bloat would result. The development team decides on the mixed multipart representation for the application data. The multipart application data will have the customer information in an XML format as the first part, and a series of images in the subsequent parts.

A sample multipart application request over HTTP is shown in Example 7.31.

POST /creditapps/ HTTP/1.1
Host: smartcredit.com
Content-Type: multipart/mixed; boundary=xyzw
--xyzw
Content-Id: <abcdefgh-1>
Content-Type: application/xml
<customer>
<name>John Doe</name>
<Address>...</Address>
...
--xyzw
Content-Id: <abcdefgh-2>
Content-Type: image/jpg
...
&_Èõmâoå¨\Ó\( ò¹åq °Ê _W¶èÁh";_ÐÚ'z0"ç5WÃ"_üv|DÜî7IÚù_é6³ÈÚ1lëÉäl›BîöWÈ"ý|›i"ì™Åã]ÓÉÝ9ƒ_"7Üý¶j9{ßáÉ?w(_"86‹ü£Ã_'?_:Ž§òÔŠvM¦éÈë4_ŸÊ"=ƒÑ]™EýÕ×Ès˜Hý...rest of the binary data goes here
--xyzw—

Example 7.31

The SmartCredit service development team considered using a custom JAX-RS Entity Provider to handle the mixed multipart data, but realized the reference JAX-RS implementation Jersey already provides support for mixed multipart data through an add-on called jersey-media-multipart. The key classes leveraged in this implementation include:

The org.glassfish.jersey.media.multipart.BodyPartEntity represents the entity of a part when a MIME Multipart entity is received and parsed.

The org.glassfish.jersey.media.multipart.BodyPart is a mutable model representing a body part nested inside a MIME Multipart entity.

The resource class method that handles the submitted application can be seen in Example 7.32.

import org.glassfish.jersey.media.multipart.MultiPart;
import org.glassfish.jersey.media.multipart.BodyPart;
import org.glassfish.jersey.media.multipart.BodyPartEntity;
import javax.ws.rs.core.Response;
...
import com.smartcredit.domain.Customer;
...
@Path("/creditapps")
public class CreditAppResource {
@POST
@Consumes("multipart/mixed")
public Response post(MultiPart multiPart) {
// First part contains a Customer object
Customer customer =
multiPart.getBodyParts().get(0).
getEntityAs(Customer.class);
// process customer information
processCustomer(customer);
// get the second part which is a scanned image
BodyPartEntity bpe =
(BodyPartEntity) multiPart.getBodyParts().
get(1).getEntity();
try {
InputStream source = bpe.getInputStream();
//process scanned image
}
// Similarly, process other images in the multipart
// content, if any...
//If everything was fine, return Response 200
return Response.status(Response.Status.OK).build();
//else if there were errors...
return Response.status(Response.Status.BAD_REQUEST).
build();
}

Example 7.32

In the code fragment, the @Consumes annotation indicates that a resource representation of multipart/mixed is expected. In this case, the payload contains customer data in XML and one or more scanned images. The following Jersey utilities perform different steps in managing the mixed multipart data:

  • com.sun.jersey.multipart.MultiPart.getBodyParts() returns a list of com.sun.jersey.multipart.BodyParts.
  • BodyPart.getEntityAs(Class<T> cls) returns the entity converted to the passed-in class type.
  • com.smartcredit.domain.Customer is a regular JAXB-annotated Java class. Since the first entity in the multipart message is known to be the customer entity, the BodyPart.getEntityAs(Customer.class) method is used to unmarshal the XML entity body into a JAXB customer object.
  • BodyPart.getEntity() returns the entity object to be unmarshaled from a request. The entity object is known to be a BodyPartEntity and is cast accordingly.
  • BodyPartEntity.getInputStream() returns the raw contents, which in this case are the contents of the scanned image.

  • Note that by using the MIME multipart utilities in Jersey, the development team is able to avoid writing much of the plumbing code that would otherwise be necessary to deal with multipart MIME messages.

Use of Industry Standards

The use of industry standards in developing service contracts builds on the IT-specific standards and seldom offers challenges when using Java as the language and runtime environment. Many industries have established data formats that ensure interoperability between business partners, suppliers, and between systems within an enterprise, such as the ACORD standard for insurance, HL7 for the healthcare industry, or SWIFT for banking.

Used primarily to exchange information between companies or independent units within an enterprise, industry standards are prime candidates for use as part of the service contract. Industry standards are generally expressed as XML schema definitions, which can be directly referenced in a service contract or serve as the basis for a specific schema.

Before the advent of JAXB 2.0 which supports the full set of XML schema constructs, a common issue was the inability to map all of the elements used in an industry schema into Java because such mapping was not defined. JAXB 2.x nearly resolves this issue, but cases still occur where a large and complex industry standard schema cannot be handled by a data binding tool like JAXB. Using an industry standard unchanged in a service contract can be tedious and lead to the generation of hundreds of Java classes mapping all of the complex types defined in the schema.