Software Development Magazine - Project Management, Programming, Software Testing |
Scrum Expert - Articles, tools, videos, news and other resources on Agile, Scrum and Kanban |
Click here to view the complete list of archived articles
This article was originally published in the Winter 2008 issue of Methods & Tools
Service Components & Compositions
Jeff Davis, http://www.manning.com/davis/
This article is based on Open Source SOA (http://www.manning.com/davis/), to be published in April 2009. It is being reproduced here by permission from Manning Publications (www.manning.com). Manning early access books and ebooks are sold exclusively through Manning. Visit the book's page for more information.
In the previous two excerpts from the forthcoming Manning Publications book Open Source SOA, we dissected the technical underpinnings of what constitutes a service oriented architecture (SOA), and selected a set of open source products that can be used to develop what we are calling the OpenSOA Platform. The remaining chapters from the book then begin a detailed examination of how to use these products, and perhaps as important, how to integrate them into a comprehensive solution. This excerpt is from Chapters 3 and 4 of the book and examines how to develop service components and combine them, when appropriate, to form service compositions. The open source product used for this is Apache Tuscany, which is an implementation of the Service Component Architecture (SCA), a standard now being shepherded by the OASIS group with support by many leading vendors such as IBM and Oracle.
Services, as the “S” in SOA suggests, are instrumental in building an SOA environment. What is a service? It is a self-contained, reusable and well-defined piece of business functionality encapsulated in code. Services are indeed the “holy grail” of SOA. If properly designed, publicized and self-describing, they 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 does not have to be re-created from scratch. Other tangible benefits include a reduction in maintenance costs and more bug-free applications.
This excerpt from chapters 3 and 4 will describe, at a high-level, the main concepts around SCA and its related standard, Service Data Objects (SDO). The complete chapters found in the book provide extensive code samples to buttress the concepts presented in this excerpt.
The Service Component Architecture
The SCA initiative, as its charter, defines a model for creating, assembling, and deploying service components using heterogonous technologies. This addresses the “S” in SOA. As part of its features it includes an XML-based declarative model for describing how components are assembled and how dependencies between components are linked together. It includes a binding model that allows for different types of communication protocols to be used when exposing a component as a service. Lastly, through its policy model, advanced infrastructure services such as security, transactions and reliable message can be defined.
SDO, a companion to SCA, is a specification for a language neutral, XML-based data model intended to facilitate the exchange of data between systems and applications. It offers several unique features, including: support for disconnected datasets, which uses change logs to identify modifications; an API for dynamically or statically constructing datasets; and built-in metadata support so that a dataset can be interrogated “on-the-fly” to understand its structure and format. The API is designed to facilitate tooling, and some vendors are already moving in that direction. SCA implementations such as Tuscany have placed special emphasis on integrating SDO as the preferred data exchange format.
Armed with this general overview of the OSOA technologies, we will now explore SCA in greater detail, and discover how its innovative assembly model advances the creation of services that are fundamental to an SOA architecture.
Understanding the SCA Assembly Model
The SCA Assembly model represents the core of the specification – it describes how services are constructed. The main ingredients of the model are shown in Figure 1
Figure 1 SCA Assembly Model
As figure 1 illustrates, multiple composites can reside within a single SCA domain. A composite can contain one or more services, which are, in turn, created by components. A component has concrete implementation, and can reference other components or services. In order to further demonstrate these concepts, let’s examine each part of the assembly and provide sample illustrations of how they are constructed. Let’s begin by looking at composites, which form the foundation for SCA assemblies.
Composites
A composite is a container that is used for defining services, components and their references. It is used to assemble SCA elements 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. 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 though one of the available bindings (JMS, SOAP etc). Most compositions will likely contain one or more components, references and often at least one service. Property values are useful for inserting default values into component classes, or for configuration options that can be declaratively defined (such as JDBC connectivity parameters, for example). Let’s take a look at the parts of a composite, starting with the most basic building block, the component.
Components
A component is business function expressed as code. Components both provide and consume services. To be a functional unit, a component must provide an implementation that represents the actual code used to provide the functionality. As we discussed 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. How is a component defined within a composite? Listing 1 depicts a simple example of a problem ticket service that is comprised of two components: ProblemTicketComponent and CreateTicketComponent.
Listing 1 Example SCA composite assembly XML
<composite xmlns="http://www.osoa.org/xmlns/sca/1.0"
targetNamespace="http://opensoa.book.chapter3"
xmlns:hw="http://opensoa.book.chapter3"
name="ProblemManagementComposite">
<component name="ProblemTicketComponent"> |#1
<implementation.java
class="opensoa.book.chapter3.impl.ProblemTicketComponentImpl" />
<service name="ProblemTicketComponent"> |#2
<binding.ws
uri="http://localhost:8085/ProblemTicketService"/> |#5
</service>
<reference name="createTicket"
target="CreateTicketComponent"/> |#3
</component>
<component name="CreateTicketComponent"> |#4
<implementation.java
class="opensoa.book.chapter3.impl.CreateTicketComponentImpl"/>
</component>
</composite>
Notice the two components elements that are defined. The ProblemTicketComponent ([#1]).is exposed as a SOAP-based web service by the embedded service element ([#2]) that is present. In addition, the component defines a dependency/reference to the CreateTicketComponent ([#4]) by virtual of the child reference ([#3]). A dynamic WSDL is being generated by the service element, since an actual WSDL was not specified (one of the features of SCA). The WSDL location would be: http://localhost:8085/ProblemTicketService?wsdl, as that is the binding.ws@uri attribute ([#5]).
What listing 1 demonstrates is how a component can be exposed a web service (ProblemTicketComponent). In turn, this component uses the services of another component, the CreateTicketComponent. This should give you some idea of how components can be defined and used with SCA (the book chapters provide the actual Java implementation used for each component, and how they are setup for use by SCA). What should be noted is that there is no SOAP or web service specific code anywhere within the component implementation class, so the component itself is not 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 lose 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!
Services
We have already demonstrated some of the capabilities of the service element using the problem ticket example introduced in the previous section. 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 of the SCA framework. An example of such a client could be one using SOAP-based web services or perhaps depositing a message into a JMS queue.
Properties
Up to this point we have shown the basics of components and services -- the building-blocks to SOA. The SCA standard also provides convenient run-time configuration capabilities through properties and references. Properties, the subject of this section, are much like their namesakes in the Spring framework, and are used for populating component variables in a setting injection-style fashion. This is obviously very useful where environment-specific values need to be set without having to resort to using a external property file. More impressively, properties can be complex XML structures, which in turn can be referenced via XPATH locations by the components using it. What does a simple example of a property definition look like? Listing 2 shows a simple usage of a property embedded within a component definition:
Listing 2 Example of properties used within SCA component definition
<component name="ProblemTicketComponent">
<implementation.java
class="opensoa.book.chapter3.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>
As the book discusses, there are many different ways by which properties can be used. In listing 2, the Java implementation class ProblemTicketComponentImpl would simple have specified a member variable of the same name as assigned to the property in order to receive its value.
The next “essential” SCA technology we will address is implementation. It is how SCA provides for multi-language 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 comprised of one or more sub-components greatly facilitates code reuse, which is a key objective behind SOA.
Implementations
The implementation node, as we have seen in previous examples, is a child element of component. It is used to define the concert implementation for the service. In the examples thus far, we have used the Java implementation, as specified by using implementation.java. However, as we have pointed out, 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 are using, supports the following:
Table 1 Apache Tuscany SCA Implementation Types
TYPE |
DESCRIPTION |
Java Components |
We have been using Java components in the examples thus 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 impelemtation. |
One implementation that is anticipated to be supported by all SCA-compliant products is the composite implementation. Using implementation.composite. you can construct a hierarchy of services which are layered upon each other. At the lowest level you would presumably have finer-grained components that perform very specific, narrow functions. As you move up the hierarchy, you could construct more courser-grained services that incorporate or build upon the lower-level ones. You could also wrap components that are designed primarily for one purpose and re-purpose them for other users.
References
In SCA, reference are somewhat analogous to properties in that they allow run-time configurations to be made without requiring implementation code changes. In the case of references, you insert dependent class instances in much the same way that properties can be used to insert static data into a class. Such flexibility contributes to the agility so often touted as a major beneficiary of moving to SOA. In listing 1 we demonstrated a simple use of a reference called createTicket. This inserted a reference, or handle, to the CreateTicketComponent and made it available to the ProblemTicketComponent. In chapter 3 in the book, it shows multiple ways in which references can be used.
References are one of the most powerful features of SCA, and they likely will play a central role in how you design assemblies. We will now turn to the last of the core SCA technologies – bindings.
Bindings
Bindings truly represent one of the most innovative and value-added aspects of SCA, for it allows you to create and reference services over a variety of different communication protocols, all-the-while the underlying implementation classes are oblivious to it. Table 2 lists the protocol bindings that are available through Apache Tuscany.
Table 2 Apache Tuscany SCA Bindings
TYPE |
DESCRIPTION |
Webservice (SOAP) |
Based on Apache Axis, which is one of the most popular SOAP engines available. Known for its high performance, standards-compliance and architecture (<binding.ws/>). You can expose components as service or using binding for referencing. |
JMS |
Tested using Apache ActiveMQ, which has become the most popular JMS solution available (<binding.jms>). Can be used for services and references. |
JSON/RPC |
This support for Javascript’s JSON protocol is useful when crafting solutions that use a web browser interface (<binding.jsonrpc/>). RPC-style support is available through Ajax binding (binding.ajax). JSON binding exists for the service level only (not reference). |
EJB |
Enables SCA components to access existing stateless session beans (<binding.jms/>). Reference support only. |
Feed (Atom, RSS) |
Service support for RSS (<binding.rss/>) and Atom (<binding.atom/>) newsfeed protocols. |
RMI |
Support for Java’s Remote Method Invocation protocol for service or references (<binding.rmi/>). |
As you can see, there is an ever-growing list of protocol bindings.
Advanced SCA Features
You should now have a sense of the capabilities offered by SCA, and with the code examples provided in Chapter 3 of the book, would possess sufficient knowledge to begin using SCA within your own organization. However, there are many advanced features of SCA that are described in much greater detail in Chapter 4. A brief summary of these advanced features follows.
Component Types
While in this except we have not demonstrated the specific implementation classes used for the SCA components we have discussed, suffice it to say that SCA leverages the Java annotation features that first appeared with the Java 1.5 release. SCA introduces its own set of annotations which make it very simple to define references, services, properties etc. Within your own environment, you may not always have ready access to modify existing legacy code to include such annotations. Or, perhaps, your coding standards frown upon annotations. In any event, SCA does provide an alternative known as Component Types that act an alternative to annotations.
To use this capability, you create what is known as a component type XML file for each class/object that you are working with, and give the file name a .componentType extension, located in the same classpath location as the source object. Listing 3 is an example of such a file:
Listing 3 Example of a Component Type XML descriptor file
<componentType
xmlns="http://www.osoa.org/xmlns/sca/1.0"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<service name="ProblemTicketComponent">
<interface.java
interface="opensoa.book.chapter41.ProblemTicketComponent" />
</service>
<reference name="createTicket">
<interface.java
interface="opensoa.book.chapter41.CreateTicketComponent" />
</reference>
<property name="username"
type="xsd:string" />
<property name="password" type="xsd:string" />
</componentType>
The service and reference nodes identify the interface classes used for each. When using annotations, these would be defined within the implementation classes directly using the @Service and @Reference annotations. In a similar fashion, the @Property is normally used to indicate which class variable or method is used to receive inbound properties in lieu of specifying it within a component type file.
Conversations
Although best practices suggest that services be made stateless, as this has immediate advantages in scalability, in practical terms, this is not always feasible, or desired. What is an example where we might want a stateful service? In the example we are building, we will be using Salesforce.com SOAP-based web services. Salesforce’s API, like many, requires that you first call a login service with your provided username and password. If successfully logged-in, you are returned a sessionId that must be used in subsequent calls. The sessionId will become invalid after some period of inactivity (2 hrs), however, and has to be refreshed. Retrieving a sessionId is an expensive operation, and can be relatively slow, so fetching a new one for each-and-every call is not advisable. SCA supports 4 types of conversation scopes:
- COMPOSITE. All requests are dispatched to the same class instance for the lifetime of the composite. The example above with the sessionId is this type of scope.
- CONVERSATION. Uses correlation to create an ongoing conversation between a client and target service. The conversation starts when the first service is requested, and terminates when an end operation is invoked.
- REQUEST. Similar to a web servlet request scope, whereby a request on a remotable interface enters the SCA runtime and processes the request until the thread completes processing. Only supported by SCA clients.
- STATELESS. The default – no session is maintained.
Chapter 4 provides examples of each of these conversational scopes, and it is likely that you will encounter the need for such an ability as you begin to use SCA in non-trivial type implementations. Another somewhat related technology is a callback.
Callbacks
Callbacks are a form of bidirectional communications whereby a client requests a service and the provider or server returns back the results by “calling-back” the client over a given interface or operation. It is considered an asynchronous form of communication because the server does not return the results through its synchronous reply, as most commonly exemplified by web services or RFC-style communications. Callbacks are often used when the processing time required to fulfill a request is unpredictable or slow.
What is an example of how it might be used in the examples we’ve been building thus far? Let’s say that we want to capture all create ticket events so that they can be fed into a business activity monitoring (BAM) dashboard that executives would monitor. For example, they might want to be apprised of any unusual spikes in ticket creation activity. To illustrate this, let’s create a new component that is called in an asynchronous fashion, and this component would, in real life, send an event to the BAM or complex event processing system. We do want to ensure that the BAM system was able to process the event successfully, so we will use a callback that just indicates whether the message was processed correctly.
Callbacks are a fairly advanced feature, and like conversations, require a fair amount of explanation that falls outside of the scope of this excerpt. However, it is important you understand such an ability exists if you are currently evaluating the merits of SCA.
Production Deployment
By default, Tuscany includes a built-in Jetty engine for surfacing the bindings that we have been using thus far (such as web services). In most production scenarios, however you will likely use a servlet containers such as Apache Tomcat, at least for exposing HTTP-based services such as SOAP. In part, this is because, by using the embedded container, each domain would require its own dedicated IP port. It is easier to use a servlet container, as you can run multiple domains within that single instance (the book describes setting this up in detail). You can also mix containers/domains in a distributed fashion, as is illustrated in figure 2.
Figure 2 Example of a distributed SCA architecture
In this example, an embedded domain is used to house a JMS service, which then references a component running within a separate domain running within Tomcat. This gives you a sense of the flexible, distributed capabilities inherent in the SCA architecture.
Scripting Language Support
One of the main selling points of SCA is that it supports multiple languages (the particular SCA implementation, such as Apache Tuscany, determines which individual languages are supported). The days are likely past when an organization is entirely homogenous in their selection of programming languages. In particular, scripting languages such as Python, Perl and Ruby have become increasingly popular. Their agile development cycles and, in some cases, simplified language structures have contributed to their success. Thus, supporting multiple languages is becoming a requirement for enterprises adopting SOA. Tuscany’s SCA reference implementation supports the following scripting languages: JavasScript, Groovy, Ruby, Python, XSLT and XQuery. Once you’ve created the script using one of the aforementioned languages, you then define the component’s implementation by identifying the script file location (notice the tuscany namespace). For example
<component name="EmailServiceComponent">
<tuscany:implementation.script script=
"opensoa/book/chapter4/impl/Email.rb"/>
</component>
In this example, a Ruby script is being called. Because Java annotations cannot be used by most scripting languages, a component type file is required if you wish to pass references or properties to the script. The last advanced topic of SCA we’ll cover is its companion specification, Service Data Objects (SDO).
Service Data Objects
SDO is designed to simplify working with complex, XML-based data structures, such as a purchase order or invoice. Upon first examination of SDO, an inevitable question often arises – how is this binding technology different than the multitude of others that exist, such as Castor, JiBX, XMLBeans or JAXB? To be honest, it does share many characteristics with these technologies, but offers extended functionality that does not exist in those binding solutions. Specifically, it was designed to support “off-line” processing, where changes to the dataset are automatically captured into change summaries that indicate any new, modified or deleted data. SDO also supports a rich set of metadata which allows the client to retrospectively examine the “data graphs” for their structure and form. Last but not least, SCA was designed to work seamlessly with SDO, and this becomes apparent when working with more complex XML structures.
SDO, like the other XML binding technologies mentioned, has a variety of different configuration options, and these are addressed in Chapter 4 of the book. In that chapter, we describe how a top-down approach can be used, whereby a complex data structure is first defined using XML Schema. From there, the follow steps are demonstrated:
1. How to develop and run an Ant target using XSD2JavaGenerator to generate Java classes from the WSDL XML schema definition.
2. How to create a new a new service interface and implementation that uses the new SDO generated classes.
3. How to create a client composition and components so that we can submit test SOAP requests.
Upon finishing chapter 4 in the book, you will have a solid understanding of how SDO can be used in-tandem with SCA for creating non-trivial services. This concludes our summary coverage of the advanced features of SCA and SDO.
Summary
The Service Component Architecture initiative, which is sponsored by a virtual “who-s who” of vendors, offers a framework for building reusable, multi-language, components that can be exposed using a variety of communication protocols. In this excerpt from Chapters 3 and 4 from the forthcoming Manning Publications book Open Source SOA, we provided a brief overview of the main elements of SCA assembly model, including composites, components, services and references. We also touched upon some of the advanced features such as conversational services and callbacks. While some of these features may not be immediately used by newcomers to SCA, any widespread SCA rollout will likely involve them to some degree. Other exciting capabilities we described were how to use languages other than Java to create and consume services. The ability to use increasingly popular languages such as Ruby is a real selling point of SCA.
The complete chapters in the book provide greater coverage of core and advanced features, and are illustrate with numerous code samples. Follow-up chapters build upon the foundation of SCA/SDO to create complex business processes; expose business rules as services; and monitor, in real-time, your enterprise pulse through event stream processing.
Methods & Tools Testmatick.com Software Testing Magazine The Scrum Expert |