Service Component Architecture
Service Component Architecture (SCA) is a framework for solving one of the most basic issues relating to building distributed SOA applications. Imagine you have an external application that exposes itself as a callable service. You now wish to write a new application that calls the external service. How do you go about doing this? You could look at how the external application is to be called and you will find that it will be likely be Web Services, JMS, MQ, REST, EJB or some similar technology. You could then code your new application using the correct API and all will work. Well … it will work for a time. You have introduced a hard dependency here. You have bound your application to a specific protocol and associated endpoint for the remote application you are calling.
If the nature of the service provider application changes such as its location, its communication protocol or its parameters, then the service caller will also need to be reworked. This means that the coupling between the caller and the provider is tight. Given that it is our desire to be loosely coupled and agile to change, maybe we can do better.
At its most simplistic level, SCA provides an abstraction between a service caller and a service provider. The service caller doesn't actually care about how the provider is called only that when it is time to invoke the services of the provider that the provider is then called. SCA provides just such a loose coupling. Instead of the service caller invoking the service provider directly, the service caller asks SCA to invoke the service provider. In turn, SCA then makes the actual call to the service provider using the the configured protocol, endpoints and parameters. At first glance, this doesn't appear to solve any problems … but if we look closer we something wonderful has happened. The service caller which is customer written logic now no-longer needs to know mechanical information about the service provider. Instead, the caller asks SCA and SCA does the work on behalf of the caller. At the SCA level, the binding of protocols and endpoints are configured at a very high level without coding. Importantly, if the details of the service provider change, the service caller application (which if we remember, is business logic) is unaffected. Only the binding details at the SCA level need to be reworked.
The question now becomes one of how to actually use this SCA concept. I'll start by saying that SCA is rich in function. This means that there is a lot of stuff in there. However, try not to let the Boeing 747 cockpit array of levers and switches deter you from realizing the benefits. We will take it slowly and carefully and expose the parts that are needed as when we need them.
Let us start with what SCA actually is from a product perspective. SCA is a runtime framework that separates callers from called services. A caller no longer calls the target service directly but instead asks SCA to call the service on its behalf. To achieve this a "proxy" is put in place of the target service. This proxy is configured with the actual knowledge of how to invoke the real target service. The proxy is identified with a name. When the caller wishes to invoke the target service, it asks SCA to invoke the target by passing in the name of the proxy. We have thus decoupled the caller from the target service provider.
Somewhere the rubber must meet the road and some definitions have to be made. SCA asks for these definitions as an XML document that describes/declares the definitions. The format of the XML is defined as an XML Schema and conforms to an SCA specification called the Service Component Definition Language (SCDL). Thankfully, this XML is merely an academic part of the story as we will never see it. I explain it here only for your understanding. The SCA XML is (for our discussion purposes) interpreted at run time. When a caller says that it wishes to invoke a service with a name of "XYZ", the SCA runtime will parse the XML looking for the definition of "XYZ". This definition will include such things as what protocol to use to connect to the back-end service, where the service is located and a host of additional (an optional) attributes.
I mentioned that we will never have to work with the SCA XML directly, so how then do we describe the environment we wish to achieve to SCA? The answer to this is to use the IBM development environment called Integration Designer (ID). Integration Designer is a full IDE previously called WebSphere Integration Developer (WID). It is based on Eclipse and looks familiar to other Eclipse based products.
Within ID, we create modules which are really projects. Each module contains a description of a single SCA environment, the piece parts that are to be integrated and details of how those parts are configured together. The description of the SCA environment is called the Assembly Diagram. ID provides a dedicated editor for creating and modifying the contents of this diagram. Imaginatively, the editor is called the Assembly Diagram Editor. Using this visual editor the relationship between components can be wired together. As you may have already guessed, the diagram is basically a visual representation of the SCA XML document that is used to control SCA operations. The Assembly Diagram Editor is rich enough that users need never edit the raw XML files by hand. In fact, ID goes out of its way to hide those from you so that all you ever see is the assembly diagram.
The Assembly Diagram can be opened from the module view.
Once opened, a drawing canvas can be seen which shows the diagram area:
This is the mechanical aspect of working with SCA, now we turn our attention to the things that can be wired together on that canvas. Experience has taught me that this can be one of the more subtle concepts to get across, so we will take our time here.
Within the SCA story there are basically two types of things that can be described. One type is code that will actually run on and within IBPM. This includes BPEL processes, Java code, and a variety of other goodies we have not yet had a chance to discuss. To help set the scene, imagine that we want to code a fragment of Java that will execute inside IBPM and that we want this Java code to call an external service. The Java code will be written and contained inside what SCA calls a component. A component is a unit of thing that is self contained and acts as a place holder for its implementation. From an SCA perspective, a finite set of SCA component types are available.
Specifically, these are:
We won't go into details on each of the component types here. Instead, there will be much written on them in subsequent sections. For now, let us simply realize that components are building blocks in the SCA diagram.
As an illustration, let us look at a Java Component. When added to the canvas area, it looks as follows:
Each of the component types has a unique icon associated with it.
Every SCA component has a name that is unique to the module in which it lives. In this example, the component is called
MyJavaComponent. On the Assembly Diagram, the visual box that is the component can be thought of as a container or holder for its actual content. We can drill down into a component to see what is inside it. In this instance, if we open it up, we would see Java code. If we had a BPEL process, we would see a BPEL process.
Now we get to take the next leap. Imagine that we have create a number of component on our Assembly Diagram where each component has a discrete and self contained purpose. This is not yet a solution … what we would have created would be a set of building blocks that we could construct our solution from. To build the solution we would need to connect the building blocks together to perform a bigger task.
For example, if we had a component that charges a credit card and we had a component that receives a customer order, we may wish for the order processing to invoke the services of the credit card charging. To describe this to SCA, we can draw wires from one component to another. This is illustrated in the next diagram:
It is important to understand that at the SCA layer, we are not describing flow control. Instead what we are saying here is that the component called CustomerOrder can (if it chooses) call another component called ChargeCreditCard. We are not saying that it will, must or does … simply that if it wants to, it can. Going further, the CustomerOrder component may invoke a service (another component) that ships product to a customer. The assembly for this may look like:
SCA Interfaces and References
Every SCA component is capable of being invoked (called) by another. This means that the component has to be able to describe what it is capable of doing and what it expects as input should it be called. Consider a component that charges a credit card. What does it expect as input? These inputs are not prescribed by the caller, they are prescribed by the implementation of credit card processing function or service. An example of input might be:
These parameters are not negotiable. In order to use the cried card service, they must be provided. This can be thought of as a contract between the credit card service provider and anyone who may want to call it. Another analogy may also help to make this concrete. In the Java programming language there is a concept called a Java Interface. The Java Interface describes the methods and parameters of those methods as well as the return types. The Java Interface does not describe how the methods are implemented … that is up to the Java programmer to decide. The Java Interface does however describe the relationship between a calling Java Class and an implementation of a class that conforms to the Interface.
This latter example is close to what we find in SCA. Every component in SCA exposes an Interface that describes the operations that can be requested of it. Each operation describes its expected input parameters and the nature of the parameters returned. It needs to be quickly states that the Interface is not described as Java … that would be too low level. Instead the interface is described in a (arguably) complex language called WSDL (Web Services Description Language). However … IBPM ID hides the WSDL from you and exposes a full function interface description editor that removes all the complexity.
Let us review what we know so far. When we want to create an SCA component, we will build an interface that abstractly describes the contract that the component will expose which will include one or more operations. Each operation will have one or more input parameters and return zero or more output parameters. When we create an SCA component, we define the type of component that it is (eg. Java, BPEL, Mediation) and we associate an interface with that component. When we finally get around to implementing the component, both the type and the interface associated with it will govern the nature of the implementation.
In the Assembly Diagram, the purple circle on the left with the capital letter "I" contained within is used to represent the interface possessed by the component. If we hover the mouse over the interface a pop-up appears showing us the name of the interface implemented by the component.
The interface that a component provides is like a socket and a reference that connects into that component is like a plug. If we sit and think about this for a while, an elegant and important concept comes to mind. Since one component provides an interface and another component that wishes to call the first provides a reference, unless both components agree on the same description of the interface it is impossible for the two components to be wired together accidentally. SCA enforces this desirable policing.
To wire two components together, the Assembly Diagram Editor allows us to draw a visual link between the two components.
This clearly illustrates to us the relationship between them.
There is one further idea here that I want to bring to the surface. When a component wishes to invoke another component, the calling component sends the request not to the other component directly, but instead passes the request to its own local reference. At this point, SCA kicks in and the Assembly Diagram is consulted. Whatever a components reference is wired to is where the request will be sent. This means that the calling component is loosely coupled to the component that provides the service. At any time, the developer can rewire the relationship between a service caller and a service provider to point to a different service (with the same interface) and this will be honored. Another way of saying this is that calling SCA component has no idea at development time who, what or where the request will be delivered to. All it sees is the contract advertised through the interface. This is SOA in its ultimate form.
The SCA Import Component
So far we have touched upon one SCA component calling another where both components are hosted inside the SCA framework. In practice, this is rarely sufficient. Most solutions involve services that are hosted outside of a single SCA environment. For example, there may be a service that processes credit card billing that is exposed as a Web Service somewhere else in your organization. You may want to perform a ZIP code lookup which is owned by an external agency. The service you are calling may be hosted by CICS on a mainframe or accessed via WebSphere MQ. Simply calling from one SCA component to another inside the SCA environment is not sufficient. Fortunately, SCA comes to our aid yet again with an additional concept called the SCA Import. The SCA Import can be thought of as a proxy for communicating with a service that exists outside of our local environment. On the Assembly Diagram, it looks as follows:
Notice its distinctive icon. Just like other SCA component, the SCA Import exposes an interface definition. This means that it can be wired as another component's SCA reference. Unlike other components, the SCA Import does not have a native implementation. Instead, when it is called, it is responsible for building a network request in a specific format and protocol and transmitting that request to the external system. When a developer adds an SCA Import to the diagram they are also responsible for binding that component to an external system. Putting it another way, the act of binding performs the following:
There is much more to be said about the SCA Import component. Each of the different protocol types has its own story and parameters and these will be described later but for now it is sufficient to understand that the SCA Import is a proxy to a real external service. Once again we see that through the loose binding of SCA wiring with its interfaces and references, the caller has no idea that the request is going external. When the caller sends its request, that request surfaces at the reference and depending on how the developer has wired the diagram, the request will flow to the target component. If that component happens to be an SCA Import, then the configuration of the SCA Import will be honored and the request transmitted externally to the target. If at some later date, the target changes location or other nature, the SCA Import need only be reconfigured and all will be well. The business logic of the caller need have no knowledge of changes to the target. Again, a perfect "separation of concerns".
The choice of name for the proxy has always caused confusion. Why is it called "Import"? The relatively simple answer is that we are importing the services of an external provider. More on this naming later after we speak about SCA Exports.
The SCA Export Component
There is one further SCA component that we must address before we go too much further. This component is called the SCA Export. From a diagraming perspective, it looks as follows:
Again, note its distinctive icon. The purpose of the SCA Export is to expose an entry point into a module so that an external caller can invoke the logic contained in the module. We have already seen that an SCA assembly can be used to wire together various pieces of function to achieve a business goal but we have skipped the idea of how the components contained within the diagram are initially started. Components contained in an SCA Assembly Diagram are not exposed to be called directly from outside the diagram. What happens inside the SCA diagram is private (from the callers). To allow external access, we insert an SCA Export component. Just like other components, it has an interface associated with it. It is this interface that is exposed to the outside world. In addition to having an interface, the SCA Export always has a reference attached to it which is of exactly the same type as its exposed interface. This reference can then be wired to other down-stream SCA Components.
Similar to the SCA Import, the SCA Export acts as a proxy. When it is configured by the developer, it declares a communications protocol (Web Services, MQ, SOAP etc) that it is willing to listen upon. When the module containing the diagram is deployed for execution, the module is examined looking for export components. For each one found, the runtime automatically starts listening for incoming requests. When a request is received, a new instance of the module is started and control is given to the component to which the export is wired.
Once again we see loose coupling at work. An SCA component has no idea who has called it, only that it has been called. This means that the export component hides from other SCA components the details of how a request was received. A diagram can have multiple SCA Exports. Each different export could be bound to a different protocol allowing the business function as a whole to be exposed through a variety of technologies.
When we started the discussion of SCA we quickly found that components have interfaces and may have references. Both of these are described using Interface descriptions. It was also mentioned that the interface descriptions are themselves WSDL files under the covers. Now it is time to look at how an interface is described to SCA.
In a module, each interface defined is a named entity. When created or opened, the interface has its own editor called the Interface Editor.
When we create a new Interface from scratch, a wizard page is displayed to us that looks as follows:
Within this page, we can enter the name that we wish to give the interface. This name combined with its namespace must be unique. Once a new interface has been created or an existing interface opened, the Interface Editor is shown.
The editor shows two primary sections. One is an Interface section that shows the nature of the interface as a whole while the second section shows the operations exposed by that interface. Each operation is a possible entry point into the component described by the interface. When initially created, the interface has no operations defined to it. We can add operations by clicking on the add operation buttons:
When an operation is defined, the properties for the operation can be changed.
Once the operations have been defined and any changes made, the interface may be saved. Saving an interface results in the actual WSDL file that the interface represents being written. Again, under the covers the interface is described in the deeply technical WSDL language but yet we need never look at the interface from that perspective. In the vast majority of cases, we need only ever work with the Interface through the logical perspective as shown through the Interface Editor. Only the runtime execution cares that an interface is actually a mechanical WSDL file.
When we add a new SCA component onto the Assembly Diagram canvas, it has no interface or references associated with it. If we hover the mouse over the component, a pop-up appears from which we can add and select the interfaces we wish:
SCA Business Objects
When we looked at SCA Interfaces, we say that each operation in the interface may have multiple input and output parameters and that each parameter has a data type associated with it. The list of data types available include the usual suspects including strings, integers, floating points, dates, times etc. However, it is extremely common to want to create our own complex data types. These complex data types are collections of named fields which themselves have their own data types. For example, a customer will commonly have an address. We could create parameters on our interface for each of the expected items such as street, city, state and zip code but this is not as convenient as creating a single parameter that represents an address as a whole.
In SCA, these complex and structured data types are called Business Objects. Within the ID tooling, we can create our own named Business Objects and give them fields with names and data types that we desire. Under the covers, the Business Object is physically represented by an XML Schema Definition file but, just like with interfaces and WSDL, ID provides an elegant editor to hide this technical detail from us. The end result is an editor called the Business Object editor that provides all the capabilities we desire while at the same time hiding from us deeply technical constructs that in the majority of times, we have no use for.
Similar to Interfaces, Business Objects are first class entities and exist in the Data Types folder.
When a Business Object is created, a wizard allows us to enter its key characteristics. Core amongst these are the name of the Business Object (BO).
When the wizard completes for a new BO or if an existing BO is opened, the BO Editor is shown:
The BO editor shows a container (the BO type) into which the fields of the BO may be defined. Each field added can be given its own name and data type.
Fields can themselves be typed for other BOs and can also be typed as arrays of data. Once a data type is defined, that data type can be used within an SCA Interface definition:
One of the primary purposes of SCA having Business Objects is to provide a normalized format of data passing between components. In addition, when raw physical data is received at an SCA Export, that data is parsed and a corresponding Business Object is constructed and passed forwards. This insulates other SCA components from having to concern themselves from the physical format of data sent by a service requestor. Conversely, when an SCA Import call is made and a parameter is a Business Object, the Business Object's data is serialized into a suitable physical format for outbound transmission. The Business Object's normalization of data moving around inside the SCA world make all of this possible.
SCA Event Sequencing
The idea of event sequencing is to ensure that requests that arrive in a given order are processed in that order but only when this would make a difference. If it doesn't matter what order the requests are processed in, they can be executed in parallel. Consider for example two requests that arrive in order. The first request creates a bank account and the second request deposits $100 in that account. If these two requests are attempted to be executed in parallel, it is conceivable that the action to add $100 may take place before the creation of the bank account has completed.
Next consider a debit of $50 from one account and a credit of $75 to a different account. Since these accounts are different and there is no relationship between the requests, the activities can happily execute in parallel.
SCA Event Sequencing can be used to examine the data in an incoming request and, based on the content of that data determine if the request should be held until previous requests have completed or whether the request is eligible for immediate start.
Event Sequencing is enabled at the SCA diagram level. By selecting an interface on a component and then selecting an operation, we can add a quality of service and one of the options is Event Sequencing.
Once an Event sequencing quality of service has been added, we can then define the properties for this attribute:
Here we define the parameters used as input of the service and the XPath expression to the field or fields that are to be used for sequencing.
The underlying implementation of Event sequencing is based on a number of WAS supplied applications and resources. Specifically:
SCA Store and Forward
SCA was an invention of IBM and some of her competitors. It was designed to provide interoperability between a variety of SOA players. SCA has become an industry standard and has undergone a variety of iterations. IBM's WebSphere Application Server provides an implementation of SCA as part of the base product, however, this is not the same SCA as is currently found in IBPM.
Installing an SCA Module through scripting
After having built an SCA module, we can export it as an EAR file for deployment. The deployment of the EAR can be accomplished through wsadmin style scripting. The command called "
AdminApp" can be used to work with EAR applications. Full details of using this command can be found in the WAS InfoCenter.
AdminApp.install('<Path to EAR>')
An example of the output of the installation looks like:
wsadmin>AdminApp.install('C:/temp/SCAInstall.ear') ADMA5016I: Installation of SCAInstallApp started. CWLIN1002I: Creating the WebSphere business integration context CWLIN1000I: Extracting the .ear file to a temporary location CWLIN1007I: Initializing the WebSphere business integration context CWLIN1005I: Performing WebSphere business integration precompilation tasks CWLIN1001I: Compiling generated artifacts CWLIN1006I: Performing WebSphere business integration postcompilation tasks CWLIN1004I: Creating an .ear file from the temporary location CWLIN1008I: Cleaning the WebSphere business integration context ADMA5058I: Application and module versions are validated with versions of deployment targets. ADMA5005I: The application SCAInstallApp is configured in the WebSphere Application Server repository. CWWBF0028I: Process components of SCAInstallApp have been successfully configured in the WebSphere configuration repository. ADMA5005I: The application SCAInstallApp is configured in the WebSphere Application Server repository. ADMA5081I: The bootstrap address for client module is configured in the WebSphere Application Server repository. ADMA5053I: The library references for the installed optional package are created. ADMA5005I: The application SCAInstallApp is configured in the WebSphere Application Server repository. ADMA5001I: The application binaries are saved in C:\IBM\WebSphere\AppServer\profiles\ProcCtr01\wstemp\Script13b19bdc42d\workspace\cells\win7-x64Node01Cell\applications\SCAInstallApp.ear\SCAInstallApp.ear ADMA5005I: The application SCAInstallApp is configured in the WebSphere Application Server repository. SECJ0400I: Successfully updated the application SCAInstallApp with the appContextIDForSecurity information. ADMA5005I: The application SCAInstallApp is configured in the WebSphere Application Server repository. ADMA5005I: The application SCAInstallApp is configured in the WebSphere Application Server repository. CWSCA3013I: Resources for the SCA application "SCAInstallApp" are being configured. CWSCA3023I: The EAR file "SCAInstallApp.ear" is being loaded for the SCA module. CWSCA3017I: Installation task "SCAModuleTask" is running. CWSCA3017I: Installation task "Resource Task for SCA Messaging Binding and EIS Binding" is running. CWSCA3017I: Installation task "Resource Task for SCA Messaging Binding and JMS Binding" is running. CWSCA3017I: Installation task "SIBus Destination Resource Task for SCA Asynchronous Invocations" is running. CWSCA3017I: Installation task "EJB NamespaceBinding Resource Task for SCAImportBinding" is running. CWSCA3017I: Installation task "SIBus Destination Resource Task for SCA SOAP/JMSInvocations" is running. CWSCA3017I: Installation task "Deployment Task for JaxWsImportBinding and JaxWsExportBinding" is running. CWSCA3014I: Resources for the SCA application "SCAInstallApp" have been configured successfully. ADMA5113I: Activation plan created successfully. ADMA5011I: The cleanup of the temp directory for application SCAInstallApp is complete. ADMA5013I: Application SCAInstallApp installed successfully. ''
After making changes through this command, remember to call:
to save the configuration changes.
Once installed, the application can be seen from the WAS admin console. Applications installed through scripting are initially in the stopped state:
There are times where we want to know what SCA is doing behind the scenes and one way to achieve that is to switch on tracing. To switch on WAS level tracing, we need to know which WAS trace flags we wish to enable.
SCA Cross Component Tracing
When we think of an SCA module, we should realize that it can span many processes and threads. As such, log information from it may be scattered throughout a log file over time and with multiple identifiers. Obviously, this can make examination of such data quite difficult. IBM has overcome this problem with a concept called "Cross Component Tracing". The high level idea behind this is that we can enable Cross Component Tracing (called XCT) on a per SCA application basis. When that application then runs, efficient log information is then written either to trace or the System Console which contains enough information for the flow through an SCA module to be visualized.
Here is an example of cross component trace for a given SCA module. We can see the entry and exit from each of the components in the assembly including their start and end times.
From an instrumentation standpoint, there is nothing new that need be injected into the SCA module to enable this. This makes it available to be "switched on" in a production environment without the need for any kind of new application deployment (which might not be allowed in such a production environment).