Chapter 9. Data representation and transformation

This chapter covers

  • Describing and representing data in various ways
  • Explaining requirements for data representations
  • Transforming data without application coding

Handling of data in a service-oriented environment can be challenging. Data has to travel over the network between service providers and consumers, and this data exchange may be implemented using different technologies. In this chapter we’ll explain how data can be represented, where data transformation is needed, and how Tuscany handles this in order to preserve the flexibility of SCA-enabled applications.

We’ll use the credit card payment example from the TuscanySCATours scenario to demonstrate how collaborating business services deal with data exchange. The example can be found in the code at the following locations:

  • contributions/payment-java
  • contributions/creditcard-payment-sdo
  • contributions/databinding-client
  • launchers/databinding

As illustrated in figure 9.1, there are two related business components: Payment and CreditCardPayment. In this case, the Payment component takes credit card information submitted directly by the customer over the internet. When payment is made via a credit card, the Payment component talks to the CreditCardPayment component to authorize the charge. Two developers, Bob and Mary, are responsible for getting these two components to work together. Bob is going to implement the Payment service while Mary develops the CreditCardPayment service.

Figure 9.1. The Payment and CreditCardPayment components that Bob and Mary are working on

In the next sections, we’ll follow Bob and Mary and learn how they assemble the Payment and CreditCardPayment components.

We’ll start by looking at how a service interface is used to describe what data will flow between a component reference and a component service. Then we’ll look at how the data described in the service interface can be represented and accessed within the running component implementation. We’ll use JAXB and SDO as examples of Java data representations.

 

JAXB

