Chapter 2. Using SCA components

This chapter covers

  • Implementing SCA components
  • Defining services, references, and properties
  • Connecting components using wires and bindings

In the previous chapter we gave a practical introduction to Apache Tuscany and the major technical concepts in SCA, showing how a business application can use SCA and benefit from its capabilities. In this chapter and the next, we’ll cover the essential concepts of SCA in more detail and show you how to use them to develop applications using Tuscany.

As a first step toward building Tuscany applications, you need to be familiar with SCA components, which are the fundamental building blocks for all SCA applications. We start by looking at the relationship between components and their implementations. Next, we’ll show how components provide services themselves and invoke other services using references and wires. We’ll examine how properties are used to customize aspects of a component’s behavior. We will then show how bindings are used to select wire protocols for a component’s services and references, and we’ll finish the chapter by looking at how deployment of components into domains affects the choice of bindings.

You’ll find plenty of examples and illustrations that show how to use these features of SCA in real applications, with discussions of design alternatives and guidance for best practice. The code samples in this chapter illustrate specific aspects of SCA using scenarios related to the simplified travel-booking application that we introduced in chapter 1. They’re not used directly as part of the complete running travel application. You can find these samples in the contributions/usingsca directory in the travel sample code.

After reading this chapter, you’ll understand how to use SCA components to create and customize applications that run on Apache Tuscany.

2.1. Implementing an SCA component

Every component contains an implementation that provides the component’s business logic. For example, a component implementation could be a Java class, a BPEL process, or an EJB. The implementation controls what the component does and how it interacts with other components. Figure 2.1 shows a component implemented using a Java class and another component implemented using a BPEL process.

Figure 2.1. An SCA component implemented using a Java class and another SCA component implemented using a BPEL process

Each component has an implementation type, which identifies the implementation technology used by the component (for example, a Java class or a BPEL process). You can take advantage of SCA’s support for different implementation types by choosing the implementation technology best suited to each application component. SCA components all have the same architecture, so it’s easy to combine them into a composite application. For example, the travel-booking application that we described in chapter 1 uses components with Java implementations. In chapter 6 we’ll show how you can add a BPEL component to this application. Components aren’t aware of each other’s implementation type, so a Java component can use a BPEL component without needing to know that it’s written in BPEL, and vice versa.

The SCA approach to components is different from other component technologies such as EJB, Microsoft .NET, and Spring. In SCA, any container-specific dependencies are encapsulated in the implementation type instead of being part of the component definitions. This is illustrated in figure 2.2.

Figure 2.2. SCA component definitions aren’t tied to any specific container technology, unlike components defined by other technologies such as EJB and Spring.

In the rest of this section we’ll look at the different implementation types that you can use with SCA components, and we’ll show how SCA uses component definitions to configure component implementations. We’ll also take a detailed look at the SCA concept of component type, which defines the formal relationship between a component implementation and its component definition.

2.1.1. Choosing an implementation type

Each component definition specifies the implementation type of the component. For example, a component with a Java class as its implementation has an implementation type of implementation.java, and a component implemented by a BPEL process has an implementation type of implementation.bpel. SCA components are defined using XML, and the following example shows how the components pictured in figure 2.1 could be defined.

<composite name="cart"
....>
<component name="ShoppingCart">
<implementation.java
class="com.tuscanyscatours.impl.ShoppingCartImpl" />
....
</component>
<component name="Payment"
xmlns:pp="http://www.tuscanyscatours.com/Payment">
<implementation.bpel process="pp:Payment" />
....
</component>
</composite>

The name attribute of the <component> element specifies the component name. This is used to refer to the component and qualify references to its constituent parts. The <composite> element is used to enclose component definitions. A composite can’t contain more than one component with the same name.

The ShoppingCart component has a Java implementation and is defined with the <implementation.java> element. The class attribute of this element contains the fully qualified name, com.tuscanyscatours.impl.ShoppingCartImpl, of the implementation class. The Payment component is implemented by a BPEL process, so it has an <implementation.bpel> element with a process attribute naming the BPEL process Payment in the XML namespace corresponding to the pp prefix. By convention, implementation elements are written as <implementation.*> with the * replaced by the specific implementation type.

The SCA 1.0 specifications define standard implementation types for Java code and code written in BPEL, C++, C, and COBOL, as well as Spring, web applications (.war files), EJBs, and Java EE archives (.ear files). SCA also provides an extension point for creating additional implementation types.

Tuscany provides implementations of the SCA implementation types for the Java language, BPEL, C++, Spring, and web applications. Tuscany also supports additional implementation types that aren’t currently part of the SCA specifications, enabling application developers to use the SCA component model with the following popular technologies:

  • HTML pages containing Web 2.0 user interface widgets and JavaScript code, described in chapter 8.
  • Scripting languages such as Python, JRuby, Groovy, and JavaScript. See chapter 6 for more details.

See chapters 5, 6, and 8 for more information about the implementation types in Tuscany. For application-specific needs that aren’t covered by the Tuscany implementation types, application developers can create additional implementation types using extension points in the Tuscany runtime. Chapter 14 describes these extension points and shows how they can be used to create user-defined implementation types.

We’ve looked at the different implementation types that you can use for components. Next we’ll show how to use SCA component definitions to configure implementations in different ways.

2.1.2. Configuring SCA components using component definitions

In SCA, a component is a configured implementation. The same implementation can be used in different components, configured in different ways. This enables code reuse while providing a high degree of flexibility and customizability. The configuration applied to an implementation that makes it into an SCA component is called a component definition.

SCA component definitions are written using an XML syntax. These definitions can configure those aspects of the component implementation that the implementation has exposed as being configurable. The configurable aspects of an implementation are collectively known as the implementation’s component type. The component type includes the services, references, and SCA properties defined by the implementation. The implementation’s business logic can’t be modified using component definitions, so the business logic isn’t part of the component type.

 

A hardware analogy for SCA components

