One of the keys to understanding Celtix Enterprise is understanding service-oriented architecture. Service-Oriented Architecture (SOA) is the next generation of software development methodology. It takes the concepts behind procedure-oriented design and object-oriented design and moves the layer of abstraction one step further away from the implementation details of a piece of atomic functionality. In doing so, it encourages the design of applications using loosely coupled units of functionality.
It also builds on the concepts used to create distributed applications such as CORBA. Specifically, it uses an XML-based grammar for defining abstract interfaces. The interfaces define the messages passed between service and consumer using XML Schema. By using XML-based types, service definitions make no assumptions about how the service is implemented.
The fundamental ideas behind service orientation are not new. One of the longest standing goals of software design is reusability. To achieve this, software languages and software design paradigms have evolved that encourage the compartmentalization of functionality. Functionality is grouped together into small, reusable units that can be used independently of the application for which they were originally intended. This not only makes them reusable, but also increases the ease with which large applications can be updated because a change to one unit of functionality does not necessarily require changes to the whole application.
The first leap forward in the quest for reusability was the move from line-by-line programming languages like BASIC to procedural languages like Pascal and C. These procedural languages brought about the procedure-oriented design paradigm. Software began being designed as collections of reusable procedures each of which performed discreet pieces of functionality.
The next leap forward was the arrival of object-oriented programming languages like C++ and Java. Object-oriented languages, and object-oriented design, made re-usability easier by introducing the concept of an object as an atomic unit of functionality. In this paradigm, an object exposes a well-defined interface that can be called on by other objects that need the object’s functionality. Because an object is a self-contained entity and because its interface is well-defined it is highly reusable across many applications.
As the code used to write applications became more modular and reusable, applications were being broken up into pieces that were distributed across many machines. For example, an application that allows bank tellers to make withdrawals and deposits is broken into a client and a server portion as shown in Figure 1.1, “Distributed Bank Application”. The server portion may also be broken up into several separate parts.
Breaking applications into multiple parts and distributing them across multiple platforms presented a new set of reusability problems. Early distributed applications were designed so that all of the parts were tightly coupled. The messages used to communicate between them were passed using proprietary formats. Often there were dependencies on specific networking hardware and protocols. One result of this tight coupling is that pieces of functionality can not be reused because it is difficult to integrate these islands of functionality. For example, if a bank had two systems that needed to do credit checks, each system would need to implement that functionality because they used different messaging styles or different networking technologies.
Many attempts have been made to solve the reusability and integration problems posed by distributed application development. Some early solutions include CORBA, DCOM, MOMs, and large EAI servers. Each of these solutions got parts of the problem right, but never solved the entire problem. CORBA and many EAI solutions increased interoperability and reusability by providing abstract, implementation neutral definitions of atomic units of functionality that could be used as a contract between parts of a distributed application. MOMs increased interoperability by defining the interaction between parts of a distributed system by the messages that are exchanged.
None of the solutions really solved the problem because they, like object-oriented programming languages, did not provide a way of breaking the dependencies that bound all the parts together. CORBA required that all of the distributed objects be CORBA objects. EAI servers required resource heavy central hubs and proprietary networking solutions. MOMs required that all of the parts used a particular messaging infrastructure that often required specific APIs to be used.
SOA breaks the chains of dependency by borrowing from the best ideas of all other paradigms. From object-oriented programming, SOA borrows the idea of atomic units of functionality with a well defined interface. From CORBA and EAI solutions, SOA borrows the idea of an implementation neutral interface definition language. From MOM, SOA borrows the idea of defining applications by the messages they exchange. The result is the concept of a service.
A service is a unit of functionality defined by a set of message exchanges that are expressed using an implementation neutral grammar. A service, unlike an object, is an abstract entity whose implementation details are left largely ambiguous. The only implementation details spelled out are the messages the service exchanges. This ambiguity, coupled with the requirement that the messages be defined by an implementation neutral grammar make a service highly reusable and easy to integrate into a complex system.
Using services, you can define applications based on business requirements and not worry so much about the details of how the functionality is implemented. This is SOA. For example, you may need a unified application to generate customer billing for a telecommunications company that provides VoIP, cellular, and traditional phone services to its customers. The biggest stumbling block to this is that each department has implemented their billing system using a different technology as shown in Figure 1.2, “Separate Billing Systems”. Because none of the technologies were designed to be interoperable and none of them expose a common interface, building a unified billing client is a major integration headache. It can be solved using traditional means, but the solution involves either adding an expensive EAI product in the middle or developing a custom integration layer.
However, you can define a service that represents the functionality of all three billing systems as shown in Figure 1.3, “Billing Systems in SOA”. This service only requires one message exchange: the user sends the customer’s account number and the service returns the bill. You now have a common interface through which a unified billing client can access all three systems. This makes developing the client much simpler, will not require as much maintenance, and will make it easier to migrate the billing systems to newer platforms if there is a business need. This approach is also much easier for a business level person to understand and express, thereby making it easier for an IT department to understand the requirements.
The disconnect between SOA and real world applications is that a service is just an idealized representation of an implemented set of functionality. The implementation is still bound to the dependencies of hardware, languages, and networking protocols that go along with using computing resources. Several key technologies have emerged to bridge the gap between a service and the implemented functionality that it represents. Among these are XML and HTTP.
XML is the language that allows SOA to exist. It provides the grammar used to describe services, it provides the type system used to describe the data passed by services, and it provides the most common format used to package the messages used by services.
Web Service Definition Language (WSDL) is an XML grammar standardized by W3C to describe services. Using WSDL you define all of the abstract portions of a service including the elements that make up the messages exchanged by the service. You then map the abstract messages exchanged by the service to a concrete payload format that is used on a network. You also define a physical endpoint by which the service can be accessed.
XML Schema is the default type system for defining the messages used by a service. Because XML Schema is a standardized XML grammar it is platform neutral and does not make any assumptions about how the messages are going to be processed. It also allows for the creation of complex messages that are built up from reusable pieces.
Simple Object Access Protocol (SOAP) is an XML-based message protocol standardized by the W3C. It defines an XML envelope for wrapping messages and a data model for encoding information in an XML document. SOAP is the most common, but not the only, concrete message format used by services. Because it is XML based, SOAP is platform independent. In addition, it is widely used.
Hypertext Transfer Protocol (HTTP) is the most common network protocol used in SOA. This is largely due to the fact that it is nearly ubiquitous. HTTP is the protocol used to connect the World Wide Web and is based on an entirely open set of standards. Its ubiquity and openness make it a perfect backbone for connecting distributed services.