3. Creating services using Apache Tuscany – Open Source SOA

Chapter 3. Creating services using Apache Tuscany

In the previous two chapters, we dissected the technical underpinnings of what constitutes a service-oriented architecture, and selected a set of open source products that can be used to develop what we are calling the Open SOA Platform. Now, let's shift gears and focus, in considerable detail, on each of the selected products. As you make your way through this chapter, you'll notice that we place special emphasis on how to integrate the sometimes disparate technologies and how to best leverage the strengths of each. We'll begin this journey by looking at one of the foundational technologies behind SOA: services.

Services, as the S in SOA suggests, are instrumental in building a SOA environment. To recap, a service is a self-contained, reusable, and well-defined piece of business functionality encapsulated in code. To most people, a service is understood as simply something that's performed as part of their day-to-day job. A person at the checkout counter where you buy your milk is performing a service, after all. A software service is no different when you think about it. It's simply a routine that performs some unit of work. For example, when you encounter a problem when placing an order on some e-commerce website, the first thing that probably comes to mind is to locate the site's "Contact Us" link. This is an example of a service used to create a customer incident or problem ticket. Typically, there are multiple channels by which customers can report service problems that may include a web form, a customer service hotline, or direct contact with a sale representative. Regardless of the channel used, there ideally would be a single service that could be used to record such tickets. This would be an example of a discrete, reusable service that could be used by multiple applications (this scenario forms the basis for our examples later in the chapter).

Services are indeed the holy grail of SOA. If properly designed, publicized, and self-describing, services become assets that can be widely reused in a variety of applications. This maximizes the investment in these assets and enables creation of a more agile enterprise since every business process doesn't have to be re-created from scratch. Other tangible benefits include a reduction in maintenance costs and more bug-free applications. This chapter explores how such services can be created using the exciting new framework known as Service Component Architecture (SCA). You're probably thinking, "Not another framework!" There are already a multitude of frameworks that can be used for making web services, and a fair number oriented toward creating reusable components. The difference, as you'll soon discover, is that SCA takes a fresh approach and uses a protocol- and language-neutral design coupled with a clever way of assembling components for maximum reusability. More exciting still is the fact that this can be done entirely with an open source SCA implementation known as Apache Tuscany (http://tuscany.apache.org/)! Let's begin by taking a close look at what it means to be a service and how such services are created.

What are service components and compositions?

A service can run the gamut from a narrowly defined piece of functionality (fine-grained) to one that encapsulates a multitude of lower-level services and is thus considered more coarse-grained in scope (see the sidebar "Coarse- vs. fine-grained services"). Regardless of a service's scope, what underlies it are concrete implementations in code. Classes and methods are used to create the services that are made available to the consuming client. You can think of these classes as components, and the SCA framework provides a uniform and consistent way to develop and wire together such components, using a variety of languages.

Although the terms are sometimes used interchangeably in the literature, a distinction can be made between a component and a service, and this distinction is important for understanding SCA. A service, like a component, is a self-contained unit of functionality. However, unlike a service, a component isn't necessarily intended to be exposed for external consumption—its purpose may be limited to providing functionality within the context of the application for which it runs. A cash register at the store performs a service both for you and the attendant, but you could think of the routine used to calculate sales tax as more analogous to a component—in and of itself, its utility is limited, but when used by the register, it's a valuable part of the service offering. A "helper" in Java, which provides static methods that are used by multiple other Java classes, could be considered a component. Enterprise JavaBeans (EJBs) in the Java EE world are often considered components if they're intended for use exclusively within the application in which they were written (that is, not exposed as an external API).

In the SCA world, they add a concept that they call a composition. A composition, which itself is a form of component, is made up of one or more components. You could think of it like a Pointillism painting [Pointillism], where many small distinct points (components) combine to make a larger image (composite). You could consider a composite analogous to a coarse-grained service, as it's the product of one or more fine-grained services. Compositions themselves may even be combined to form higher-level forms of compositions. Like a component, a composite becomes considered a "service" when it's wrapped for external consumption. The benefits of building software based on the reusable building blocks of components and composites have been espoused for several decades, as we discuss next.

The Service Component Architecture (SCA) initiative, and its companion, Service Data Objects (SDO), were advanced in 2005 by a consortium of companies, including IBM, BEA, and Oracle. SCA grew out of the need to create a framework exclusively designed for developing components supported by multiple protocols and languages—a key facet of SOA. No other existing framework appeared suitable to meet this requirement. Apache Tuscany was the first open source reference implementation of this technology. For the reasons cited in chapter 2, we selected Tuscany as the component framework for our Open SOA Platform. Recently, management of the SCA and SDO standards was moved to the OASIS group, a highly respected standards organization responsible for such notable standards as Electronic Business Using XML (ebXML), Security Assertions Markup Language (SAML), and OpenDocument, among others. Of course, you're probably a bit skeptical of yet another standard, along with the supporting vendors who have less than altruistic motives in offering their support. To dispel some of these concerns, a broad interest group was established to further the development of the SCA-related standards; it's known as the Open Service-Oriented Architecture (OSOA) collaboration (this was the group initially established to promote SCA, and predates the move to OASIS—it remains unclear what impact this may have on OSOA).

Let's now explore SCA in greater detail and discover how its innovative assembly model advances the creation of services that are fundamental to a SOA architecture.

The SCA assembly model

To gain an understanding of SCA, it's useful to first take a high-level overview of what's called the SCA Assembly model. This model represents the core of the specification as it describes how services are constructed. The main ingredients of the model are shown in figure 3.1.