To illustrate the relationship between the component implementation, the component type, and component definitions, we can use the analogy of a hardware component such as the 555 Timer IC (http://en.wikipedia.org/wiki/555_timer_IC). This chip is manufactured by different companies (Philips, Motorola, RCA, and so on) with different part numbers, and all versions of it work according to the same specification and can be used in the same electronic circuit. It’s also possible for a circuit that uses this chip to customize its operation by varying the voltage or capacitance applied to various pins.

In SCA terms, the manufacturer’s part number is an SCA component implementation, with different implementations possible for the same component functionality. When an individual chip is installed in a circuit, this is comparable to a configured SCA component, with the design of the surrounding circuit providing the component’s configuration. The SCA component type corresponds to the chip’s pin connections, which control the customizations that can be applied to the component implementation. The analogy isn’t perfect, but it may help you to visualize what’s going on when we talk about the component type of an SCA component implementation being configured by a component definition.

 

We’ll use an example to show how the same SCA component implementation can be configured in different ways by different components. In this example, a car rental implementation defines an SCA property for the minimum age of the renter. This implementation can be configured by different car rental partner companies so that one company’s car rental component requires a minimum age of 21 and the other company’s component requires a minimum age of 25. This scenario is illustrated in figure 2.3, which shows how the same car rental implementation has been configured to produce a component for a provider of value cars with a lower minimum renter age and a component for a provider of luxury cars with a higher minimum age. Figure 2.3 shows the relationships between the implementation, the definitions of the two components, and the resulting components.

Figure 2.3. An SCA component implementation that’s been configured using two different component definitions to produce two SCA components. The numbered arrows represent different kinds of relationships between the objects shown in the figure.

At the lower left of figure 2.3 is the CarVendorImpl implementation. For the purposes of the diagram, this is shown separated into its configurable portion (the component type) and its nonconfigurable portion (the business logic), represented by different sizes of rectangle. Above this are XML component definitions for BestValueCars and TopLuxuryCars with different configurations of the CarVendorImpl implementation. At the right of the figure are the SCA components BestValueCars and TopLuxuryCars that we’ve created from this implementation and these component definitions.

The component type isn’t the same as the component’s implementation type that we mentioned in section 2.1.1. The implementation type just says what kind of implementation technology the component uses, such as a Java class or a BPEL process. The component type is a much more detailed picture of the “shape” of this particular implementation, focusing on services, references, and properties, because these are the aspects of the implementation that can be configured by SCA component definitions.

The BestValueCars and TopLuxuryCars components share the same business logic from the CarVendorImpl implementation (shown by the arrows marked 1 in the figure). In contrast, each component has its own configuration resulting from merging its component definition with the implementation’s component type (shown by the arrows marked 2 and 3 in the figure), with the component definition taking priority. As well as the difference in minimum renter age, the TopLuxuryCars component would have a different list of car types and prices than the BestValueCars component.

You’ve seen how the configurable shape of an implementation is represented by its component type and how SCA components are created by configuring component implementations using component definitions. Next, we’ll look at what kinds of things are in the component type and how the component type of an implementation is defined.

2.1.3. Discovering or defining the component type

SCA uses two different approaches for discovering or defining the component type of an implementation, depending on whether the underlying implementation technology provides facilities for programmatically examining its own implementations (known as introspection). For implementation types that support introspection (such as Java classes and BPEL processes), SCA defines rules for discovering the component type of an implementation by introspecting it. For implementation types where automatic discovery by introspection isn’t possible, the definition of the component type must be provided alongside the implementation as a separate XML file.

For Java implementations, the component type is introspected from the component’s Java implementation class. The following listing shows a simple example of a Java implementation class with no SCA annotations.

Listing 2.1. A Java component implementation class with no SCA annotations
package com.tuscanyscatours;

public class AirportCodes {
public String getAirport(String code) {
if ("AAA".equals(code)) return "Anaa";
else if ("AAB".equals(code)) return "Arrabury";
// other airport codes and cities would follow here
else return null;
}
}

You can find this example in the contributions/usingsca directory of the travel sample.

There’s no need for the user to provide a component type definition because Tuscany determines the component type by introspecting the implementation class. The introspected component type for this class contains information that’s equivalent to the following XML definition:

<componentType xmlns="http://www.osoa.org/xmlns/sca/1.0">
<service name="AirportCodes">
<interface.java interface="com.tuscanyscatours.AirportCodes" />
</service>
</componentType>

Because the component type is determined by the Tuscany runtime using introspection, there’s no physical artifact containing the above XML. In these cases, when we use the XML syntax in this book, it’s as a human-readable way of showing the implementation’s component type using a standard notation.

In this example there are no SCA annotations in the implementation class. If the class does contain SCA annotations, these are recognized and processed as part of introspecting the class to discover its component type, as you’ll see in the following sections.

Some implementation technologies don’t support introspection. SCA handles this situation by requiring a “side file” to be provided alongside the implementation to define its component type. This file has the extension .componentType and contains XML definitions written using the syntax shown previously. For SCA implementation types that use introspection such as implementation.java, side files aren’t recognized and will be ignored if present.

We’ve looked at how component types are discovered and defined, and we’ve shown how a component type can be described using an XML representation. In the following sections we’ll examine the details of what a component type can contain.

2.2. Using components to provide services

SCA is all about enabling service composition. Most SCA components provide at least one service, though it’s possible to have components that use other services without providing any services themselves. These services can be used by other SCA components or by non-SCA code.

In this section we’ll explore services in detail, starting with how services are defined by a component implementation and going on to explain how these services can be configured using component definitions. Finally, we’ll look at some advanced features of service interfaces in SCA, such as local and remotable interfaces, bidirectional interfaces and callbacks, and conversational interfaces.

2.2.1. Defining services

The SCA specification describes a service as an addressable interface of the component’s implementation. To put this into somewhat simpler language, every service has a name and an interface. The name identifies the service and distinguishes it from other services. The interface defines the names, inputs, and outputs of the operations that the service provides. Figure 2.4 shows a component with one service.

Figure 2.4. TripBooking is an SCA component with one service named Bookings.

The services provided by a component are defined by the component’s implementation. The details of how these services are defined depend on the component’s implementation type. For example, when using implementation.java, the @Service annotation on the service implementation class specifies one or more Java interfaces that represent services provided by the implementation. The following example shows how @Service can be used:

package com.tuscanyscatours.usingsca.impl;
import com.tuscanyscatours.Bookings;
import org.osoa.sca.annotations.Service;

@Service(Bookings.class)
public class TripBookingImpl implements Bookings {
....
public String newBooking(String trip, int people) {
....
}
}

This implementation defines a single service named Bookings with the Java interface com.tuscanyscatours.Bookings. This interface could be defined as follows:

package com.tuscanyscatours;
import org.osoa.sca.annotations.Remotable;

@Remotable
public interface Bookings {
String newBooking(String trip, int people);
}

All the methods of the interface are exposed by the service.

If the implementation class isn’t annotated with @Service, SCA assumes that the implementation class has services corresponding to all its implemented interfaces that are annotated with @Remotable (see section 2.2.4 for more information about remotable services). The Bookings interface is annotated with @Remotable, so we could have omitted the @Service annotation from the implementation class.

The component implementation class is usually declared as implementing (in the Java language sense) its service interfaces. In the previous example, the TripBookingImpl class does this by declaring that it implements the Bookings interface. However, SCA doesn’t insist on this and only checks that all the methods of the service interfaces are present in the implementation class. You can find full details of how to define services for Java implementations in chapter 5.

Other implementation types have different ways of defining services. For example, implementation.bpel introspects the BPEL process to find partner links that receive a message before sending a message and maps these partner links to SCA services.

 

One ring to bind them all...

If you’re used to working with other component models, you may find it surprising that SCA delegates the task of service definition to component implementations and allows each implementation type to do this in its own way. This approach works because SCA requires all implementation types to support the same service and component semantics. These semantics are embodied in the SCA definition of component type. This consistency ensures that all SCA services and components can be configured and composed in the same way, no matter what implementation technology was used to define them. The same goes for references and properties, as you’ll see in later sections of this chapter. The combination of a common abstraction for components and services together with complete flexibility for how this abstraction is expressed in different implementation technologies is one of the most powerful and compelling features of SCA.

 

Every service has an interface that specifies the operations provided by the service and the input and output types of those operations. In the previous example, the SCA service Bookings has the Java interface com.tuscanyscatours.Bookings. This means that the Bookings service has a single operation, newBooking, with inputs of a String and an int, and a String as output. A service with a Java interface containing two methods would have two operations. Let’s look at how interfaces are defined in SCA.

2.2.2. Interface definition in SCA

Interfaces are widely used in many programming and communication technologies. For example, a Java interface defines a programming contract that can be provided by an implementation class and is used by other implementation classes. C++ uses abstract base classes for the same purpose. In Web Services, WSDL 1.1 definitions use portTypes (renamed to interfaces in WSDL 2.0) to define the operations that can be used to interact with services. CORBA uses OMG IDL (Interface Definition Language) to define the interface provided by a remote object. These are just a few examples of existing interface-definition technologies. SCA has chosen not to create an interface-definition mechanism of its own but instead to make interface definition an extensibility point so that existing styles of interface definition can be used for SCA services.

 

Why doesn’t SCA have its own interface definition language?

An important part of SCA’s vision is to provide a service-oriented programming model that can be used with the broadest possible range of existing technologies. SCA can be used to compose Java implementations, web service endpoints, CORBA distributed objects, and much more. When connecting Java implementations, it’s natural to use Java interfaces. For composing web services, WSDL definitions are the preferred choice, and when exposing a CORBA implementation using SCA, it’s easiest to use CORBA IDL interfaces that have already been defined. A new interface definition language imposed by SCA would not add value but would make it harder for users to create SCA services that use these technologies.

 

The interface languages that can be used to define SCA interfaces are represented in SCA by different interface types. For example, a service whose interface is defined by a WSDL 1.1 portType is represented in an SCA component definition by the interface.wsdl interface type and XML element. Here’s an example:

<interface.wsdl interface=
"http://tuscanyscatours.com/#wsdl.interface(Bookings)" />

This defines an SCA interface using a WSDL 1.1 portType named Bookings, which is in the XML namespace http://tuscanyscatours.com/. In case you’re wondering about using WSDL 2.0, this is permitted in SCA 1.0 but isn’t supported by Tuscany and has been removed from SCA 1.1.

An SCA service with a Java interface would have the interface.java interface type, as in the following example:

<interface.java interface="com.tuscanyscatours.Bookings" />

Here the SCA interface is defined using the Java interface whose fully qualified name is com.tuscanyscatours.Bookings. The <interface.wsdl> and <interface.java> elements both contain an interface attribute, with each interface type specifying what this attribute value can contain.

What happens when SCA is used to compose services that use different interface technologies? For example, the Trips service could be implemented as a web service endpoint defined in WSDL, and the Bookings service, which uses Trips, could have a Java implementation. We’d like to be able to define the Trips service with a WSDL 1.1 portType for its interface, while allowing the Bookings service to use a Java interface when referring to the same service. SCA supports these combinations, which brings up some interesting questions, such as what to do about overloaded methods (allowed in Java interfaces but not in WSDL) and how to handle data transfer objects (Java interfaces use Java objects, but WSDL uses XML schema types). You’ll see how SCA deals with this when we look at wiring in section 2.3.2.

You’ve seen how services and interfaces are defined in SCA. Now we’ll look at how an SCA component definition can customize the definitions of the component’s services.

2.2.3. Configuring services in component definitions

The component definition can specify configuration settings for services defined in the implementation’s component type. For example, the component definition can change a service interface to use a different interface language. The Bookings service that you saw in section 2.2.1 has an introspected interface type of interface.java. The interface type could be changed to interface.wsdl in a component definition, which means that the component service interface is a WSDL 1.1 portType. This could be useful when creating a component that will be accessed by other components that don’t have Java implementations. Here’s an example component definition that does this:

<component name="WebBooking">
<implementation.java
class="com.tuscanyscatours.usingsca.impl.TripBookingImpl" />
<service name="Bookings">
<interface.wsdl interface=
"http://tuscanyscatours.com/#wsdl.interface(Bookings)" />
</service>
</component>

Another example of component service configuration is a component definition overriding the component implementation’s service interfaces to subset the service operations defined by the component implementation. The component definition can’t add additional operations or additional services that go beyond those defined by the component implementation.

A component definition can’t remove any of the services defined by its component implementation. We’ll show how you can subset these services in section 3.4.2.

If the component definition doesn’t specify any configuration for the service, the default configuration computed by the component type discovery rules is used. For example, the same implementation could be used in another component defined as follows:

<component name="TripBooking">
<implementation.java
class="com.tuscanyscatours.usingsca.impl.TripBookingImpl" />
</component>

This component definition doesn’t mention the service or its interface, so it has a Bookings service with an interface definition taken from the implementation’s introspected component type. We’re using a Java implementation type, and this means that the introspected interface type will always be interface.java.

You’ve seen how implementations define services and how services use interfaces to specify the operations that the service provides. Services are part of the implementation’s component type, which represents the configurable aspects of the implementation. SCA supports a number of different implementation types as well as different interface types. Component definitions are used to configure components by combining component implementations with additional configuration information. The component type represents those aspects of a component implementation that can be reconfigured by a component definition. If you’re comfortable with all of this, you’re well on the way to understanding SCA! Now it’s time to look at some other interesting things you can do with SCA interfaces.

 

What you see may not be what you get

When you look at a component definition, you may not see everything that the component contains. This is because all the services, references, and properties from the implementation’s component type automatically become part of the component as is, unless they’re reconfigured in the component definition. Some people feel slightly uncomfortable with this and prefer to spell out component definitions in full by repeating everything from the component type in the component definition.

 

2.2.4. Local and remotable interfaces

SCA supports local and remotable interfaces. A service with a local interface can only be called from code running in the same operating system process (a local call). A service with a remotable interface has the additional ability to be called from code running in a different process or on a different computer (a remote call). Services defined with remotable interfaces can be used for local calls as well as remote calls.

It’s up to the definition of each SCA interface type as to whether interfaces of that type can be local, remotable, or both. Interfaces defined using the interface type interface.wsdl are always remotable. Interfaces defined using the interface type interface.java can be either local or remotable; the default is local, with remotable interfaces identified using the @Remotable Java annotation.

The choice of a local or remotable interface has consequences for implementation developers. With a local interface, parameters and results are passed by reference (shared), and any changes made to these shared programming language objects by the service implementation are visible to calling code. With a remotable interface, parameters and results are passed by value (copied), and any changes made by the service implementation aren’t seen by the calling code. Sharing data can be more efficient, but it creates a closer dependency between implementation details of the calling code and the service implementation (tight coupling). Copying data means that calling code and service implementation are less dependent on each other’s internal details (loose coupling), but the copying can be costly, especially if the amount of data being passed is large. The best of both worlds would be to have the flexibility of remotable interfaces without the cost of data copying, and SCA and Tuscany provide optimizations to support this for many common cases.

Some services need to be remotable because they’re called by other services that are running in a different location. Remotable services also provide better deployment flexibility than local services, because a remotable service can be moved to a different execution host machine or process without affecting any code that calls the service. Moving a service might be necessary to improve scalability, fault tolerance, or security. In contrast, a local service can’t be moved unless all the code that calls the service is moved at the same time, so that the locality relationship between calling code and service implementation is maintained.

You can find more detailed information about local and remotable interfaces in chapters 4 and 5, with examples of how you can use them in Tuscany applications. Next we’ll look at how SCA supports callbacks using bidirectional interfaces.

2.2.5. Bidirectional interfaces and callbacks

In most service-definition technologies, the roles of service provider and service requester are clearly distinguished. The service provides business functionality, and the service requester makes use of this functionality by invoking service operations defined by the service interface. In some cases a service interaction also requires the service provider to make invocations back to the service requester. To support this interaction style, SCA provides the ability to define a bidirectional interface.

A bidirectional interface is a combination of two interfaces: one that’s used for service requesters to invoke the service provider and one that’s used by the service provider to make invocations to the service requester (referred to as callbacks). In an interface definition, the forward interface for invocations from requester to service provider is specified using the interface attribute, and the callback interface for invocations from service provider to requester is specified using the callbackInterface attribute. Here’s an example of a bidirectional interface definition for the interface.java interface type:

<interface.java
interface="com.tuscanyscatours.common.Search"
callbackInterface="com.tuscanyscatours.common.SearchCallback" />

A service requester using a service that provides a bidirectional interface needs to support the callback interface so that the service provider can make callbacks to the service requester. The details of how the requester’s implementation provides this support depend on the requester’s implementation type. For implementation.java, this support is normally provided by the requester’s implementation class implementing the callback interface.

Bidirectional interfaces can be local or remotable. Mixing local and remotable interfaces within a bidirectional interface definition isn’t allowed, so you can’t specify a remotable callback interface for a local forward interface (or vice versa).

There’s a detailed discussion of bidirectional interfaces and callbacks in chapter 4, with examples of business scenarios that require this interaction style and sample code showing how to implement the service requester and provider sides of a bidirectional interaction. Now we’ll look at how service implementations can maintain state between service invocations by using conversational interfaces.

2.2.6. Conversational interfaces

Some interactions between service requesters and providers require a sequence of calls to perform a business function. For example, an initial call could create an order, subsequent calls could add items to the order, and a final call could submit the order for processing. This kind of interaction is often described as stateful, because of the need for both the requester and provider to maintain internal state data reflecting the current state of the interaction.

SCA 1.0 supports the concept of conversational interfaces to model this kind of interaction style. For interface.java, the interface can be marked as conversational by using the @Conversational annotation on the Java interface. For interface.wsdl, SCA has defined the global attribute requires in the SCA namespace, which can be used to mark a WSDL 1.1 <portType> or WSDL 2.0 <interface> element as representing a conversational SCA interface.

Conversational interfaces can be local or remotable. It’s possible to mark a bidirectional interface as conversational in its forward direction, in its callback direction, or in both directions. Chapter 4 contains a detailed explanation of conversational interfaces and shows how to use them in Tuscany applications.

 

Note

The future of conversational interfaces in the SCA specifications is under discussion. Although there are similar concepts in some other middle-ware technologies, there’s currently no accepted industry standard for conversational semantics. Because of the lack of industry standardization in this area, conversations aren’t included in the SCA 1.1 specifications being standardized by OASIS and will be reconsidered for a future version of SCA.

 

You’ve seen how services are defined and configured in SCA and the important role that interfaces play in defining services. Now we’ll look at how SCA service implementations can make use of other services.

2.3. Connecting components using references and wires

Service implementations often need to use other services, and they identify their dependencies on other services by defining references. Let’s suppose that TuscanySCATours is changing its business model to partner directly with car, flight, and hotel providers instead of using a trip-provider service to purchase prepackaged trips. This reduces the cost of purchasing trips and also opens up the possibility of selling customized trips. To implement this we’ll modify the TripBooking component so that it has references for a car-booking service, a flight-booking service, and a hotel-booking service, as shown in figure 2.5.

Figure 2.5. TripBooking is an SCA component with one service and three references.

In this section we’ll show how a component’s references are defined and how they’re connected to other services. We’ll also show how a single reference can be connected to more than one service.

2.3.1. Defining references

The details of how to define a reference vary between implementation types. For Java implementations, the @Reference annotation is used for this. The following example shows a reference definition for a flight-booking service:

package com.tuscanyscatours.usingsca.impl;
import com.tuscanyscatours.Bookings;
import com.tuscanyscatours.Flights;

public class TripBookingImpl implements Bookings {

@Reference
protected Flights flights;

....
}

In this example code, Bookings and Flights are Java interfaces for the trip-booking and flight-booking services, TripBookingImpl is the implementation class for the trip-booking service, and the flights field in the TripBookingImpl class is annotated with @Reference. The name of the reference defaults to flights, which is the name of the field. This default name can be overridden by adding a name member to the @Reference annotation. When an SCA runtime such as Tuscany creates an instance of the TripBookingImpl class, it injects a proxy for the flight-booking service into the flights variable. This means that the flights variable is initialized to the correct value, even though there’s no code in TripBookingImpl that does this.

The injected proxy implements the same Java interfaces as the service that it calls. When called by code in the service requester, it invokes the service on the requester’s behalf (hence the term proxy). For example, to call the flight-booking service to make a reservation, the requester could call the reference proxy injected into the flights field using code like the following:

flights.bookFlight(flightNumber, date, numSeats, bookingClass);

References can be injected into Java implementations using constructor parameters, fields, or setter methods. See chapter 5 for full details of how to do this. The following listing is an example showing these different styles of reference injection for Java implementations. You can find this example in the contributions/usingsca directory of the travel sample.

Listing 2.2. Reference injection using fields, setter methods, and constructor parameters

In listing 2.2, a reference proxy to a car-booking service is injected using a constructor parameter, a reference proxy to a flight-booking service is injected using a field, and a reference proxy to a hotel-booking service is injected using a setter method.

The introspected component type contains three references named cars, flights, and hotels. It doesn’t make any distinction among these references based on the different ways they were defined in the Java code (as a constructor parameter, a field, and a setter method). This is because the component type is an abstraction of the configurable shape of the implementation and doesn’t include any Java-specific implementation details.

Other implementation types have their own ways of defining references. For example, the BPEL implementation type introspects the BPEL process to find partner links that send a message before receiving a message, and it maps these partner links to SCA references.

You’ve seen how component implementations can define references, and you’ve looked at different ways of injecting reference proxies into Java implementations. Now it’s time to examine how references know which services to call.

2.3.2. Wiring references to services

The connection between a reference and a service is called a wire, and the process of making these connections is called wiring. Tuscany wires a component’s references when the component is deployed, before the component’s implementation starts executing.

Figure 2.6 shows how the TripBooking component could be wired to services for making car bookings, flight bookings, and hotel bookings. In this figure, the wires are the lines connecting references and services. Wiring is part of component configuration, and wires are specified using component definitions.

Figure 2.6. The SCA references in the TripBooking component have wires connecting them to SCA services in other SCA components: CarPartner, FlightPartner, and HotelPartner.

The following listing shows component definitions corresponding to the components and wires in figure 2.6. This example can be found in the contributions/usingsca directory of the travel sample.

Listing 2.3. Connecting component references and services using wires
<composite xmlns="http://www.osoa.org/xmlns/sca/1.0"
targetNamespace="http://tuscanyscatours.com/"
name="bookings1">
<component name="TripBooking">
<implementation.java
class="com.tuscanyscatours.usingsca.impl.TripBookingImpl" />
<reference name="cars" target="CarPartner/Cars" />
<reference name="flights" target="FlightPartner/Flights" />
<reference name="hotels" target="HotelPartner" />
</component>
<component name="CarPartner">
<implementation.java
class="com.tuscanyscatours.usingsca.impl.CarVendorImpl" />
</component>
<component name="FlightPartner">
<implementation.java
class="com.tuscanyscatours.usingsca.impl.FlightPartnerImpl" />
</component>
<component name="HotelPartner">
<implementation.java
class="com.tuscanyscatours.usingsca.impl.HotelPartnerImpl" />
</component>
</composite>

This XML file doesn’t include any definitions for the component services. This is because the service definitions are taken from the component types of the component implementations. We’re not doing any configuration of these services, so there’s no need to mention them in the XML file. We do need to mention the component references explicitly because we’re providing wiring information for them.

References are wired to services using the target attribute of the <reference> element to specify the relative URI of the service. The syntax of this URI is a component name followed by a service name, separated by a / character. If the target component has a single service, it’s sufficient to specify just the component name. We’re using this shorthand when wiring the hotels reference to the Hotels service of the HotelPartner component.

When a reference is wired to a service, the interfaces of the reference and service must be compatible. This means that the service’s interface needs to provide all the operations in the reference’s interface, with the same input types, output types, and exceptions. The service could also provide additional operations that aren’t used by the reference. The SCA specifications describe this as a “compatible superset” relationship. For a bidirectional interface, the operations on the reference’s callback interface must be a compatible superset of the operations on the service’s callback interface, because the roles of service requester and provider are reversed when making callbacks.

If the interfaces of the reference and service are defined using the same interface type, it’s easy for Tuscany to look at the operation signatures to check compatibility. If the interfaces are defined using different interface types, one of the interface types needs to be mapped to the other interface type. (We mentioned this situation in section 2.2.2.) For example, if the reference’s interface uses interface.java and the service’s interface uses interface.wsdl, the SCA rules require Tuscany to use the Java-to-WSDL mapping defined by JAX-WS to convert the reference’s interface to a WSDL 1.1 portType and compare this with the service’s interface. In this case, the Java interface needs to be defined as remotable and isn’t allowed to use method overloading. Java data types passed as parameters or return types on the methods of the reference’s interface are converted to XML schema types using either the JAXB or SDO mapping. Chapter 9 describes data type mapping in more detail. If this interface mapping produces incompatible interfaces, or if the reference and service are defined using different interface types that don’t have a mapping between them, the reference and service can’t be wired together.

Using the target attribute on a reference isn’t the only way to specify a wire. We’ll look now at other ways of wiring references to services.

2.3.3. Wire elements

Instead of using a target attribute on the <reference> element, you can use a separate <wire> element to connect a reference to a service. The <wire> element has source and target attributes for the wire’s reference and service. For example, the wire from the hotels reference of the TripBooking component to the Hotels service of the HotelPartner component could be written as a <wire> element by making the following changes to the code in listing 2.3:

<composite xmlns="http://www.osoa.org/xmlns/sca/1.0"
targetNamespace="http://tuscanyscatours.com/"
name="bookings2">
<component name="TripBooking">
<implementation.java
class="com.tuscanyscatours.usingsca.impl.TripBookingImpl" />
<reference name="cars" target="CarPartner/Cars" />
<reference name="flights" target="FlightPartner/Flights" />
</component>
<wire source="TripBooking/hotels" target="HotelPartner" />
....
</composite>

In this version the <reference> element for hotels has been replaced by a <wire> element. A sample that uses this composite file can be found in the contributions/ usingsca directory of the travel sample. The value of the <wire> element’s source attribute is a component name and reference name separated by /. The reference name can be omitted if the component only has one reference. The <wire> element’s target attribute specifies a target service using the same relative URI notation as the target attribute of the <reference> element. Putting all this together, the <wire> element in our example connects the TripBooking component’s hotels reference (note the lowercase h) to the HotelPartner component’s Hotels service (the only service for this component).

Using the <wire> element to specify a wire has exactly the same meaning as using the target attribute of the <reference> element. Because <wire> elements aren’t part of component definitions, the wiring configuration is completely separate from the component definitions, allowing wiring changes to be made without affecting any component definitions. Another advantage of using this approach is that components can be deployed without being wired, and the wires connecting the components can be deployed separately. This provides deployment-time flexibility in how components are wired together.

So far we’ve assumed that every reference is explicitly wired to a single service. SCA also allows references to be wired automatically, wired to more than one service, or left unwired. We’ll describe these possibilities in the remainder of this section. These SCA capabilities fall into a slightly more advanced category, so it’s fine to skip ahead to section 2.4 if you just want to understand the basics of SCA.

2.3.4. Automatic wiring

As an alternative to explicit wiring using target attributes or <wire> elements, SCA has an autowire capability. This automatically wires references to services in the same composite that have a matching interface, without the need to specify <reference> targets or <wire> elements.

The following listing shows how the example in listing 2.3 could be rewritten using autowire. You can find this example in the travel sample’s contributions/usingsca directory.

Listing 2.4. Using autowire to connect references and services
<composite xmlns="http://www.osoa.org/xmlns/sca/1.0"
targetNamespace="http://tuscanyscatours.com/"
name="bookings3">
<component name="TripBooking" autowire="true">
<implementation.java
class="com.tuscanyscatours.usingsca.impl.TripBookingImpl" />
</component>
<component name="CarPartner">
<implementation.java
class="com.tuscanyscatours.usingsca.impl.CarVendorImpl" />
</component>
<component name="FlightPartner">
<implementation.java
class="com.tuscanyscatours.usingsca.impl.FlightPartnerImpl" />
</component>
<component name="HotelPartner">
<implementation.java
class="com.tuscanyscatours.usingsca.impl.HotelPartnerImpl" />
</component>
</composite>

In this version of the example, we’ve enabled automatic wiring for the TripBooking component by specifying autowire="true" on its <component> element. This means that Tuscany automatically wires every reference within the component to a service in the same composite that has a matching interface, as defined by the interface compatibility rules described in section 2.3.2. If there’s more than one matching service in the composite, the choice among them is implementation dependent. In this example, each of the three references in TripBooking has exactly one matching service, so there’s no ambiguity. If no matching services are found in the composite, an error is raised.

Automatic wiring can be a great time-saver, but it can cause problems if the composite happens to contain more than one service that matches a reference. In these cases, the automatic wiring rules might make a choice that the developer was not expecting, without any warning that this has happened!

Next we’ll look at how SCA allows a reference to be wired to more than one service or left unwired.

2.3.5. Reference multiplicity

The multiplicity attribute of the <reference> element specifies the number of wires that can be used for the reference, which is referred to as the reference’s multiplicity. The different settings are listed in table 2.1.

Table 2.1. Multiplicity settings for references with their meanings

Multiplicity setting

Meaning of the setting

multiplicity="1..1" The reference is always wired to a single service.
multiplicity="1..n" The reference is always wired to one or more services.
multiplicity="0..1" The reference is optionally wired to a single service.
multiplicity="0..n" The reference is optionally wired to one or more services.

The n in these multiplicity settings is a literal that appears exactly as shown. For example, it isn’t possible to specify a multiplicity of "1..5".

Wiring a reference to multiple services allows an implementation to make a choice at runtime between different providers of a service. For example, the CarPartner component from the example in section 2.3.2 could have the service and references shown in figure 2.7.

Figure 2.7. The CarPartner component has a reference cars with multiplicity 1..n and another reference luxuryCars with multiplicity 0..n.

In this figure, the cars reference has multiplicity 1..n, which allows it to be wired to more than one car-vendor service. This enables the business logic in the CarPartner component to select a car vendor based on price and availability at the time each car booking is made. The CarPartner component needs at least one car vendor, so the cars reference is defined with multiplicity 1..n rather than 0..n. Some rental locations also have vendors specializing in luxury cars, and the luxuryCars reference can be wired to these vendors if there are any. Some rental locations have only regular cars and no luxury cars, so the luxuryCars reference is defined with multiplicity 0..n to allow it to be left unwired. Here’s the component type corresponding to figure 2.7:

<componentType xmlns="http://www.osoa.org/xmlns/sca/1.0">
<service name="Cars">
<interface.java interface="com.tuscanyscatours.Cars" />
</service>
<reference name="cars" multiplicity="1..n">
<interface.java interface="com.tuscanyscatours.Cars" />
</reference>
<reference name="luxuryCars" multiplicity="0..n">
<interface.java interface="com.tuscanyscatours.Cars" />
</reference>
</componentType>

The multiplicity of references defined within implementations is determined by the rules for the implementation type. For Java implementations, the @Reference annotation can have a required member with a value of false to indicate that injection of the reference is optional. An array or collection used as a reference means that the reference is multivalued, with all available targets injected as elements of the array or collection. The default value of the required member is true.

See chapter 5 for more information and code examples showing how to define different multiplicities for references in Java component implementations. For components that don’t have Java implementations, each implementation type defines its own way of specifying these multiplicity settings.

We’ve shown why references with different multiplicities are useful and how they can be defined. Next we’ll look at how wiring works for different multiplicities.

2.3.6. Wiring with different multiplicities

Let’s look at how wires are specified for references whose multiplicity isn’t 1..1. We’ll illustrate these using the example wiring configuration in figure 2.8.

Figure 2.8. The cars reference of CarPartner is wired to two car vendor components: JoesCars and KensCars. The other reference, luxuryCars, is left unwired.

In figure 2.8 the CarPartner component is configured with a choice of two rental car vendors, Joe’s Cars and Ken’s Cars. This is shown by multiple wires from the cars reference of CarPartner. No vendors of luxury rental cars are available, so the luxury-Cars reference has been left unwired.

We’ll start by showing how this configuration can be defined using the target attribute of the <reference> element. The following code shows how you could write component definitions for the wiring setup shown in figure 2.8. This example can be found in the travel sample’s contributions/usingsca directory.

Listing 2.5. Wiring references with different multiplicities
<composite xmlns="http://www.osoa.org/xmlns/sca/1.0"
targetNamespace="http://tuscanyscatours.com/"
name="carbookings1">
<component name="CarPartner">
<implementation.java
class="com.tuscanyscatours.usingsca.impl.CarPartnerImpl" />
<reference name="cars" target="JoesCars KensCars" />
</component>
<component name="JoesCars">
<implementation.java
class="com.tuscanyscatours.usingsca.impl.CarVendorImpl" />
</component>
<component name="KensCars">
<implementation.java
class="com.tuscanyscatours.usingsca.impl.CarVendorImpl" />
</component>
</composite>

Multiple targets for a reference are specified using a single <reference> element with space-separated names in the targets attribute. In listing 2.5 the target attribute of the <reference> element for cars specifies two target services. It’s sufficient to just give the component names JoesCars and KensCars, because each of these components has only one service. There’s no <reference> element for the luxuryCars reference, so this reference will be left unwired.

References with multiplicity can also be wired using <wire> elements. Each <wire> element can specify only one target, so we’ll need a separate <wire> element for each target service. The following listing shows how you could rewrite the example from figure 2.8 using <wire> elements.

Listing 2.6. Wiring references with different multiplicities using <wire> elements
<composite xmlns="http://www.osoa.org/xmlns/sca/1.0"
targetNamespace="http://tuscanyscatours.com/"
name="carbookings2">
<component name="CarPartner">
<implementation.java
class="com.tuscanyscatours.usingsca.impl.CarPartnerImpl" />
</component>
<wire source="CarPartner/cars" target="JoesCars" />
<wire source="CarPartner/cars" target="KensCars" />
<component name="JoesCars">
<implementation.java
class="com.tuscanyscatours.usingsca.impl.CarVendorImpl" />
</component>
<component name="KensCars">
<implementation.java
class="com.tuscanyscatours.usingsca.impl.CarVendorImpl" />
</component>
</composite>

In listing 2.6 the <reference> element from listing 2.5 has been omitted, and <wire> elements are used instead. You can find this code in the travel sample’s contributions/ usingsca directory.

The rules for autowire are slightly different when references have multiplicities other than 1..1. If an autowired reference has multiplicity 0..n or 1..n (an upper bound greater than 1), it’s wired to all matching services in the composite. For references with a multiplicity of 0..1 or 0..n (a lower bound of 0), it isn’t an error if no matching services are found. The next listing shows the example from figure 2.8 with autowired references. This example is included in the travel sample’s contributions/ usingsca directory.

Listing 2.7. Wiring references with different multiplicities using autowire
<composite xmlns="http://www.osoa.org/xmlns/sca/1.0"
targetNamespace="http://tuscanyscatours.com/"
name="carbookings3">
<component name="CarPartner" autowire="true">
<implementation.java
class="com.tuscanyscatours.usingsca.impl.CarPartnerImpl" />
<reference name="luxuryCars" autowire="false" />
</component>
<component name="JoesCars">
<implementation.java
class="com.tuscanyscatours.usingsca.impl.CarVendorImpl" />
</component>
<component name="KensCars">
<implementation.java
class="com.tuscanyscatours.usingsca.impl.CarVendorImpl" />
</component>
</composite>

In listing 2.7 we’ve taken advantage of autowire to eliminate the need to write targets or wires. The cars reference of CarPartner will be automatically wired to both of the Cars services in the JoesCars and KensCars components because these services have interfaces matching the cars reference. You’ll notice that we’ve turned off autowire for the luxuryCars reference. This reference has the same interface as the cars reference, so the autowire rules would incorrectly wire this reference to the Cars services in JoesCars and KensCars. This is an example of the potential problems with autowire that we mentioned in section 2.3.4.

You’ve seen how references can be defined and how they can be connected to services in a number of different ways. Next we’ll look at how components can be configured using properties.

2.4. Configuring components using properties

Implementations can enable external configuration of some of the values that they use in their processing. These externally configurable values are called properties. In this section you’ll see how to define properties and how to configure values for both simple and complex property types.

Figure 2.9 shows a currency converter component with two properties.

Figure 2.9. A currency converter component with two properties, fromCurrency and toCurrency

We’ll use this component as an example to show how properties are defined and how to configure values for properties.

2.4.1. Defining properties

As with services and references, the way properties are defined depends on the implementation type. For Java implementations, the @Property annotation is used to define an SCA property. Listing 2.8 illustrates how this annotation can be used to define the fromCurrency and toCurrency properties for the currency converter component shown in figure 2.9. You can find this code in the travel sample’s contributions/ usingsca directory.

Listing 2.8. Defining properties for a component implementation

Listing 2.8 shows a service interface CurrencyConverter and a component implementation class CurrencyConverterImpl. In the implementation class the @Property annotation has been applied to the fromCurrency and toCurrency fields. When the Tuscany runtime creates an instance of CurrencyConverterImpl, Tuscany injects property values into these fields. Like references, properties can be injected using constructor parameters, fields, or setter methods.

You’ve seen an example of how properties can be defined. Next you’ll see how property values can be configured using component definitions.

2.4.2. Configuring values for properties

Property values are configured using <property> elements in the component definition. The name attribute of the <property> element identifies the property being configured. For simple property types such as strings and numbers, the <property> element’s content is used as the value for the property in the configured component.

In our example each configured component converts between a particular pair of currencies, which are specified as the values of the fromCurrency and toCurrency properties. The following listing shows component definitions that create converters from EUR to JPY and from USD to GBP. This code is available in the travel sample’s contributions/usingsca directory.

Listing 2.9. Configuring property values in component definitions
<composite xmlns="http://www.osoa.org/xmlns/sca/1.0"
targetNamespace="http://tuscanyscatours.com/"
name="converter">
<component name="EURJPYConverter">
<implementation.java class=
"com.tuscanyscatours.usingsca.impl.CurrencyConverterImpl" />
<property name="fromCurrency">EUR</property>
<property name="toCurrency">JPY</property>
</component>
<component name="USDGBPConverter">
<implementation.java class=
"com.tuscanyscatours.usingsca.impl.CurrencyConverterImpl" />
<property name="fromCurrency">USD</property>
<property name="toCurrency">GBP</property>
</component>
</composite>

The convert method of EURJPYConverter converts euros into yen, and the convert method of USDGBPConverter converts dollars into pounds. For conversions between other currency pairs, it’s easy to create additional converter components by specifying different values for the properties.

Like services and references, properties are part of the implementation’s component type. The component type for CurrencyConverterImpl looks like this:

<componentType xmlns="http://www.osoa.org/xmlns/sca/1.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<service name=CurrencyConverter">
<interface.java
interface="com.tuscanyscatours.CurrencyConverter" />
</service>
<property name="fromCurrency" type="xs:string" />
<property name="toCurrency" type="xs:string" />
</componentType>

You might be looking at this example and wondering why we don’t just define the currency codes as Java static constants. Creating a new converter would be a simple matter of changing the values of the constants and recompiling the class. There are three main advantages of using SCA properties instead of Java constants:

  • There’s only one implementation of the class. Using Java constants would require making an extra copy of the implementation class with different constant values for each different currency conversion pair.
  • Property configuration can be done without changing the code within the class. For most businesses, changing implementation code is expensive—even for a small change like this. This is why SCA provides so many facilities to adapt and change applications using external configuration rather than by modifying implementation code. The important thing isn’t the amount of code change that’s needed but whether changes can be made without needing to modify the implementation.
  • A management tool can display and change the values of SCA component properties much more easily than values within implementation code. For small applications with a few components, this may not be important. When these components become part of a larger and more complex application, it’s easy to see the manageability and configurability benefits of defining some carefully chosen properties.

 

Configurability, configurability, configurability

SCA is all about the ability to reconfigure various aspects of an application without going in and changing the code. Every feature of SCA is designed to make this easier for business developers and infrastructure developers. Tuscany provides a runtime framework for SCA that supports the same goals of flexible configuration and infrastructure extensibility.

 

We’ve shown how to define and configure properties that are simple scalars with string values. In the rest of this section we’ll show how properties can use the full power of XML schema to represent complex data structures. This is a more advanced capability of SCA properties, and it’s fine to skip ahead to section 2.5 if you just want to cover the basics now.

2.4.3. Using complex types for properties

Any XML schema complex type defined as a global element or schema type (that is, an element or schema type declared as a child of the schema root element) can be used as the type of an SCA property. Following is an example of an XML schema global element representing a U.S.-style address.

Listing 2.10. XML schema global element definition for SCA property
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://tuscanyscatours.com/">
<xs:element name="billingAddress">
<xs:complexType>
<xs:sequence>
<xs:element name="street" type="xs:string" />
<xs:element name="city" type="xs:string" />
<xs:element name="state" type="xs:string" />
<xs:element name="zip" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>

You can use this as the type of a property in a component implementation. For example, a Customer component could be implemented using Java code similar to the following:

package com.tuscanyscatours;
import org.osoa.sca.annotations.Remotable;

@Remotable
public interface CustomerInfo {
....
}

package com.tuscanyscatours.usingsca.impl;
import org.osoa.sca.annotations.Property;
import com.tuscanyscatours.BillingAddress;
import com.tuscanyscatours.CustomerInfo;

public class CustomerImpl implements CustomerInfo {
@Property
protected BillingAddress billingAddress;
....
}

The BillingAddress class that’s used as the Java type of the billingAddress property needs to be mappable to the XML schema global element shown in listing 2.10. For example, the BillingAddress class could be generated from the XML schema by using the JAXB mapping from XML schema to Java code. Listing 2.11 shows an example definition of the Customer component with a configured value for the billingAddress property. You can find all the code needed to run this example in the contributions/usingsca directory of the travel sample.

Listing 2.11. SCA configuration for property defined as global element
<composite xmlns="http://www.osoa.org/xmlns/sca/1.0"
targetNamespace=" http://tuscanyscatours.com/"
xmlns:t="http://tuscanyscatours.com/"
name="orders1">

<component name="Customer">
<implementation.java
class="com.tuscanyscatours.usingsca.impl.CustomerImpl" />
<property name="billingAddress" element="t:billingAddress">
<t:billingAddress xmlns="">
<street>123 Main Street</street>
<city>New York</city>
<state>NY</state>
<zip>01234</zip>
</t:billingAddress>
</property>
</component>
</composite>

The element attribute of the <property> element indicates that the property type is defined as an XML schema global element. The property value is an instance of this global element, appearing as a child of the <property> element.

It’s also possible to specify the property type using an XML schema type instead of a global element. This can be useful when multiple properties have the same type definition. For example, let’s suppose that the CustomerImpl component implementation is extended to contain a delivery address as well as a billing address, where both of these addresses are defined by the XML schema type shown in the following listing.

Listing 2.12. XML schema type definition for SCA property
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace=" http://tuscanyscatours.com/">
<xs:complexType name="Address">
<xs:sequence>
<xs:element name="street" type="xs:string" />
<xs:element name="city" type="xs:string" />
<xs:element name="state" type="xs:string" />
<xs:element name="zip" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:schema>

The new property deliveryAddress is added to the CustomerImpl class as follows:

package com.tuscanyscatours.usingsca.impl;
import org.osoa.sca.annotations.Property;
import com.tuscanyscatours.Address;
import com.tuscanyscatours.BillingAddress;
import com.tuscanyscatours.CustomerInfo;

public class CustomerImpl implements CustomerInfo {
@Property
protected BillingAddress billingAddress;
@Property
protected Address deliveryAddress;
....
}

The new property deliveryAddress has the Java type Address, which is mapped from the schema type Address using the JAXB mapping. The Java type of the billingAddress property is BillingAddress (as used in the previous version of the code), which works because this Java type is mappable to the property schema type Address.

Because the billing and delivery addresses are defined in XML using a schema type, their values are configured in the component definition using <property> elements with type attributes instead of the element attribute used in listing 2.11. The property values are specified using an element of the Address schema type. For example, you could define an <address> schema global element as follows:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://tuscanyscatours.com/orders"
xmlns:t="http://tuscanyscatours.com/">
<<xs:element name="address" type="t:Address" />
</xs:schema>

You can use this element to configure the property values for billingAddress and deliveryAddress. The full component definition is shown in the following listing, and the code for this example is available in the contributions/usingsca directory of the travel sample.

Listing 2.13. SCA configuration for properties defined using a schema type
<composite xmlns="http://www.osoa.org/xmlns/sca/1.0"
targetNamespace=" http://tuscanyscatours.com/"
xmlns:t="http://tuscanyscatours.com/"
xmlns:o="http://tuscanyscatours.com/orders"
name="orders2">

<component name="Customer">
<implementation.java
class="com.tuscanyscatours.usingsca.impl.CustomerImpl" />
<property name="billingAddress" type="t:Address">
<o:address xmlns="">
<street>123 Main Street</street>
<city>New York</city>
<state>NY</state>
<zip>01234</zip>
</o:address>
</property>
<property name="deliveryAddress" type="t:Address">
<o:address xmlns="">
<street>456 Market Street</street>
<city>San Francisco</city>
<state>CA</state>
<zip>98765</zip>
</o:address>
</property>
</component>
</composite>

We’ve shown how property values are specified using XML within component definitions. It’s also possible to set a property value using the value of some other property or from the contents of a file. These are described in the SCA Assembly Model specification, which is available at http://osoa.org/display/Main/Service+Component+Architecture+Specifications.

We’ve looked at all the configurability points of an SCA component: services, references, and properties. Now it’s time to look at how SCA services and references can be configured to control the wire-level protocols and endpoints that they use when they communicate.

2.5. Enabling communication flexibility using bindings

One of the most important features of SCA is its support for a wide variety of communication protocols. If your services need to talk Web Services, JMS, CORBA, RMI, or REST, they can do it using SCA and Tuscany. If they need to use some specialized or proprietary protocol to meet a particular application need, that’s fine too. Even better, your business code doesn’t need to know which protocol it’s using; the choice of a protocol is made by (you guessed it) the component’s configuration. How cool is that? The piece of SCA magic that makes all this possible is called a binding.

In the rest of this section you’ll see how to use bindings on services and references and what it means if no bindings are configured. Finally, we’ll look at the SCA domain and see how bindings relate to communication within and outside an SCA domain.

2.5.1. Configuring bindings for services and references

You can use bindings on services or references. Putting a binding on a service means that the service can be invoked using the communication protocol specified by the binding. The service implementation code doesn’t need to do anything special to make this happen; all you have to do is add the binding to the service’s configuration. Each binding has a binding type that identifies the communication technology used by the binding, such as Web Services or JMS.

For example, to make the Bookings service available as a web service, the component definition might look like this:

<component name="TripBooking">
<implementation.java
class="com.tuscanyscatours.usingsca.impl.TripBookingImpl" />
<service name="Bookings">
<binding.ws uri="http://tuscanyscatours.com:8085/Bookings" />
</service>
</component>

By adding the <binding.ws> element, you’ve told the SCA runtime that you want to use the SCA Web Services Binding to expose the Bookings service as a web service using SOAP/HTTP at the endpoint specified in the uri attribute. That’s all you need to do to create a web service. There’s no need to learn JAX-WS or to make any changes to the Bookings service’s implementation.

A service can have more than one binding. If you want to invoke the Bookings service over JMS as well as Web Services, you just need to add another binding. Here’s an example component definition showing this:

<component name="TripBooking">
<implementation.java
class="com.tuscanyscatours.usingsca.impl.TripBookingImpl" />
<service name="Bookings">
<binding.ws uri="http://tuscanyscatours.com:8085/Bookings" />
<binding.jms uri="jms:Bookings" />
</service>
</component>

The <binding.jms> element makes the Bookings service available over JMS. Again, it wasn’t necessary to learn the JMS API or change any implementation code.

Bindings provide the linkage between SCA and Tuscany and the rest of the world! The Bookings service is written in SCA and runs in Tuscany. Because this service is configured using bindings, it can be called by client code that isn’t written using SCA or running in Tuscany. For calls to the Bookings web service, the client code can be written in any language and can use any WS-I—compliant Web Services runtime. For JMS calls, the client code can be written directly to the JMS API using any JMS provider that’s compatible with the JMS provider configured for Tuscany’s JMS binding.

You’ve seen how bindings can be used on SCA services to make them available using standard communication protocols. In the same way, bindings can be used on SCA references to call non-SCA services using a standard communication protocol. In this case the roles are reversed; the client of the non-SCA service is implemented using SCA, and the non-SCA service uses some standard communication protocol and can be implemented using any technology that supports the chosen protocol. For example, the service could be a web service endpoint that supports SOAP/HTTP, or it could be an EJB session bean communicating over RMI-IIOP. To talk to a web service, the reference would specify <binding.ws>, and for calling an EJB, you’d use <binding.ejb>.

The binding.ws, binding.jms, and binding.ejb binding types are defined by the SCA specifications and are provided as part of Tuscany. If your services need to use a protocol that Tuscany doesn’t support out of the box, you can use Tuscany’s support for extension points to create a new binding type for that protocol. Chapter 14 shows an example of how to do this.

Figure 2.10 shows a diagrammatic representation of configuring bindings on a service and references of a component named TripBooking. Listing 2.14 shows an example component definition for the service, references, and bindings pictured in figure 2.10. The code for this example is available in the contributions/usingsca directory of the travel sample.

Figure 2.10. The Bookings service is configured with Web Services and JMS bindings, the cars reference is configured with a Web Services binding, and the flights reference is configured with an EJB binding.

Listing 2.14. Configuring component services and references with bindings
<composite xmlns="http://www.osoa.org/xmlns/sca/1.0"
targetNamespace="http://tuscanyscatours.com/"
name="bookings4">
<component name="TripBooking">
<implementation.java
class="com.tuscanyscatours.usingsca.impl.TripBookingImpl" />
<service name="Bookings">
<binding.ws uri="http://tuscanyscatours.com:8085/Bookings" />
<binding.jms uri="jms:Bookings" />
</service>
<reference name="cars">
<binding.ws uri="http://tuscanycars.com:8081/Cars" />
</reference>
<reference name="flights">
<binding.ejb uri="corbaname:rir:#flight/FlightPartnerHome" />
</reference>
<reference name="hotels" target="HotelPartner" />
</component>
<component name="HotelPartner">
<implementation.java
class="com.tuscanyscatours.usingsca.impl.HotelPartnerImpl" />
</component>
</composite>

You’ll notice that <reference> elements in listing 2.14 that are configured with bindings don’t have a target attribute. This is because the binding provides the destination information for the reference.

We’ve looked at how bindings can be applied to services and references. Now we’ll look at what happens for services and references that don’t specify a binding in their configuration.

2.5.2. The default binding

In listing 2.14 there isn’t a binding for the hotels reference. This means it has an implicit binding type of binding.sca (often called the default binding). The default binding is used to connect an SCA reference to an SCA service, leaving the choice of communication technology to the SCA runtime in which the reference and service are deployed. Other bindings (such as binding.ws and binding.jms) select a specific communication protocol or API that can interoperate with non-SCA code. Because of this, bindings other than the default binding are often called interoperable bindings.

Tuscany uses Web Services over SOAP/HTTP for remote calls over binding.sca; other SCA runtimes might use a different standard protocol such as RMI-IIOP, or they could use a proprietary protocol. In the future Tuscany could switch to something else for the default binding, so Tuscany applications shouldn’t assume that using the default binding means they’re getting Web Services. An application that wants to use Web Services to communicate between components should specify <binding.ws> to make sure this happens.

The default binding can be used only for connecting a reference to a service within the same SCA domain. Connections that span domain boundaries must specify an interoperable binding. The domain is an important concept in SCA, and we’ll describe it in detail in chapter 3. For now, we’ll give a brief overview of what an SCA domain is and describe how it relates to bindings and wiring.

2.5.3. Domains, bindings, and wiring

The SCA domain is a deployment and management boundary for SCA components. For example, a domain could be a single application server, a server cluster, or a group of servers or clusters. An entire domain typically runs a single vendor’s implementation of SCA.

Every SCA component is part of an SCA domain. References and services within the same domain can be connected using wires. Connections between references and services within the same domain can use the default binding because SCA guarantees that the implementation of this binding will be consistent within a domain. For communication outside the domain, references and services can’t use wires and instead must use interoperable bindings to interact with other services.

We’ll illustrate the use of domains with a scenario based on the TuscanySCATours company that we looked at in chapter 1. The company has grown, and it has created a separate division to provide a specialized hotel-booking service. This hotel-booking service is used by the TuscanySCATours trip-booking service, and it’s also available directly to customers who only want to book a hotel. The two divisions of the company use separate SCA domains to deploy and administer the services they provide: the TuscanySCATours domain for the original trip-booking service and the TuscanySCAHotels domain for the new hotel-booking service. Figure 2.11 illustrates this scenario.

Figure 2.11. Two SCA domains containing components, showing how the components are connected. Wires (shown as solid lines) are used for connections inside each domain, and bindings (shown as broken lines with arrows) are used for connections that cross a domain boundary.

In this figure, the solid lines connecting SCA components represent SCA wires, and the broken lines with arrows represent connections that use an interoperable binding instead of a wire. We’ll start by looking at the connections from the references of the TripBooking component in the TuscanySCATours domain. The flights reference is connected to a web service that makes flight bookings. This isn’t an SCA service, so the flights reference is configured with the interoperable Web Services binding and the endpoint URI of the flight-booking service. The hotels reference is connected to the Hotels service of the HotelPartner SCA component in the TuscanySCAHotels domain. Because SCA wires can’t span domains, the reference and service are connected by configuring both of them with the Web Services binding and the service’s endpoint URI. Finally, the cars reference of TripBooking is connected to the Cars service of the CarPartner component in the TuscanySCATours domain. Because the reference and service are in the same domain, we can connect them using an SCA wire and the default binding. The Cars service isn’t exposed outside the TuscanySCATours domain and doesn’t interoperate with non-SCA code, so there’s no need for it to have any interoperable bindings.

Now let’s look at the connections to the Hotels service of the HotelPartner component in the TuscanySCAHotels domain. As well as the connection from the hotels reference of the TripBooking component, there are connections from HotelBooker (a hotel-booking client application that doesn’t use SCA) and from the hotels reference of the SCA component HotelOffers in the TuscanySCAHotels domain. Because the Hotels service is configured using the interoperable Web Services binding, the HotelBooker software can use any web service client software to invoke the Hotels service. The connection between HotelOffers and HotelPartner uses an SCA wire because these components are in the same SCA domain. This wire could use either the default binding or the interoperable Web Services binding that the service provides. In this example we’ve chosen to use the default binding because this is the simplest approach for wires within an SCA domain. Another option would have been to use the Web Services binding at both ends of the wire.

It’s useful to see how the connections in figure 2.11 could be configured using component definitions. In chapter 3 we’ll cover domain configuration and composite deployment in detail; for now, the following listing shows an example of how the components and connections in the TuscanySCATours domain in figure 2.11 could be defined for a deployment configuration.

The next listing shows example component definitions for the TuscanySCAHotels domain. You can find the code for listings 2.15 and 2.16 in the contributions/usingsca directory of the travel sample.

Listing 2.15. Component definitions for the TuscanySCATours domain
<composite xmlns="http://www.osoa.org/xmlns/sca/1.0"
targetNamespace="http://tuscanyscatours.com/"
name="toursdomain">
<component name="TripBooking">
<implementation.java
class="com.tuscanyscatours.usingsca.impl.TripBookingImpl" />
<reference name="flights">
<binding.ws
uri="http://flightbookingservice.com:8084/Flights" />
</reference>
<reference name="hotels">
<binding.ws uri="http://tuscanyscahotels.com:8083/Hotels" />
</reference>
<reference name="cars" target="CarPartner/Cars" />
</component>
<component name="CarPartner">
<implementation.java
class="com.tuscanyscatours.usingsca.impl.CarVendorImpl" />
</component>
</composite>
Listing 2.16. Component definitions for the TuscanySCAHotels domain

It’s important to specify <binding.sca> as well as <binding.ws> on the Hotels service. Without this the hotels reference couldn’t be wired to the Hotels service using the default binding (binding.sca). Another option would be to put <binding.ws> on the hotels reference and omit <binding.sca> from the Hotels service.

 

What’s in a name?

In the example code in this chapter you’ve seen various names in a number of different styles such as all lowercase (toursdomain) and concatenated capitalized words with either an uppercase initial letter (TripBooking) or a lowercase initial letter (minAge). Although SCA doesn’t impose or recommend any particular naming convention, the following suggestions may be useful. The names of artifacts defined by a component (services, references, and properties) will usually follow the naming style of the component’s implementation type. For SCA artifacts (components, composites, and domains), there’s no recommended or established SCA naming convention. For XML-related artifacts (types, elements, and namespaces), the usual XML conventions apply.

 

The example in figure 2.11 shows most of the ways that SCA references and services can be connected. It’s also possible to use a matched pair of bindings to connect an SCA reference to an SCA service in the same SCA domain, as an alternative to wiring. This could be useful if an SCA reference needs to invoke an SCA service that only has an interoperable binding, and the reference and service are in the same SCA domain.

In this section we’ve described a number of options for how SCA references and services can be connected, and it’s worth summarizing these briefly:

  • To connect a reference and service in the same SCA domain, you can do any of the following:

    • Use a wire with the default binding
    • Use a wire with an interoperable binding
    • Configure the reference and service with matching bindings
  • To connect an SCA reference and SCA service that aren’t in the same domain, you can configure the reference and service with matching interoperable bindings.
  • To connect an SCA reference or service to non-SCA code, you can configure the reference or service with an interoperable binding.

Interoperable bindings enable SCA code to interoperate with non-SCA code and allow SCA code from different vendors to interoperate across a domain boundary. The default binding allows vendors to provide optimized communication where interoperability isn’t required.

2.6. Summary

We’ve shown how SCA components can have implementations of various different types. The component definition configures selected aspects of the implementation, known as its component type. The component type includes services, references, and properties. Component references and services are connected using wires, or they can be configured using bindings to specify a particular communication protocol.

These concepts provide the essential foundations for SCA that you’ll use when building applications with Tuscany. In a building, the foundations are essential but usually not exciting. The exciting part is what’s built on top of the foundations. In the next chapter, we’ll move beyond the foundations and show how to add walls, doors, windows, upper stories, and a roof! To put this in SCA terms, we’ll go on to explain how components can be composed and packaged into higher-level SCA constructs such as composites and contributions and deployed into an SCA domain using the Tuscany runtime in a local or distributed environment. With this additional information as well as the foundational concepts we’ve looked at in this chapter, you’ll have a complete overview of everything involved in building an SCA composite application. Turn the page and come with us as we continue the journey.

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

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