JAXB (Java Architecture for XML Binding) is defined by JSR 222 (http://jcp.org/en/jsr/detail?id=222). It provides a convenient way to process XML content using Java objects by binding its XML schema to Java representation. At the time of writing, Tuscany uses the JAXB version 2.1.7 implementation from Sun.

 

 

SDO

SDO (Service Data Objects) is designed to simplify and unify the way in which applications handle data. Using SDO, application programmers can uniformly access and manipulate data from heterogeneous data sources, including relational databases, XML data sources, web services, and enterprise information systems (http://www.osoa.org/display/Main/Service+Data+Objects+Specifications). At the time of writing, Tuscany uses its own version 1.1.1 implementation of SDO.

 

SCA allows interface contracts between references and services to be specified and controlled in a number of ways, so we’ll look at that next before finally moving on to look at why data transformations are important and how the Tuscany SCA databinding framework can perform many data transformations automatically without requiring explicit code in the component implementation.

9.1. Data exchange between SCA components

In this first section we’ll follow Bob and Mary as they describe the interface for the CreditCardPayment component service. As you build and describe your components in SCA, one of the most important things that you’ll do in terms of controlling the way that data is represented is to describe the component service interfaces. Service interfaces are often referred to as contracts, and we’ll use both terms here. You’ll see in this section that Bob and Mary choose WSDL 1.1 as a common, standard, and interoperable interface description language. The WSDL interface they describe is referenced directly from the composite file that describes their application.

The first thing Bob and Mary do is agree on what information should be exchanged between the Payment and CreditCardPayment components. In our example, the Payment component will provide the CreditCardPayment component with detailed information about the credit card and the amount of charge. The CreditCardPayment component will then respond with the status of the card transaction. With some help from the business analysts, Bob and Mary find out that the authorize operation should exchange the following information about a credit card transaction, shown in table 9.1.

Table 9.1. An informal description of the data exchange required for the CreditCardPayment component authorize operation

Operation: authorize

Data description

Input Credit card detail: Credit card type: MasterCard, Visa, Amex, Discover Credit card number Expiration month and year Credit card verification code Card owner Name Address Street City State Zip Code Home phone Amount of charge
Output Status of the card transaction

The description of the business operation becomes a contract to bind the Payment component as a service consumer to the CreditCardPayment component as the service provider. Table 9.1 defines the necessary parts of the input/output data that Bob and Mary agreed to. This information will ensure that the CreditCardPayment component has the data required to authorize credit card charges requested by the Payment component.

To formally describe the business functions and data exchange requirements, Bob and Mary now need to define a business interface for the CreditCardPayment component. SCA supports several ways to define service interfaces, such as Java interfaces, WSDL 1.1 port type, WSDL 2.0 interface, or CORBA IDL. They all have constructs to define the operations as well as the data structures and types.

9.1.1. Using WSDL to describe the CreditCardPayment interface

Interoperability across different systems is important to Mary and Bob, so they choose to use WSDL 1.1 and XML Schema 1.0 to define the CreditCardPayment interface and the CreditCardDetails data type. WSDL 1.1 is a W3C standard and is in common use, so it meets their requirement for interoperability.

 

Interface/data decoupling

Using a programming language–neutral interface definition such as WSDL/XSD promotes loose coupling between the service consumer and provider. This happens because the data exchange is document oriented and programming language independent. By contrast, component interfaces that expose programming language–specific forms of data (for example, Java) promote tight coupling, because this usually forces the use of the same programming language on each side of the interface.

 

Listing 9.1 shows the WSDL definition that describes the CreditCardPayment interface and its authorize operation. This WSDL could have been written by hand, or it could have been generated using your favorite WSDL tool such as the WSDL editor from the Eclipse Web Tools Platform (WTP) project.

Listing 9.1. The WSDL definition for the CreditCardPayment service interface

If you look toward the top of the WSDL document in listing 9.1, you’ll see a WSDL <wsdl:types> element, which contains a set of the XML schema types. These schema types describe the structure of the data flowing in and out of the authorize operation. The authorize operation itself is defined by a WSDL <wsdl:operation name="authorize"> element within the WSDL <wsdl:portType name="CreditCardPayment">. You can also see that WSDL <wsdl:message> elements referenced by the authorize operation map the schema types to the input and output messages of the operation.

Figure 9.2 shows a graphical visualization of the XML schema types contained in the <wsdl:types> section of the WSDL document. It matches the informal description of the data Bob and Mary collected in table 9.1.

Figure 9.2. Visualization of the XML schema definition for CreditCardDetailsType

As you can see from the XML schema in listing 9.1 and from its visual representation in figure 9.2, the data required to describe the customer’s credit card comprises several nested levels of data fields. In order to access and manipulate this data within a component implementation, you’ll need a suitable data structure.

It’s often the case when describing component service interfaces that you create the WSDL definition containing a portType, use the WSDL as part of the component description in your composite file, and then use the WSDL to generate data structures for use in your business logic. This is often called a top-down approach. You’re starting from abstract WSDL and using it to generate the concrete interfaces and structures used in your component implementation.

Alternatively, it may be the case that you’re starting from a component implementation, for example, a Java class that implements a Java interface. In this case the Java interface is supported by SCA, and you may not need to worry about WSDL at all. This often happens if you’re implementing all of your components using Java. If WSDL is required, because you want to present your service interfaces to remote clients that require it, then the Tuscany runtime can generate the WSDL for you based on your component description. If you have a component service that uses binding.ws, you can generate a WSDL description of the component service by pointing your browser at the service endpoint URL with ?wsdl added to the end, for example, http://somehost:8080/MyComponentService?wsdl.

In this chapter we’ll be taking the top-down approach and defining the WSDL to start with because it helps us show how different data formats can be used. You’ll see in section 9.2 how the data structures can be generated from the WSDL and used in the component implementation. Before we get to building the component, let’s see how Bob and Mary use the WSDL interface description in an SCA composite file.

9.1.2. Using WSDL in an SCA composite

Bob and Mary have now reached an agreement on how to exchange data between Payment and CreditCardPayment components, and a WSDL file has been constructed describing the contract. If they were to build an SCA composite file now to describe the wiring between the two components, it would look something like the following composite file.

Listing 9.2. Using WSDL interfaces in component references and services

In the Payment component creditCardPayment reference definition, the <binding. ws> element (see chapter 7 for the syntax) references the WSDL service port . The Tuscany binding.ws implementation is able to read the WSDL document and extract enough information about the target interface and its network location to make the call to the CreditCardPayment component.

In the CreditCardPayment component CreditCardPayment service definition, a slightly different approach is taken. The WSDL document is referenced in the <interface.wsdl> element by QName of the portType , and the <binding.ws> element is configured manually with the URI of the endpoint that’s to be exposed by the service. The WSDL service and binding will be generated using SOAP document literal style.

Why does SCA support these two different approaches? The WSDL document is a generic mechanism for describing service interfaces and isn’t always bound directly to the Web Services binding. So when defining the CreditCardPayment service on the CreditCardPayment component, we could have used another type of binding, for example, binding.jms, but still use interface.wsdl to allow the WSDL document to describe the structure of the service interface. For those of you familiar with Web Services, it may seem a little odd that WSDL can be used with anything other than SOAP/ HTTP Web Services. WSDL does a good job in describing the shape of an interface independently of its binding, so it does work well in this situation.

You may be wondering how the Tuscany SCA runtime is able to find the WSDL file when this composite file references the WSDL elements such as port type or service only by XML qualified name and not by physical location. Remember that the Tuscany runtime reads contributions, which contain composite files, Java classes, and WSDL files, among other things. When Tuscany first reads the contribution, it indexes all the artifacts it finds. Hence, the application developer doesn’t need to provide the physical location of the WSDL file. As long as the WSDL file is included in the contribution, Tuscany can find it automatically.

Now that Bob and Mary have described the contract between their two components, using WSDL, they’ll implement the business logic using SCA Java components. Bob must create the PaymentImpl class and Mary must create the CreditCardPaymentImpl class, and they must each choose a data representation technology. Even though WSDL is used to formally define the data exchange between the two components over the Web Services protocol, it isn’t natural to work from WSDL and XSD when writing Java programs. It’s much more convenient to have Java classes that represent the data structures.

Bob and Mary will map the WSDL form of the service interface into a Java interface. The resulting interface will represent operation parameters and return values using Java types. These types are the in-memory representation of the data being exchanged between components. Let’s now look at the Java-based technologies Bob and Mary chose to represent the data.

9.2. Representing data within component implementations

Data needs to have an in-memory representation so that component implementation logic can access and manipulate it. It’s natural that the component developer will choose an appropriate representation of the business interface’s business data to facilitate data processing. We’ll first look at how Bob exploits JAXB to interact with a reference to the CreditCardPayment component. Then we’ll look at how Mary uses SDO to implement the CreditCardPayment authorize operation.

Although Bob and Mary have chosen Java technology to represent the credit card data in their component implementations, the SCA Web Services binding, binding.ws, needs to handle the data and marshal and unmarshal it to and from SOAP envelopes that pass over HTTP. The Tuscany implementation of the Web Services binding is based on technology from the Apache Axis2 project (http://ws.apache.org/axis2/). The Web Services binding interface receives and produces data in the form of Axis AXIOM objects.

 

AXIOM

AXIOM stands for Axis Object Model (also known as OM, or Object Model) and refers to the XML Infoset model that was initially developed for Apache Axis2. For more information, please see http://ws.apache.org/commons/axiom/.

 

Figure 9.3 gives an overview of the different data representations involved in the various parts of our simple scenario for the purpose of illustrating data exchange in a typical composite application. The data is represented as JAXB objects at the Payment component reference. It’s then converted into an Axiom XML model so that the Axis2 stack behind the Web Services binding can send it out in a SOAP message. On the wire, the data is an XML document inside a SOAP envelope. At the service ends, the reverse happens; the data is read into an AXIOM model and then is converted into SDO objects before being passed to the CreditCardPayment service.

Figure 9.3. As a message passes from component reference to component service, its data is represented in several different formats depending on whether the message is in the component, in the binding, or being passed on the wire.

You’ll see later on how the Tuscany runtime arranges for the data to be transformed between these various formats. First though, let’s look at how Bob and Mary deal with the data in their component implementations.

9.2.1. Passing data to component references using JAXB objects

Remember that Bob is implementing the Payment component that references the CreditCardPayment component. Bob is a Java developer, and he wants to implement the payment service in Java. To talk to the CreditCardPayment service, which we know is described using a WSDL port type, Bob prefers to have a Java interface, which is compatible with the WSDL port type. Furthermore, there are many different ways to represent the CreditCardDetails data type in Java, for example:

  • Raw data, such as byte[], String, InputStream, or Reader
  • XML parsing technologies, such as DOM, SAX events, StAX
  • Java/XML binding technologies, such as JavaBeans, JAXB, SDO (generated static SDO classes or dynamic DataObject), AXIOM

Bob has a few requirements in mind for the data representation:

  • Strong-typed access for the business information through methods such as getAddress()
  • Can be used to produce XML documents
  • Can be used to hold request data from the web frontend

To talk to a web service using Java, Bob needs to create an interface with methods that map to the set of WSDL operations. He also needs to have Java classes to represent the data types defined by the XML schema. Bob could write the plain Java classes by hand, but some of the WSDL and XSD information such as the namespace and element names would be lost. As a result, the Java classes can’t be mapped to WSDL precisely.

To simplify Java programming with Web Services without dealing with the complexity of WSDL and XSD, the SCA specification recommends JAX-WS to map the WSDL interface into a Java interface. Bob adopts JAX-WS and also chooses JAXB as the representation of XML data. Both JAX-WS and JAXB use Java annotations to customize Java classes with the complete metadata from the WSDL and XSD.

 

JAX-WS

JAX-WS stands for Java API for XML Web Services. It defines rules and Java annotations to map Web Services to Java and vice versa. You can read the specification at http://jcp.org/en/jsr/detail?id=224.

 

JAX-WS and JAXB are both part of JDK 6 update 6 or later. Standalone distributions can also be downloaded from the web. Bob runs the JAX-WS wsimport tool from his JDK to generate the Java interfaces and corresponding JAXB classes from the WSDL and XSD. Here’s how that’s done:

wsimport –p com.tuscanyscatours.payment.creditcard CreditCardPayment.wsdl

Instead of using the tools provided by JDK 6 or other JAX-WS implementation projects, Bob could have used the JAX-WS wsimport Maven plug-in or ANT tasks to generate the Java classes. We use Maven in the TuscanySCATours example, and the following is included in the payment-java contribution pom.xml file.

<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxws-maven-plugin</artifactId>
<version>1.9</version>
<executions>
<execution>
<id>wsimport</id>
<phase>generate-sources</phase>
<goals>
<goal>wsimport</goal>
</goals>
<configuration>
<packageName>com.tuscanyscatours.payment.creditcard</packageName>
<wsdlDirectory>${basedir}/src/main/resources</wsdlDirectory>
<wsdlFiles>
<wsdlFile>CreditCardPayment.wsdl</wsdlFile>
</wsdlFiles>
<sourceDestDir>
${project.build.directory}/jaxws-source
</sourceDestDir>
<verbose>false</verbose>
<xnocompile>true</xnocompile>
</configuration>
</execution>
</executions>
</plugin>

The wsimport command or plug-in will generate the JAX-WS service endpoint interfaces as well as the JAXB classes for the complex XSD types. The list of generated files is shown in table 9.2.

Table 9.2. The Java classes generated from the CreditCardPayment WSDL using wsimport

Generated class

Description

CreditCardPayment.java The JAX-WS service endpoint interface. It can be used as a remotable interface for SCA Java component services or references.
AddressType.java
CreditCardDetailsType.java
CreditCardTypeType.java
PayerType.java
The JAXB classes to represent the complex types defined by the XML schema. For example, CreditCardDetailsType represents the detail information about the credit card.
AuthorizeType.java
AuthorizeResponseType.java
Wrapper types that hold the parameters passing in and out of the authorize operations. These are required to support wrapper-style encoding of parameters. You can read the details of wrapper-style encoding in section 2.3.1.2 of the JAX-WS specification.
ObjectFactory.java
package-info.java
The JAXB object factory to create JAXB objects and the package-info file containing the XML schema target namespace for the given package.

The wsimport tool will generate a Java interface for the service that the WSDL describes, as shown here.

Listing 9.3. AX-WS generated interface for the CreditCardPayment component
package com.tuscanyscatours.payment.creditcard;

import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.ws.RequestWrapper;
import javax.xml.ws.ResponseWrapper;

@WebService (name = "CreditCardPayment",
targetNamespace = "http://www.example.org/CreditCardPayment/")
@XmlSeeAlso({
ObjectFactory.class
})
public interface CreditCardPayment {

@WebMethod (action =
"http://www.example.org/CreditCardPayment/authorize")
@WebResult (name = "Status",
targetNamespace = "")
@RequestWrapper(localName = "authorize",
targetNamespace = "http://www.example.org/CreditCardPayment/",
className = "org.example.creditcardpayment.AuthorizeType")
@ResponseWrapper(localName = "authorizeResponse",
targetNamespace = "http://www.example.org/CreditCardPayment/",
className ="org.example.creditcardpayment.AuthorizeResponseType")
public String authorize(
@WebParam (name = "CreditCard", targetNamespace = "")
CreditCardDetailsType creditCard,
@WebParam(name = "Amount", targetNamespace = "")
float amount);
}

This generated Java interface looks complicated because it’s annotated automatically with JAX-WS annotations to capture additional metadata based on the corresponding WSDL and XSD. For example, @WebParm customizes the mapping of an individual parameter to a WSDL message part and XML element. @WebResult customizes the mapping for the return value.

If a plain Java interface with no annotations is written and used as the service interface, then the Tuscany runtime applies the default mapping rules defined by JAX-WS when handling maps between the service interface and the SOAP envelopes on the wire. For example, the targetNamespace will be derived from the Java package name and the parameter names will be assumed to be arg0, arg1, argN, and so on. For more information on the default mapping, please refer to chapter 3 of the JAX-WS specification.

Bob adopts the interface that’s generated by the JAX-WS wsimport tool. He also uses the generated JAXB classes that appear as parameters to the operations in the generated interface to represent the data in his Java component implementation. For example, the following listing shows the generated JAXB class used to represent the CreditCardDetails structure that he must pass to the authorize operation of the CreditCardPayment component.

Listing 9.4. JAXB generated class for the CreditCardDetails data structure

We’ve omitted the setter and getter methods from this class definition for readability. In this JAXB class, annotations are placed in the Java code by the wsimport tool to accurately record the mapping from the Java class to the XML schema type definition that was used to generate it. For example, @XmlType provides the name and the ordering of child elements. @XmlElement denotes a local XML element and specifies its name. This approach works well if you start from WSDL and XSD. If you start from written Java objects, then JAXB has a set of default mapping rules to map Java types into XML types.

Bob uses the generated CreditCardDetailsType type explicitly when creating his component implementation. The following listing shows how this generated JAXB type can be used.

Listing 9.5. Using generated JAXB classes within a component implementation

In this example the Payment component service defines two methods to show two ways in which data can be dealt with. In the makePaymentMember operation, it’s assumed that the customer has preregistered with TuscanySCATours and provided their credit card details. The details are retrieved from the database, and the CreditCardDetailsType object is created field by field to pass to the CreditCardPayment component. This is a good example of the component implementation performing some mediation between distinct application-level data types.

In the makePaymentNonMember operation, the client application collects the credit card details and passes them in. Bob passes the object straight through his logic and on to the CreditCardPayment component with no further intervention.

Now you’ve seen how Bob makes a request to the CreditCardPayment component. Let’s look at how Mary implements the service side.

9.2.2. Accepting data in component services as SDO objects

Mary takes a different approach than Bob. There are many different options for implementing the CreditCardPayment component, such as these:

  • A legacy application that’s wrapped as a web service
  • A web service implemented using C++ or .NET
  • A web service implemented in Java

From the data-representation perspective, the CreditCardDetails data can also be represented in many different ways. The key is that Mary’s decision can be completely independent of Bob’s, although what she’s implementing will be called by Bob’s Payment component.

Mary also decides to use Java to implement the CreditCardPayment component and will expose it as a web service using binding.ws. But instead of JAXB she chooses to use Service Data Objects (SDO) to represent the data. SDO is a data programming architecture and API. The Tuscany project provides an implementation of SDO, and the SCA runtime supports SDO as a databinding.

The main purpose of SDO is to simplify data programming so that developers can focus on business logic instead of the underlying technology used to represent data. SDO provides uniform access to data that can reside in heterogeneous sources such as XML, RDB, Java, and SOAP. SDO provides other benefits such as change history and disconnected model. We won’t cover all that here because this is a book about SCA. If you’d like to learn more about SDO, the Tuscany project and SDO specification that are published on OSOA and OASIS are a good starting point.

Let’s focus on the implementation details related to using SDO to represent data. Like JAX-WS and JAXB, SDO allows you to generate Java interfaces and classes from XML schema. As an alternative to statically generated Java classes that represent data structures, SDO also provides a dynamic API (commonj.sdo.DataObject) so that you can directly work with XML data in Java without code generation. In this next example we’ll use the static approach. The steps are similar to those used by Bob where he generated JAXB classes from WSDL for the client side.

Mary first generates the SDO classes from the CreditCardPayment.wsdl file. This can be done using the SDO static code generator, which is a command-line tool in Tuscany for generating Java source code (static SDOs) for data types defined in an XML schema. The generator is used as follows (assuming the SDO tools are available on the classpath):

java org.apache.tuscany.sdo.generate.XSD2JavaGenerator –targetDirectory
target/sdo-source –javaPackage payment.creditcard –prefix
CreditCardPayment –noNotification –noContainment –noUnsettable src/main/
resources/wsdl/ CreditCardPayment.wsdl

The structure of the SDO project code is described on the Apache Tuscany website (https://cwiki.apache.org/TUSCANY/sdo-project-code-structure.html). This includes details of the command-line arguments for this SDOstatic code generator.

As an alternative to the command-line generator, you can use the SDO Maven plug-in to generate the Java classes. We use Maven in the TuscanySCATours example, and the following is included in the creditcard-payment-sdo contribution pom.xml file:

<plugin>
<groupId>org.apache.tuscany.sdo</groupId>
<artifactId>tuscany-sdo-plugin</artifactId>
<version>1.1.1</version>
<executions>
<execution>
<id>generate-sdo</id>
<phase>generate-sources</phase>
<configuration>
<schemaFile>
${basedir}/src/main/resources/CreditCardPayment.wsdl
</schemaFile>
<javaPackage> com.tuscanyscatours.payment.creditcard</javaPackage>
<prefix>CreditCardPayment</prefix>
<noNotification>true</noNotification>
<noContainer>true</noContainer>
<noUnsettable>true</noUnsettable>
</configuration>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
</plugin>

Table 9.3 shows the set of interfaces and classes that result from running the SDO static code generator.

Table 9.3. SDO classes generated from the CreditCardPayment WSDL document

Generated class

Description

AddressType.java
AuthorizeResponseType.java
AuthorizeType.java
CreditCardDetailsType.java
PayerType.java
The Java interfaces for the XML data types
AddressTypeImpl.java
AuthorizeResponseTypeImpl.java
AuthorizeTypeImpl.java
CreditCardDetailsTypeImpl.java
PayerTypeImpl.java
The implementation classes of the Java interfaces
CreditCardPaymentFactory.java
The factory interface that can be used to create SDO objects
CreditCardPaymentFactoryImpl.java
The implementation class of the factory

Let’s look at the SDO version of the CreditCardDetailsType. SDO generates an interface as well as an implementation class. The interface doesn’t have any SDO dependencies, and so it can potentially be implemented using other technologies. The following listing shows the generated CreditCardDetailsType. The comments that appear in this generated code have been omitted for readability.

Listing 9.6. Generated SDO interface for CreditCardDetailsType
package com.tuscanyscatours.payment.creditcard;

import java.io.Serializable;

public interface CreditCardDetailsType extends Serializable {
String getCreditCardType();
void setCreditCardType(String value);
String getCreditCardNumber();
void setCreditCardNumber(String value);
int getExpMonth();
void setExpMonth(int value);
int getExpYear();
void setExpYear(int value);
PayerType getCardOwner();
void setCardOwner(PayerType value);
String getCVV2();
void setCVV2(String value);
}

There is a generated factory interface and class called CreditCardPaymentFactory. It can be used to create instances of CreditCardDetailsType.

Using these generated data types, Mary can now manually define a remotable service interface as follows:

@Remotable
public interface CreditCardPayment {

public String authorize(CreditCardDetailsType creditCard,
float amount);
}

Based on this remotable service interface, Mary can go ahead and create an implementation for the service. The implementation class will implement the interface.

@Service(CreditCardPayment.class)
public class CreditCardPaymentWSImpl implements CreditCardPayment {

public String authorize(CreditCardDetailsType creditCard,
float amount) {
String cardNumber = creditCard.getCreditCardNumber();
PayerType owner = creditCard.getCardOwner();
...
}
}

As the last step, the CreditCardPayment component service can be exposed using the Web Services binding by configuring the component in the following way:

<component name="CreditCardPayment">
<implementation.java
class="com.tuscanyscatours.payment.creditcard.impl.CreditCardPaymentImpl"/>
<service name="CreditCardPayment">
<interface.wsdl interface= "http://www.example.org/CreditCardPayment/#
wsdl.porttype(CreditCardPayment)"
<binding.ws/>
</service>
</component>

We’ve walked through the steps that Bob and Mary take to develop the two SCA components that exchange data over the Web Services protocol. Bob and Mary independently choose to use two different databindings (JAXB versus SDO) in their business logic to represent the same business data. Their choices are independent of the data-representation technologies imposed by the protocol stack, in this case, Web Services SOAP over HTTP.

Although it’s unlikely that you’ll be implementing the same application as Bob and Mary did, you’ll face the same problems of how to describe data structures on a service interface and how to create suitable data objects so that you can manipulate data in your component implementations. You may also be faced with a situation where different databindings are required to represent the same information. The techniques that are shown here apply whatever the specific nature of your application or the data you have to deal with.

Having said this, we’ll continue to follow Bob and Mary as they look into how the decisions they’ve made so far about using WSDL, JAXB, and SDO can be reflected in SCA component definitions.

9.3. Describing data contracts within SCA compositions

An SCA component has multiple places where you can specify the interfaces for SCA services and references. Figure 9.4 shows that component types, references, services, and bindings can all be configured with interface information.

Figure 9.4. Interface information can be configured through reference and service interfaces in the component type. It can also be configured through interface elements in the reference and service elements of a component in the composite file. Interface configuration can also be imposed by some bindings.

Arrow 1 in figure 9.4 shows that a Java field declaration annotated with @Reference in the implementation class is introspected as a reference of the component type. Section 9.3.1 describes how interface configuration is determined for a component type. Arrow 2 indicates that the component reference is inherited from the component type.

The component reference can be further configured with interface.wsdl and binding.ws, as illustrated by arrow 3. Section 9.3.2 discusses the impact of configuring the reference with an interface.wsdl element. Section 9.3.3 goes on to discuss the impact of binding specific interface configuration.

These same configuration points are also applicable to component services. This section gives you enough information to determine where interface configuration is required in your application.

9.3.1. Specifying contracts on the component type

The Payment component owned by Bob is a Java component. It configures the creditCardPayment reference with a Web Services binding.

<component name="Payment">
<implementation.java
class="com.tuscanyscatours.payment.impl.PaymentImpl" />
<reference name="creditCardPayment">
<binding.ws uri="http://localhost:8080/CreditCardPayment" />
</reference>
</component>

What interface is used for the creditCardPayment reference? The SCA assembly specification says that if the interface for a component reference isn’t explicitly configured in the composite file, then it inherits its interface from the component type. The component type represents the contract of the component implementation and can be derived in one of two ways: Either it can be specified explicitly in a component-type side file, or, for most implementation types, Java included, the component type can be derived by the runtime by inspecting the Java implementation class. From the data-handling perspective, the data types imposed by the implementation class dictate the representations of data that the component will consume and produce. The following listing shows an outline of the Payment component implementation. This will be used when determining the component type by introspection.

Listing 9.7. Introspecting the component type from the component implementation

In this case Tuscany builds the component type by introspecting the component implementation class, PaymentImpl, and the interfaces it implements. In particular, the runtime can detect that this component has a reference, creditCardComponent , which uses the CreditCardPayment interface. It can also detect that the component exposes a Payment service with two operations, makePaymentMember and makePaymentNonMember . Please refer to the description of implementation.java in chapter 5 to understand the rules that map Java members into SCA component type constructs.

Note that the creditCardPayment field is annotated with @Reference. It defines an SCA reference named creditCardPayment. The interface of the reference is com.tuscanyscatours.payment.creditcard.CreditCardPayment. The component implementation code is written to talk to the CreditCardPayment component through this Java interface. The Java types for the parameters and return value denote the data representation that the component uses to communicate with the service provider. In this case we know those types are JAXB objects because we’ve previously been through the steps involved in building this interface.

The data types for the service that the component exposes can be found by looking at the parameters that the two operations require. In this case it’s a combination of Java primitive types and the CreditCardDetailsType JAXB type.

9.3.2. Specifying contracts on component services and references

What if the interface is reconfigured at the component level? For example, the following code shows how an <interface.wsdl> element can be added to the composite description:

<component name="Payment">
<implementation.java
class="com.tuscanyscatours.payment.creditcard.CreditCardPaymentImpl" />
<reference name="creditCardPayment">
<interface.wsdl interface="http://www.example.org/CreditCardPayment/#
wsdl.interface(CreditCardPayment)"/>
<binding.ws uri="http://localhost:8080/CreditCardPayment" />
</reference>
</component>

Now the component reference is further configured with a WSDL interface. Interestingly though, this won’t change how the Payment component implementation code works with data. The Payment component talks to the CreditCardPayment component using the CreditCardPayment interface, which is the Java type for the field annotated with @Reference.

The interface for the component reference is used to constrain the algorithm that wires SCA references to SCA services. For example, the WSDL can be tailored to match only a subset of available component services. The <interface.wsdl/> element also provides information for the binding, for example, the WSDL required to define the web service.

Equally, a component’s services can be configured in the same way. In this case the interface description serves to restrict the service interface that’s exposed through the service binding. The interface configured in the service element must be a compatible subset of the interface offered by the service implementation.

9.3.3. Providing contract configuration to bindings

The binding configuration for a reference might impact how the data is represented by the binding extension code. In our case, <binding.ws> can point to a WSDL element, and the WSDL will be used to define the wire format for the SOAP message. For example, if <binding.ws> is configured as follows, the Web Services binding uses the WSDL service CreditCardPaymentService and WSDL port CreditCardPaymentPort as configuration when sending and receiving SOAP envelopes:

<binding.ws wsdlElement="http://www.example.org/CreditCardPayment/#wsdl.
port(CreditCardPaymentService/CreditCardPaymentPort)"/>

This ability to configure bindings is important because the details of a communication protocol used by a service may be exacting. For example, in the case of Web Services, the SCA reference may be required to send SOAP messages using document literal encoding or other specific forms of encoding. This detailed configuration can be achieved by providing the Web Services binding with a WSDL interface configured in precisely the right way.

This binding-specific configuration is also applicable to bindings that appear within component service elements of a composite file.

You’ve now seen how interface configuration information can be applied in various places in our SCA application. From this you understand how a component’s services and references are typed either through explicit configuration of the component type or composite files or through introspection of the component implementation itself. We’ll now look at how data is transformed in order that it will be presented in the right format in references and services, in the bindings they use, and on the wire between references and services.

When business data is exchanged over various protocols, different wire formats can be used to encode the data. For example, web services use XML messages, JSON-RPC uses JSON, and RMI-IIOP uses serialized Java objects. Different implementations of the same protocol stacks may choose to use different data representations. For example, in the Web Service domain, some examples are as follows:

  • Axis1 uses DOM.
  • Axis2 uses AXIOM.
  • JAX-WS uses JAXB.

You’ve already seen that when data is received from the bits and bytes of the transport, many different data representations are available in the Java programming language, for example:

  • Raw data, such as byte[], String, InputStream, or Reader
  • XML parsing technologies, such as DOM, SAX events, or StAX
  • Java/XML binding technologies, such as JavaBeans, JAXB, SDO (generated static SDO classes or dynamic DataObject), or AXIOM

All of these options mean that the Tuscany runtime must be flexible enough to provide suitable transformations as data flows from reference to service and back again. Section 9.4 gives an overview of various transformations that are required in order that data be in the right format at every point between reference and service.

9.4. Data transformations

In an SOA environment it’s not always possible to enforce a unified data representation technology for all service communications. Relying on business logic to convert data from one form to another removes some of SCA’s promised flexibility because it couples the service implementation, service collaboration, and service communication technologies tightly together. To exchange data in different representations without the intervention of business logic developers, we’ll need to introduce data transformation capabilities.

Bob and Mary have chosen to represent the data in different ways for their collaborating services. Data needs to be transformed so that the components can handle the data in their own formats. Let’s first understand what data transformation would be required for a round trip between the Payment and CreditCardPayment components from the TuscanySCATours scenario.

To purchase a travel package, the customer selects credit card as the method of payment. The customer isn’t a registered user, so when it comes time to pay for their chosen trip, they fill out a form on the web page to provide information such as credit card number, expiration date, holder’s name, and billing address. When the customer clicks the confirm button, the web browser sends the request to the Payment component. The Payment component then calls the external CreditCardPayment component over Web Services to authorize the charge. The status of the transaction is updated on the web page so that the customer knows whether it goes through.

Figure 9.5 shows how the various stages of this process take place and how data must be transformed between components.

Figure 9.5. Component interaction and data flow for the credit card payment sample

The following sections describe the requirements for each of the three main transformations in turn. Each section refers to the corresponding stage number in figure 9.5. The process starts in the web browser JavaScript, which takes the credit card data from the HTML form and populates a JavaScript object. It then makes an Ajax invocation to the Payment component running on the server using the JSON-RPC protocol. In the browser the data is represented as a JavaScript object and exchanged over the HTTP connection using JSON format.

9.4.1. Converting the data coming from the browser from JSON to JAXB

This is shown as stage 1 in figure 9.5. The Payment component is implemented by a Java class. It provides a service that takes the credit card information as a JAXB object. The service is configured with binding.jsonrpc to service the Ajax requests from the web browser. The binding receives the JSON data from the JSON-RPC layer, and it needs to be converted into the JAXB object so that the Java implementation for the Payment component can handle it.

9.4.2. Converting from JAXB to AXIOM in order to send a SOAP request

This is shown as stage 2 in figure 9.5. The Payment component has a reference to the CreditCardPayment component using the Web Services protocol in order to authorize the credit card charge. The Java implementation makes the web service request using a Java interface, which passes a JAXB object. The JAXB object has to be transformed into an AXIOM object so that the Axis2 stack can marshal it into a SOAP message. Web service responses are unmarshalled back into JAXB from the AXIOM/XML representation provided by Axis2.

9.4.3. Converting from AXIOM to SDO

This is shown as stage 3 in figure 9.5. The Web Services binding for the CreditCardPayment component receives the credit card transaction from the Axis2 stack as an AXIOM object, and it needs to be converted into SDO so that CreditCardPayment can handle it. Responses coming back from the CreditCardPayment component are transformed from SDO back into AXIOM ready for the Web Services binding to create the response SOAP envelope.

These data transformations seem to be complicated and they’re technology oriented. If the application developers were forced to manually convert the data from one format to the other, it would be a burden. The business logic would become brittle again because it would be tied to a set of data representation technologies that are peculiar to the binding technology. We would also lose the flexibility to connect references and services that represent the same data in different ways. But don’t worry, because you’ll now see how Tuscany helps Bob and Mary by introducing a databinding framework that provides transparent data transformation between components without the intervention of a component’s business logic.

9.5. The Tuscany databinding framework

In order to facilitate data handling in the SOA environment, the Tuscany SCA infrastructure provides a databinding framework that handles data conversions automatically at points in the architecture where data conversion is required. This preserves application flexibility and simplifies the development of bindings. Figure 9.6 shows where the Tuscany runtime transparently transforms the data passing between the Payment and CreditCardPayment components without intervention from the business logic.

Figure 9.6. Automatic data transformation between Payment and CreditCardPayment components

Tuscany supports popular databindings such as JAXB, SDO, DOM, StAX, and AXIOM. It also provides the ability to extend the architecture to easily add new ones. The Tuscany databinding framework is illustrated in figure 9.7, transforming data at a component reference. The same process happens for a component service.

Figure 9.7. The Tuscany databinding framework uses a graph of transformers (1–6) to find a path (1) to transform data from JAXB to AXIOM for the Payment component reference using binding.ws.

There are a few primary functions in the databinding framework. Databinding abstracts the different representations of data. Code to transform from one data representation to another is plugged into the Tuscany runtime as databinding transformers. Transformers (marked as 1–6 in figure 9.7) connect databindings, and they form a graph for the possible paths by which data can be transformed. Figure 9.7 shows a path with transformer 1 chosen to convert data from JAXB to AXIOM.

Component implementation extensions use the Tuscany extension programming interfaces to provide information about which data representations can be handled by the business logic. In some cases the details of the expected data type can be specified by the component implementation itself via the component service interface. You’ve seen how this is achieved in our CreditCardPayment example, where the Java interface describes operations with parameters using specific data representation technologies. In our example, the data is represented using JAXB and SDO.

Binding extensions use the Tuscany SPI to tell the Tuscany runtime which data representations are expected by the protocol stack. The data can then be converted from the application code into a supported representation by the binding and vice versa. The Tuscany runtime will establish the following paths for data transformation.

  • SCA component reference > SCA reference binding
  • SCA service binding > SCA component service

If there is a mismatch between the data representation used by the component and the data representation used by the binding, a data transformation interceptor will be added to perform the data transformation. This transformation is transparent to application developers. When transformation is needed, the interceptor finds a path in the transformer graph and invokes the transformers on the path to convert the data from the source representation to the target representation. There may be multiple paths between two databindings. If a direct transformer is available, the Tuscany runtime will use it; otherwise, it’ll find the most efficient path between the two databindings. In the case that no path can be found, a system exception will be thrown to indicate that the two components can’t interact using the data formats as is.

9.6. Summary

In this chapter, we’ve shown the different aspects of data handling in an SCA environment through the sample credit card payment scenario.

As you learned previously in this book, with SCA and Tuscany it’s straightforward to reconfigure and assemble a business solution, for example, you can

  • Change the implementation technology
  • Change the reference to service wiring
  • Change the communication protocol

As you’ve seen from Bob and Mary’s experience in this chapter, in order to exploit this flexibility, application developers need the freedom to choose their preferred data representation. Components with compatible data but with incompatible data representations, such as JAXB and SDO, are able to interoperate without changing the business logic. You’ve seen that data representation can be considered in three different places:

  • Component implementation
  • Component references and services and their bindings
  • Communication protocols between bindings

The same SCA service can be implemented using different technologies that support or require different data representations. Some implementation types such as implementation.java don’t mandate how data will be represented, and it’s up to component developers to choose the appropriate format. Other implementation types, such as implementation.bpel, require specific data representations, in this case XML. It all depends on what data format the component implementation engine supports.

In SCA, service providers are decoupled from service consumers. Collaborating services don’t have to adopt the same data representations for the same data structure. It isn’t even feasible in some cases; for example, the service consumer and service provider may be owned by two different organizations, which have their own preferred data representations. The same SCA service can be consumed by more than one service that provides input data and handles output data with different representations. So the data representation for a service provider is agnostic in relation to the service consumers.

SCA also separates the communication protocols from the business logic. Declarative bindings make it possible to switch protocols without changing the component implementation code. Furthermore, the same SCA service and references can be configured with different bindings so that they can communicate over different protocols that require different wire formats. For example, the Payment component can be configured using both binding.ws and binding.jsonrpc so that it can be exposed as a Web Service and a JSON-RPC service. The Web Services protocol uses an XML-based wire format, whereas JSON-RPC uses JSON. Similar requirements apply to SCA references too.

Tuscany provides a framework that simplifies the data representation and transformation so that business application developers can have the freedom to choose their preferred data representation technology. This allows developers to implement business logic without worrying about complex data transformations between references and services. This decoupling of data representation allows SCA to deliver on its promises of flexibility and agility. A developer can rewire a component and even change the binding technology without having to change the component implementation to take account of differing data representations.

Now that you understand how data can be represented and transformed, it’s time to take a wider view of an SCA application and look at how statements of policy can be applied, which are independent of component implementations, their reference, services, and bindings, and, indeed, the data that passes between them.

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

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