Figure 3.1 shows us that multiple composites can reside within a single SCA domain. What this means is that you can decompose an assembly into multiple composites, which can help you organize related functionality into logic groupings. A composite itself can contain one or more services, which are, in turn, constructed from components. A component has a concrete implementation and can reference other components or services. So, to keep the ball rolling, let's examine these concepts by looking at each part of the assembly as well as sample illustrations of how they're used. In our examples, we'll use Apache Tuscany, the open source SCA implementation that we selected for our Open SOA Platform (the README.txt file in this chapter's source code describes how to run the examples).

To demonstrate the concepts, let's partially construct a hypothetical problem ticket system using SCA. We'll start with simple constructs to illustrate the main concepts of building services and then progressively embellish the system to demonstrate advanced SCA features. Once the system is completed, you'll have a solid understanding of how to use SCA to create services—an essential ingredient for building a SOA environment.

Figure 3.1. A high-level overview of the SCA Assembly model. Configuration options are highly flexible.<br></br> 

Let's assume the following high-level requirements for our hypothetical ticket system:

  • Must be exposed as one or more services so that it can be called by a variety of different communication protocols. This includes web, JMS, and SOAP. This ability will allow the system to be "embedded" within many different applications.

  • Must accept a variety of ticket types or templates—for example, a web form for collecting issues directly from a user, or directly from application or systems monitoring solutions.

  • Must provide support for a distributed architecture to support future scaling.

  • Must provide the ability to generate real-time events on all activity. This is beneficial for integration with complex event processing (CEP) systems, the topic of chapter 8.

These obviously only skim the surface of possible requirements, but they do provide context for our examples as we move forward. If you were developing this application without SCA, you'd likely use a Spring-based framework for building it. In particular, Spring now provides excellent support for JMS and SOAP, as well as a distributed computing solution. Many other viable solutions exist as well. We suggest you think through how you'd tackle this challenge, using whatever frameworks you're accustomed to, and then contrast that approach with the SCA one we're building as this chapter progresses. We think you'll find that SCA dramatically simplifies many areas of development and, in particular, offers a refreshingly new approach for thinking about components and services.

With this use case in mind, let's start our examination of Tuscany with composites—the top-level building blocks of SCA.

Introducing the composite file

A composite is a container that's used for defining services, components, and their references. It's used to assemble SCA artifacts into logical groupings of components. For example, all operations that deal with a CRM system's customer management might be grouped together in a single composite.

Note

For those familiar with Spring, the SCA composite would be considered roughly analogous to what Spring typically calls the application context XML file, where beans are defined. The component element, described in the next section, is similar in function to the bean element within Spring configurations.

Interestingly, a composite itself may be treated as a component, which is an example of what SCA calls a recursive composition (as you may recall from earlier, multiple composites may exist within a given domain). A composite defines the public services that are made available through one of the available SCA bindings (JMS, SOAP, etc.). Figure 3.2 is an abbreviated look at the XML Schema definition for composites. Many elements, such as reference and service, can also be defined within an individual component configuration.

Figure 3.2. XML Schema definition overview for composites<br></br> 

Most composite files will likely contain one or more components, references, and often at least one service (the composite element is the root of the XML file, which is why it's sometimes referred to as a composite file). You'll learn later in this chapter and the next how to combine multiple composites within a domain to simplify maintenance or aid in classification. Figure 3.3 illustrates a distributed SCA environment setup using three virtual machines (VMs).

The top-level domain is defined using a composite that incorporates the node-specific compositions. The next chapter describes distributed SCA options and configurations.

Figure 3.3. Relationships between domains, nodes, and composites<br></br> 

The SCA specification uses a graphical notation to visually illustrate how a given composition is defined. An example that we'll build on is shown in figure 3.4.

Figure 3.4's composite shows two defined components: ProblemTicketComponent and CreateTicketComponent. The CreateTicketComponent is responsible for creating the problem ticket, whereas the ProblemTicketComponent can be considered more of a "controller" component that merely delegates its work to a dependent component. This makes sense when you consider that additional components would then be added for deleting and updating tickets. For now, the service we'll be creating is very simple—a web service used for creating new problem tickets.

How is the composite illustrated in figure 3.4 defined within the XML? Listing 3.1 shows the assembly definition (all composites have a .composite extension, which makes them easily identifiable in the source code for this chapter).

Figure 3.4. A simple composite example with two components<br></br> 

Example 3.1. SCA composite assembly XML for figure 3.4

Notice the two components elements that are defined

Note

To differentiate attributes from elements, we preface attributes with the XPath convention of using the at-sign (@). So, when you see something like binding.ws@uri, we're referring to the binding.ws element's uri attribute.

Lastly, the ProblemTicketComponent defines a dependency or reference to the CreateTicketComponent

One thing that will become apparent as we move forward is that the SCA specification offers great flexibility in how to configure the SCA assemblies. For example, in listing 3.1, the service element was embedded with the component definition

Example 3.2. Example of an SCA composite alternative configuration

The functionality of the composites defined in listings 3.1 and 3.2 is identical, but in 3.2, the service is defined separately in a stand-alone fashion

Note

Since services represent the key functionality offered by SCA, we generally prefer the greater visibility afforded them when they're defined as direct children of the root composite, as illustrated in listing 3.2.

How would you instantiate the assembly defined in listing 3.1 or 3.2? You can use different approaches, and we'll discuss them in greater detail as we move forward. The easiest way to start the assembly is to use what's referred to as an embedded SCA domain. This code fragment provides a brief illustration of how this can be done:

SCADomain scaDomain = SCADomain.newInstance("problemMgmt.composite");

In this case, assume the code in listing 3.1 was saved to a file called problemMgmt.composite. The SCADomain.newInstance method then receives that file as a single parameter and launches the domain using that assembly definition. Of course, we wouldn't get very far if we tried running this assembly—after all, we haven't actually developed the components yet! This is the topic of the next subject—components.

Configuring components

A component is a business function expressed within code. Components are, in a sense, the building blocks that constitute an application, somewhat akin to the ingredients in a recipe. Components can both provide and consume services. To be a functional unit, a component must provide an implementation that consists of the actual code used to perform the functionality. As we demonstrated in the previous section, a component can also directly specify a service by which it can be exposed for external consumption, as well as identify any references or dependencies of the component. The high-level definition of the component element is shown in figure 3.5.

As you recall from the previous section, we provided an example definition of a component. That fragment is shown here for convenience:

<component name="ProblemTicketComponent">
  <implementation.java
     class="opensoa.book.chapter3.impl.ProblemTicketComponentImpl"/>
  <service name="ProblemTicketComponent">
     <binding.ws uri="http://localhost:8085/ProblemTicketService"/>
  </service>
  <reference name="createTicket" target="CreateTicketComponent"/>
</component>

The concrete implementation for this component is performed by the class ProblemTicketComponentImpl. Let's create this class (listing 3.3) so we can illustrate what has to be done to provide the SCA component functionality (we've purposely kept our example simple to begin with).

Figure 3.5. XML Schema definition overview for components<br></br> 

Example 3.3. Java implementation for ProblemTicketComponentImpl

As you can see, there are two SCA annotations specified in the class

<reference name="createTicket" target="CreateTicketComponent"/>

Listing 3.4 contains the interface definition for the service operations implemented by ProblemTicketComponentImpl.

Example 3.4. Interface used by ProblemTicketComponentImpl

The only unique aspect to the interface class is the SCA @Remotable annotation

Tip

SCA's Java implementation doesn't require the use of annotations, such as the ones we've used in the examples so far. Instead, you can use SCA's component type file. This is covered in more detail in the next chapter.

The service operation we're exposing is defined within the createTicket method. This method takes, as its single parameter, a TicketDO object. This data object class just contains the details of the problem ticket, along with corresponding accessor methods. The member variables for the TicketDO object are

private String customerEmail;
private String customerName;
private String subject;
private String problemDesc;
private int caseNumber;

The only thing that remains to be described is the referenced component class, CreateTicketComponentImpl, which is responsible for creating the problem ticket and returning an identifier (as we pointed out previously, other components such as those used for updating and deleting would eventually be added as service operations). For now, the CreateTicketComponentImpl class's create method is a placeholder and simply returns a random identifier regardless of what is submitted to it. The class is shown in listing 3.5.

Example 3.5. CreateTicketComponentImpl reference class

Given that our sample involves several classes, let's recap the process of starting an SCA domain/server, receiving an inbound web service request for our exposed service, and creating a ticket. Figure 3.6 illustrates the steps, which are described in table 3.1.

Figure 3.6. Overview of the sample assembly we've constructed<br></br> 

Table 3.1. Description of the steps shown in figure 3.6<br></br> 

Step

Description

1

The ProblemTicketServer class starts the SCA domain/container by using the "embedded" server. It instantiates the server by specifying the composite XML file used, which in this case is called problemMgmt.composite.

2

The SCADomain class, which is part of the Apache Tuscany implementation, is used to start the embedded Jetty server. In turn, this is used to host the web service that's being exposed by the assembly's service element.

3

A web services client initiates a CreateTicket request against the hosted web service using the dynamically generated WSDL created by the web service binding associated with the service element defined in the composite. The web service SOAP request might resemble the following:

<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:chap="http://chapter32.book.opensoa/">
   <soapenv:Header/>
   <soapenv:Body>
      <chap:createTicket>
         <arg0>
            <caseNumber>10001</caseNumber>
            <customerEmail>jdoe@someplace.com</customerEmail>
            <customerName>John Doe</customerName>
            <problemDesc>This is a problem desc</problemDesc>
            <source>This is the source</source>
            <subject>This is the subject</subject>
         </arg0>
      </chap:createTicket>
   </soapenv:Body>
</soapenv:Envelope>

4

The inbound request is received by the SCA embedded server, which then delegates the processing of the request to the component implementing the service, ProblemTicketComponentImpl.

5

The ProblemTicketComponentImpl has an associated dependency created through the reference element in the component's definition XML: CreateTicketComponent.

6

The reference is injected into the ProblemTicketComponentImpl by way of setter injection. Now the CreateTicketComponent is instantiated. This class is responsible for processing the inbound problem ticket.

7

The request is processed and the results are returned to the client.

What we have demonstrated thus far is a fairly simple example of an SCA assembly. We've exposed a component as a web service and demonstrated how references to other components can be declaratively defined within the SCA assembly. Even though it's a simple example, it's worth noting that the components we've created have no awareness of what communications protocol will be used to interface with them. There's no SOAP- or web service-specific code anywhere within the component implementation class, so the component itself isn't bound directly to a specific protocol. Instead, the binding of the protocol to the component is done declaratively through the service element definition. This form of loose coupling is very appealing, because as we'll see next, we can now expose services through any number of different protocols, or bindings, without having to change any implementation code. This is truly exciting stuff!

Defining services

We've already demonstrated some of the capabilities of the service element using the problem ticket example we've been building. To recap, the service element is used to expose a component's functionality for external consumption through any number of communication protocols, such as SOAP or JMS. The consumer of the service can be another component or an external client running outside the SCA framework. An example of such a client is one using a SOAP-based web service or perhaps instead interfacing through JMS queues. The service's binding method specifies the protocol by which it will be exposed. Figure 3.7 depicts the schema definition overview for services.

In our simple example from listing 3.1 (listing 3.2 is functionally equivalent, as you may recall, but defines the services at the root composite level), we specified the service as a nested element inside the component we're exposing. The service was defined as

<service name="ProblemTicketComponent" promote="ProblemTicketComponent">
  <binding.ws uri="http://localhost:8085/ProblemTicketService" />
</service>

In the preceding code, we did not specify an @interface attribute, as the service is supporting all the available business functions. However, by using the @interface attribute, you can selectively decide which methods to expose as public operations. For example, let's assume we've created another component called ProblemTicketComponent2 (and its corresponding implementation, ProblemTicketComponentImpl2) that's the same as ProblemTicketComponent with the exception that we've added another method to the ProblemTicketComponent2 called deleteTicket. If we then add this method to the interface and run the assembly, we'll notice in the generated WSDL that two operations are exposed through this web service, createTicket and deleteTicket, as illustrated in this WSDL fragment:

Figure 3.7. XML Schema definition overview for services<br></br> 

<wsdl:binding name="ProblemTicketComponent2SOAP11Binding"
   type="ns0:ProblemTicketComponent2PortType">
  <soap:binding style="document"
    transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="createTicket">
    <soap:operation soapAction="urn:createTicket" style="document"/>
    ... wsdl input and output
  </wsdl:operation>
 <wsdl:operation name="deleteTicket">
   <soap:operation soapAction="urn:deleteTicket" style="document"/>
   ... wsdl input and output
 </wsdl:operation>
</wsdl:binding>

If we then decide that only the createTicket operation should be exposed as a web service, we can specify an interface that only includes the createTicket method, even though the implementation class ProblemTicketComponentImpl2 contains two methods. For example, we can specify the original ProblemTicketComponent as the interface, since it only contained the single createTicket method. This would result in the following component definition

<service
  name="ProblemTicketComponent2"
  promote="ProblemTicketComponent2">
  <interface.java
    interface="opensoa.book.chapter3.ProblemTicketComponent" />
  <binding.ws uri="http://localhost:8085/ProblemTicketService" />
</service>

When the WSDL is automatically generated, it will only contain the single operation, createTicket. What's interesting to note is that the interface class used doesn't necessarily have to be the actual Java interface class that was implemented by the component. Instead, think of it as simply a definition for what services will be provided by the component. You can also use the interface.wsdl and specify a WSDL to define the full or subset of the method to expose. Enforcing which operations are permitted, as defined by the method signatures of the interface class, is performed at the container level, so it's secure. The alternative approach of simply creating a custom WSDL with only the operations specified that you want exposed isn't secure, since those operations could still be invoked by someone knowledgeable of the source (as pointed out previously, this custom WSDL could be referenced as the interface, in which case it's secure).

The binding child element associated with service described earlier is discussed in section 3.2.7. The callback functionality, which can be used for creating bi-directional services, is an advanced feature and will be discussed in chapter 4. Let's now focus on how property values can be set declaratively through the XML composition into component variables. Known as SCA properties, this capability allows runtime configurations to be easily made without having to recompile or modify code.

Working with properties

Up to this point we've covered the basics of creating components and services—the building blocks of SOA. The SCA standard also provides convenient runtime configuration capabilities through properties and references. Properties, the subject of this section, are much like their namesake in the Spring framework and are used for populating component variables in an injection-style fashion (references are the topic for section 3.2.6). This is obviously useful when you have to set environment-specific values without having to resort to using an external property file. More impressively, properties can be complex XML structures, which can be referenced via XPath locations by the components using it. This adds convenience and manageability to the assembly process. Figure 3.8 displays the schema fragment associated with the Property element.

Figure 3.8. XML Schema definition overview for properties<br></br> 

We haven't previously illustrated any components that have utilized a property value, so we'll modify our ProblemTicketComponent to use some properties. In this case, let's assume that we want to pass a username and password to the component. In a real-life scenario, this may be necessary for establishing database connectivity or for accessing other types of resources (SMTP/POP3, File, etc.). In this instance, we'll create the username and password as "global" properties at the composite level (that is, created as a direct descendent of the document root element). They'll then be referenced from within the ProblemTicketComponent definition. This is illustrated in the updated composition definition shown in listing 3.6.

Example 3.6. Example of using global properties

Notice that, within the component, the global properties were referenced using the @source attribute of the embedded property element. The naming convention requires that you preface the referenced named variable using a $ sign within the @source attribute, as is shown in the listing.

As an alternative to using global properties, you could have included the property settings directly within the component element, such as

<component name="ProblemTicketComponent">
  <implementation.java
    class="opensoa.book.chapter3_24.impl.ProblemTicketComponentImpl" />

  <service name="ProblemTicketComponent">
   <binding.ws uri="http://localhost:8085/ProblemTicketService"/>
  </service>

  <property name="username">jdoe@mycompany.com</property>
  <property name="password">mypassword1</property>
  <reference name="createTicket" target="CreateTicketComponent"/>
</component>

Regardless of the approach used, the ProblemTicketComponentImpl class must be modified to capture the injected properties. This can be done most easily by just adding two new member variables along with the SCA @Property annotation:

@Property
protected String username;
@Property
protected String password;

The @Property annotations spell out that these two class variables are set as properties. Note that there's no need to create setter methods to inject these values, although they must be specified with public or protected visibility in order for this approach to work. If specifying a nonprivate access level modifier is a concern, you can use the more traditional JavaBean-style approach and use setters to instruct the container to populate the properties in this fashion. Here's an example:

private String username;
private String password;

@Property(name="username")
 public void setMyUsername(String username) {
this.username = username;
}

@Property
public void setPassword(String password) {
  this.password = password;
}

Notice that, for the username property, we created a method that didn't adhere to the standard "accessor" method style of set Variable—instead of setUsername, we used setMyUsername. Since the standard JavaBean accessor convention wasn't used, the optional @name attribute associated with the @Property reference had to be specified. Using the setter style injection can also be helpful if you want to perform additional processing after the value has been assigned (such as validation checks).

Using a Java Collection is also straightforward. For example, instead of using two properties to set the username and password, we can use a single property defined as

<property name="credentials" many="true">
  "jdoe@mycompany.com"
  "mypassword1"
</property>

Then, within the component class, it will be injected by using

@Property
protected Collection<String> credentials;

You can then access it like you would any other Collection class, such as

credentials.iterator().next()

which will return the first item in the collection, or .

More interestingly, properties can also be complex XML structures. You can then use XPath expressions to selectively identify which value you wish to populate into a given variable. For example, the following property called credentials is set to an embedded XML fragment as a global directly within the composite element:

<property name="credentials" type="hw:CredentialsType" >
   <Credentials>
     <username>jdoe@mycompany.com</username>
     <password>mypassword1</password>
   </Credentials>
</property>

To then pass the specific values associated with username and password, the following property reference can be used within the component definition:

<property name="username"
  source="$credentials/*[local-name()='Credentials']/
        *[local-name()='username']" />
<property name="password"
  source="$credentials/*[local-name()='Credentials']/
        *[local-name()='password']" />

The source attribute must be a valid XPath, as shown here; otherwise the injected reference will be set to null. The complete modified composition is shown in listing 3.7.

Example 3.7. Modified composition illustrating use of embedded XML properties

<composite xmlns="http://www.osoa.org/xmlns/sca/1.0"
  targetNamespace="http://opensoa.book.chapter3"
  xmlns:hw="http://opensoa.book.chapter3"
  name="ProblemManagementComposite">

  <property name="credentials" type="hw:CredentialsType" >
   <Credentials>
     <username>jdoe@mycompany.com</username>
     <password>mypassword1</password>
   </Credentials>
 </property>

 <component name="ProblemTicketComponent">
   <implementation.java
    class="opensoa.book.chapter3_24.impl.ProblemTicketComponentImpl" />
   <service name="ProblemTicketComponent">
     <binding.ws uri="http://localhost:8085/ProblemTicketService"/>
   </service>
   <property name="username"
    source="$credentials/*[local-name()='Credentials']/
          *[local-name()='username']" />
   <property name="password"
    source="$credentials/*[local-name()='Credentials']/
          *[local-name()='password']" />
   <reference name="createTicket" target="CreateTicketComponent"/>
 </component>

 <component name="CreateTicketComponent">
   <implementation.java
     class="opensoa.book.chapter3_24.impl.CreateTicketComponentImpl"/>
 </component>
</composite>

As you can see, there's considerable flexibility in how static property values can be injected into component classes at runtime. The next "essential" SCA technology we'll address is implementation. Implementation is how SCA provides for multilanguage support and is the mechanism by which recursive compositions are created, which is the nesting of composites to create higher-level assemblies. As you may recall from our SOA discussion in chapter 1, the ability to easily create components that are themselves composed of one or more subcomponents greatly facilitates code reuse—a key objective behind SOA.

Implementation options

The implementation node, as we've seen in previous examples, is a child element of component. It's used to define the concrete implementation for the component. In the examples thus far, we've used the Java implementation, as specified by using implementation.java. However, SCA is designed to support multiple languages. Which languages are supported is driven by the SCA implementation. Apache Tuscany, the open source SCA offering we're using, supports the following types, shown in table 3.2.

Table 3.2. Apache Tuscany SCA implementation types<br></br> 

Type

Description

Java components

We've been using Java components in the examples so far.

Spring assemblies

You can invoke Java code exposed through Spring.

Scripting: JavaScript, Groovy, Ruby, Python, XSLT

Uses JSR 223 to support a wide variety of scripting languages.

BPEL

Integration with Apache ODE for BPEL support.

XQuery

Supports Saxon XQuery.

OSGi

Supports Apache Felix OSGi implementation.

One implementation that's anticipated to be supported by all SCA-compliant products is the composite implementation. Using implementation.composite, you can construct a hierarchy of services that are layered upon each other. At the lowest level, you would presumably have finer-grained components that perform specific, narrow functions. As you move up the hierarchy, you could construct coarser-grained services that incorporate or build upon the lower-level ones. You could also wrap components that are designed primarily for one purpose and repurpose them for other users. This strategy can best be illustrated through an example, which follows.

So far, we've created a service that can be used to submit a hypothetical problem ticket. The ticket data structure used resembles that of an inbound customer service email, and contains such fields as subject, body/ description, and to. Let's assume now that someone in IT decided that it would be an outstanding idea to also generate cases/tickets for system events that occur, since they too need to be followed up on in a similar manner. Rather than build an entirely new service to perform this function, the development team decides to create a façade or wrapper service that, while using the nomenclature familiar with IT guys, really just leverages the existing problem ticket service. This new service will use a new component called SystemErrorComponent, which just calls ProblemTicketComponent under the covers. In fact, foresight would tell us that other organizations within the company will also likely be interested in similarly leveraging the problem ticket system. Figure 3.9 illustrates what is now more broadly called the Issue Management System (IMS) that supports receiving tickets from any number of sources.

To support this new capability, we'll create a new composite assembly called IssueManagementComposite that references the problem ticket assembly we created in listing 3.1. This new assembly will be constructed so that it will be the main service interface for the various interfaces, such as system IT tickets or customer service tickets. The ProblemManagementComposite will be used for the low-level create, delete, and update ticket operations, which are in turn called by those components defined in the IssueManagementComposite. Why follow such an approach? It enables us to create customized service interfaces for each of the audiences interested in using the service. This approach will lower the barrier for widespread acceptance of the system, and marketing is an important part in improving the adoption rate of SOA. Listing 3.8 shows the ProblemManagementComposite assembly we created earlier.

Figure 3.9. Overall plans for the issue Management System<br></br> 

Example 3.8. ProblemManagementComposite

<composite
 xmlns="http://www.osoa.org/xmlns/sca/1.0"
 targetNamespace="http://opensoa.book.chapter325"
 xmlns:hw="http://opensoa.book.chapter325"
 name="ProblemManagementComposite3">

 <property name="username">jdoe@mycompany.com</property>
 <property name="password">mypassword1</property>

 <service
  name="ProblemTicketService"
  promote="ProblemTicketComponent">
  <interface.java
    interface="opensoa.book.chapter3_25.ProblemTicketComponent"/>
 </service>

 <component name="ProblemTicketComponent">
   <implementation.java
    class=
    "opensoa.book.chapter3_25.impl.ProblemTicketComponentImpl" />
   <property name="username" source="$username" />
   <property name="password" source="$password" />

   <reference
      name="createTicket" target="CreateTicketComponent" />
   </component>
<component name="CreateTicketComponent">
     <implementation.java
       class="opensoa.book.chapter3_25.impl.CreateTicketComponentImpl" />
   </component>
</composite>

The new IssueManagementComposite, which is the assembly for exposing issue-specific services for generating problem tickets, appears in listing 3.9. In this example, only a single new interface was developed: for creating IT system trouble tickets.

Example 3.9. IssueManagementComposite for creating issue-specific problem tickets

Before we examine the Java code associated with SystemErrorComponentImpl

Two questions might come to mind: how do you specify the file location containing the Problem-ManagementComposite, and how does the container know which component within ProblemManagementComposite to use for injecting ProblemTicketComponent? The answer to both can be summed up, somewhat tongue-in-cheek, as "automagically." To answer the first question: the container automatically loads and parses all composite files that it finds on the classpath. Hence, it could identify where to find ProblemManagementComposite (in my example, it's in a file called problemMgmt.composite). As for the second question, a form of autowiring is performed—the SystemErrorComponentImpl is expecting a class of type ProblemTicketComponent, and through the container's parsing of the ProblemManagementComposite, it could identify a match since only a single component matched that class signature.

We can now take a closer look at the implementation of the SystemErrorComponentImpl class (listing 3.10), which is responsible for receiving an inbound system IT problem ticket request and then wraps and resubmits it to the ProblemTicketComponent service.

Example 3.10. SystemErrorComponentImpl.java

The code represents a simple component implementation and identifies the SCA service interface

Starting the SCA container can be done as you saw earlier by using the SCA embedded domain class, in which case you just specify the composite file used to initiate the desired assembly. In this case, the IssueManagementComposite was defined in a file called issueMgmt.composite, so the SCA embedded domain was started using the code shown in listing 3.11.

Example 3.11. Starting the SCA embedded domain

public class ProblemTicketServer {

   public static void main(String[] args) {

      SCADomain scaDomain = SCADomain.newInstance("issueMgmt.composite");
      try {
         System.out.println("ProblemTicket server started" +
          " (press enter to shutdown)");
          System.in.read();
      } catch (IOException e) {
         e.printStackTrace();
      }

      scaDomain.close();
      System.out.println("ProblemTicket server stopped");
   }
}

What have we accomplished in this section? We've created a new higher-level composite assembly (IssueManagementComposite) that uses the services defined within another, different composite (ProblemManagementComposite). This demonstrates how you can truly create compositions of services, which is one of the foundational objectives behind SOA. We accomplished this using the implementation.composite implementation type, which is currently supported in Apache Tuscany (in chapter 4 I'll show how other languages can be used to create concrete implementations). You also saw how we can inject, by reference, a component service that was defined in a different composite assembly. In the next section, we further examine references that, similar to properties, allow runtime configurations to be made without requiring implementation code changes. Such flexibility contributes to the agility so often touted as a major benefit of moving to SOA.

Using references for dependency injection

The SCA reference, as we've demonstrated in a variety of ways, is used to insert dependent class instances in much the same way that properties can be used to insert static data into a class. This approach was first popularized by Spring's innovative inversion of control features, which defined a form of dependency injection. SCA builds on many of the best practices of Spring while introducing some additional capabilities. The definition of the reference node is illustrated in figure 3.10.

In the assembly examples we've created so far, we've specified references directly within the component definition, such as

<component name="SystemErrorComponent">
  <implementation.java
    class="opensoa.book.chapter3_26.impl.SystemErrorComponentImpl" />
  <reference name="problemTicket" target="ProblemTicket"/>
</component>

Figure 3.10. XML Schema definition overview for references<br></br> 

However, similar to the service and property elements, the reference element can also be specified at the composite level, with the @promote attribute used to indicate what component will use the reference. This approach is generally used when you're specifying an external service that will act as the referenced object. For example, in the previous section we referenced a component that consisted of an implementation.composite to invoke a service located in another assembly. You could also accomplish this by using a reference that had a web service binding. This approach is best illustrated through an example (see listing 3.12).

Example 3.12. Using web service binding to specify a remote reference

As you can see in listing 3.12, the reference element has been removed from the component element definition

Listing 3.3 illustrated how a reference was associated with a setter method that followed standard JavaBean conventions. Similar to how properties are injected, references can also be injected either by specifying a public or protected instance variable designated with the @Reference annotation. Here's how we specified the CreateTicketComponent as a reference:

@Reference
protected CreateTicketComponent createTicket;

Using the setter approach is similar (note that we changed the instance variable to private using this approach, to be consistent with the JavaBean convention).

private CreateTicketComponent createTicket;

@Reference
public void setProblemTicket(ProblemTicketComponent problemTicket) {
  this.problemTicket = problemTicket;
}

Depending on your coding conventions, this approach may be preferred, and it does add some flexibility, as you can use the setter to perform other actions, if need be, during the time of injection.

References are one of the most powerful features of SCA, and they likely will play a central role in how you design assemblies. Let's now turn to the last of the core SCA technologies: bindings.

Defining available bindings

Bindings represent one of the most innovative and value-added aspects of SCA, for they allow you to create and reference services over a variety of communication protocols, and the underlying implementation classes are oblivious to them. Figure 3.11 shows a simplified definition for the binding element.

Figure 3.11. XML Schema definition overview for bindings<br></br> 

The supported SCA bindings, much as with implementation types, will likely vary from one SCA product to another. However, we anticipate that most SCA implementations will support a web service binding (binding.ws). The supported bindings within the Apache Tuscany project are shown in table 3.3.

Table 3.3. Apache Tuscany binding types<br></br> 

Type

Description

Webservice

Uses Apache Axis 2 as the underlying engine.

JMS

Default implementation uses ActiveMQ.

JSON-RPC

JavaScript JSON support for browser/server type connectivity.

EJB

Only stateless session beans are currently supported.

Feed

RSS feed.

We've already seen some of the capabilities of the web services binding (binding.ws), such as the ability to dynamically generate a WSDL if one isn't present. Often it's beneficial to create your own WSDL—for example, if you want to consolidate your web services into a single WSDL file instead of having a separate WSDL constructed for each exposed service. Let's consider how this can be done.

The sample application we've created has thus far involved creation of two web services. The first service was the ProblemTicketService. It's a "generic" service that eventually will be used to create cases. The second web service, SystemErrorService, is a wrapper service tailored specifically for inbound IT system tickets (as you recall, it repackages the request and resubmits it to the ProblemTicketService). Until now, we've used the WSDL autogeneration feature of Tuscany to create a WSDL for each of the two services. However, it would be preferable to create a single WSDL that incorporates both of these services. Figure 3.12 shows the custom-created WSDL.

Figure 3.12. Graphical depiction of WSDL for combined services<br></br> 

As illustrated, two separate services are defined within the WSDL, one for each SCA service we've exposed. Combining definitions into a single WSDL is often convenient as there are less definition files to manage and everything is in one place. The service definitions within the WSDL are shown here:

<wsdl:service name="SystemErrorService">
  <wsdl:port name="SOAP" binding="ns0:SystemErrorServiceSOAPBinding">
    <soap:address
      location="http://localhost:8085/SystemErrorService"/>
  </wsdl:port>
</wsdl:service>

<wsdl:service name="ProblemTicketService">
  <wsdl:port name="SOAP" binding="ns0:ProblemTicketServiceSOAPBinding">
    <soap:address
      location="http://localhost:8085/ProblemTicketService"/>
  </wsdl:port>
  </wsdl:service>

To create the single WSDL, use the two generated WSDLs and merge them together. To make the WSDL more manageable in size, separate the XSD schemas into individual files and assign them their own namespaces. Then include them using the schema include element, which results in a much abbreviated wsdl: types section:

<wsdl:types>
  <xs:schema >
    <xs:import
      namespace="http://chapter3.book.opensoa/system"
      schemaLocation="systemTicket.xsd"/>
    <xs:import
      namespace=http://chapter3.book.opensoa/issue
      schemaLocation="issueTicket.xsd"/>
 </xs:schema>
</wsdl:types>

Now, for us to use this new WSDL, it must be referenced in the service definition of our assembly. Let's modify the ProblemManagementComposite, which defines the ProblemTicketService, so that the service entry reads

<service name="ProblemTicketService" promote="ProblemTicketComponent">
  <binding.ws wsdlElement=
   "http://chapter3.book.opensoa#wsdl.port(ProblemTicketService/SOAP)"/>
</service>

Two things will likely jump out at you when reviewing this code: the wsdlElement definition and the #wsdl.port syntax. The Web Service Binding Specification [SCAWS] defines several implementation patterns for how you can dynamically reference specific portions of the WSDL. The #wsdl.port pattern accepts as its parameter <service-name>/<port-name>. So in our example we're stating that the service we want to expose for this component can be found, as shown in figure 3.13.

The definition for SystemErrorService similarly references the WSDL location for the service being exposed:

<service name="SystemErrorService" promote="SystemErrorComponent">
  <binding.ws wsdlElement=
   "http://chapter3.book.opensoa#wsdl.port(SystemErrorService/SOAP)"/>
</service>

To recap what this has accomplished: (a) we now have a single WSDL that defines both services, and this simplifies management; and (b) a single port is used, whereas previously we used a port for each service exposed (multiple ports can cause network headaches, as firewall changes may be required to support each additional port used).

One of the main benefits of SCA is that it supports introducing different protocols without having to modify the underlying components to reflect any protocol-specific configurations. The ProblemTicketComponentImpl class we developed earlier (listing 3.3) had no SOAP-specific code present, such as Axis2 classes, and yet we exposed the service through SOAP. That said, many Java shops choose not to use SOAP over HTTP internally and instead prefer JMS. In part, this is due to the flexibility inherent in JMS to support asynchronous communications (something only recently becoming more widespread in SOAP over HTTP). JMS is arguably also stronger in the areas of guaranteed message delivery, and ActiveMQ's built-in support for Apache Camel [Camel] provides powerful support for many common enterprise integration patterns.

Figure 3.13. How the WS binding service and port definition maps to the WSDL file<br></br> 

Let's demonstrate how easy it is to change protocols using SCA. You may be skeptical that this works as advertised (we must confess to being dubious at first as well), so we'll add a JMS binding to the SystemErrorService service. We chose this service because it represents tickets that can be created internally through monitoring applications, and JMS is commonly used as the communications protocol for these types of event notifications.

Adding a JMS binding as an additional service entry point for SystemErrorComponent requires three steps: (1) adding a new binding element definition to the existing SystemErrorService service, (2) adding a JMS WSDL binding, and (3) creating a test JMS client. Let's take a look at the first task.

Note

Apache Tuscany, which I'm using for examples, supports two methods of JMS binding. The first, which I'm demonstrating in this section, uses SOAP over JMS. The other uses the binding.jms type. The latter appears to be a more flexible solution insofar as configuration is concerned, but the former (which still uses binding.ws, since it uses SOAP) is easier to configure.

We can add an additional binding protocol by including another binding element within the service definition. In our example, we'll add another binding.ws element, but this one will specify a JMS queue and configuration as well as specify a WSDL wsdl.binding that has been added to support SOAP over JMS (more on this shortly). The code example in listing 3.13 demonstrates the changes.

Example 3.13. Adding a JMS as an additional binding to a service

The first binding.ws was the one added to support the JMS protocol

To test the JMS binding, let's develop a client assembly that posts messages to the designated JMS queue. This will be used to simulate a regular JMS client that interfaces with the service. Although we could do this without using SCA, the exercise is beneficial because it demonstrates how SCA can be used within a client capacity. To develop this assembly, we'll create a new component that remotely references the SystemErrorService via JMS. This reference will then be used to invoke the JMS call and return the results (the default SOAP over JMS binding supports synchronous JMS calls). The assembly for the JMS client is shown in listing 3.14.

Example 3.14. Assembly for the JMS client used to submit remote requests

The reference element injects an object into JMSComponent's jmsClient instance variable that adheres to the specification provided by interface.wsdl element

@Remotable
public interface JMSClient {
  public int systemProblem(SystemErrorDO ticket);
}

To simplify what's happening, consider the reference being injected as a remote "handle" that's provided to the local component, JMSClientImpl. The handle's interface can be defined either via a Java class or through a WSDL (in this case, we used the WSDL). If a WSDL is used, then an implementation class that adheres to the WSDL specification must be used for receiving the handle with the component class. In other words, the interface defines the contract or structure of the reference and it can be defined using either a Java class or WSDL. The implementation of that interface can be satisfied using any of the supported implementation types, such as implementation.java or implementation.spring. Listing 3.15 displays a Java component class implementation for our JMS client.

Example 3.15. JMSClientImpl component class

When the systemProblem method is invoked, it uses the remote JMS handle represented by the jmsClient variable

SCADomain scaDomain = SCADomain.newInstance("jmsclient.composite");
JMSClient jmsClient = scaDomain.getService(JMSClient.class,
  "JMSComponent");

SystemErrorDO ticket = new SystemErrorDO();
ticket.setProblem("test problem");
ticket.setSystem("test system");
ticket.setTitle("test title");
jmsClient.systemProblem(ticket);
scaDomain.close();

As previously pointed out, you're obviously not limited to using SCA to populate the remote JMS message. You can also use the ActiveMQ administrative console to submit a test messages.

To recap: We added a new binding to the SystemErrorService that enabled it to receive SOAP over JMS in addition to the SOAP over HTTP we previously set up. Then we created a JMS client using an SCA assembly for purposes of creating test requests. Adding the new JMS binding didn't result in any changes to the underlying target components. This exemplifies some of the great power and flexibility afforded by SCA. We've now covered all of the core SCA technologies and illustrated their usage.

Summary

One of the biggest challenges software developers face today is selecting the right framework. As you know, we're awash in frameworks, ranging from those used to create web applications and web services to application assembly. So there's probably a healthy dose of skepticism about the Service Component Architecture (SCA), regarding both its ability to fulfill its promise of an easy-to-use component assembly model with protocol and language neutrality as well as its vendor commitment. After all, we've seen in the past standards like Java Business Integration (JBI), which was launched with great fanfare, only to die and whither on the vine as vendor support, once so promising, quickly evaporated. Will SCA suffer from the same grim future? While my crystal ball may not always be accurate, We do think the future is bright for SCA. Why? Because SCA is the product of SOA best practices that have been learned over the past several years, and it also recognizes the heterogeneous environment in which most enterprises operate.

The SCA assembly framework, centered on the notion of components and services, nurtures a SOA mind-set of creating discrete, reusable units of code that can easily be shared and distributed. To demonstrate SCA's capability, we created in this chapter a hypothetical problem ticket service constructed of SCA components. We used Apache Tuscany, an excellent open source SCA implementation. The services we created were then exposed as SOAP-based web service over both HTTP and JMS. The code used to build the components was completely oblivious to the underlying protocol used when exposing it as a service. This is very exciting stuff, and means that as an architect, you don't have to worry about locking yourself into having to select up-front a single protocol or language. The power and flexibility of SCA also became apparent as we created higher-level compositions that consisted of lower-level components. We used Spring-like "inversion of control" dependency injection to configure the classes at runtime with dependent classes or properties.

While this chapter has covered the core SCA functionality, there's much more to learn about SCA, and we'll dive into some of the more advanced features in the next chapter.