Friday, January 19, 2007

Fun Facts to Know And Tell: Java Business Integration

For over a year I worked with a team of developers on a project to expose feature-rich multi-modal communications capabilities to business process automation. The systems engineers probably had their own description of what the product did, but that's how I thought of it, and it was a darn good idea. One of the frameworks we built on top of was ServiceMix, Apache's open source enterprise service bus (ESB) based on the Java Business Integration (JBI) 1.0 specification.

There are times I'd like to claim to be a specialist, but my resume suggests otherwise. For sure, I am not a specialist in web services. So when duty called for me to become the local ServiceMix and JBI expert, I approached it more from a real-time messaging perspective than a Web Services perspective. This article describes some of the surprises I had in store.

Most of these fun facts to know and tell are about JBI and would probably apply to any ESB that was JBI-compliant. A few of them are about ServiceMix specifically. None of them have anything to do with the actual product that we developed.

Our development began with ServiceMix 2.0, progressed to ServiceMix 3.0 for our commercial release, and proceeded to test with ServiceMix 3.0.1. The core portion of ServiceMix that implements the JBI spec was quite stable and usable in the releases we chose to use, particularly considering the relative immaturity of the product. Like all active open source projects, ServiceMix is a moving target. Depending on what specific Subversion trunk of ServiceMix you decide to use, your mileage may vary.

In the sections below I cite the appropriate portions of the JBI spec for your reference.

Service Engines vs. Binding Components [4.3, p. 14]

The JBI spec, and most JBI presentations, seem to make a big distinction between a JBI bus component which is a Service Engine (SE) versus a component which is a Binding Component (BC). I find this to be mostly a conceptual distinction, depending on how you choose to think about the components that you develop for your application. The JBI API is exactly the same no matter what you call your component. (Former colleague Rick Block suggested that early in the development of the JBI spec this was not the case.)

I think of an SE as a component that encapsulates the implementation of some service and accepts requests and generates responses for that service only over the ESB, using JBI normalized messages inside JBI message exchanges. It may maintain internal state about the service it provides. An SE might front-end a database used to maintain inventory. It might be a JBI wrapper for a legacy service like weather information. It might be an abstract interface to a vastly complex system sitting outside the ESB. It might do something dirt simple like return the time of day from a central clock.

I think of BCs as purely protocol converters that serve as gatekeepers between the outside world and the ESB. A BC serves as a proxy between an external client that sits outside of the ESB and an SE that sits on the the ESB. If the BC maintains state, it is only about the transactions that are in progress between the outside client and the SE, or, in JBI-speak, about message exchanges that are in the active state. Once a Message Exchange reaches a terminal state like done or error, the job of the BC for that particular transaction is completed. A BC might convert between external clients using the Java Message Service (JMS) and internal services using JBI messaging. A Simple Object Access Protocol (SOAP) router on the ESB that receives SOAP requests from external web services clients (like your web browser), turns them into JBI message exchanges, and routes them to an SE on the ESB, is also a kind of BC.

This is fuzzier than you might think, and discussions over whether a component is an SE or a BC can quickly devolve to how many angels can dance on the head of a pin. For example, suppose you had a component that incorporated a SIP protocol stack to implement complex VOIP control capabilities. You can think of this component as a container of all the SIP endpoints with which it will ever communicate, and the service it provides is a set of high-level communications capabilities. In this sense, it is an SE. You can also think of it as a complicated protocol converter between SIP endpoints that speak only the SIP protocol and SEs on the ESB which speak only JBI messages. In this sense it is a BC.

In general, don't agonize too much over whether your component is a Service Engine or a Binding Component. In practice, the distinction isn't terribly important from a purely JBI point of view, although it may be important from an architectural point of view for your application. Separating BC and SE functionality makes your application more flexible if you can design it such that just by adding a new BC you can expose your SEs to a whole new domain of external clients, like SNA systems.

Services vs. Endpoints [5.1.1, p. 21]

I think of JBI as a fractal collection of containers: the JBI container (in our case, ServiceMix) contains JBI components. Each JBI component contains zero or more services. Each service contains one or more endpoints. Messages on the JBI ESB may be addressed to a service or to an endpoint within a service.

For example, a time service on the ESB might be a single service with a single qualified name (a service name within a specific namespace). But that time service might expose multiple endpoints, one endpoint for any of several NTP servers, and each with an endpoint name unique within that service. Requests for time could be addressed to the time service itself, in which case the selection of which NTP server to use is left up to some other mechanism, or it could be addressed to a specific endpoint, so that the time would be provided by a specific NTP server. The JBI spec says that if you addresses a request to a service, the choice of endpoint is implementation dependent; in this case, it really means your implementation when you code the service.

Because every service must have at least one endpoint, I sometimes use the terms service and endpoint interchangeably, but as we will find out when we discuss routing, the distinction is important.

Providers vs. Consumers [5.1.1, p. 21]

Given my background in real-time messaging, I really struggled with this JBI nomenclature, and it turns out to be vitally important to understand the distinction. I am used to thinking of messaging components has having the roles of producer and consumer, as in a message producer is that which sends the message, and a message consumer is that which receives the message. These are strictly roles played during a specific message exchange, so a single messaging component may be both a producer and a consumer at different times.

In JBI, provider and consumer are also roles played during a specific message exchange, as in a service provider provides a service, and a service consumer makes a request of the service provider. In this context, the service consumer may never receive a message at all (other than, in JBI, getting a done back from the service provider to indicate the request was successfully received) and a service provider may never send a message (other than sending the done, which carries no payload). As above, a single component may be both a service provider and a service consumer. In receiving a request from a consumer it may act as a provider, but in servicing that request it may act as a consumer by making requests of other providers. Once I got my head around this fact, things got a little easier.

A service provider must activate an endpoint on the ESB. The endpoint is one means through which messages exchanges are addressed to the service provider. (More on this later.) Once it does this, it has exposed its endpoint to receive message exchanges from service consumers. If a component does not activate at least one endpoint, it cannot act as a service provider, because service consumers have no way of addressing message exchanges to it. If a component never acts as a service provider, it need never activate an endpoint on the ESB. It can still address message exchanges to service providers, send those exchanges on the ESB, and receive responses. But no other component on the ESB can originate a new message exchange and send it to that consumer because the consumer is effectively invisible on the ESB.

The pipe through which components on the ESB send and receive (or accept, in JBI-speak) message exchanges on the ESB is the delivery channel. Think of the delivery channel as a socket and you won't be too far off. The JBI container gives each component on the ESB a delivery channel. When a consumer sends a message exchange to a provider over the delivery channel, the message exchange only contains the address of the service and endpoint exposed by the provider that were used by the consumer to address the message exchange. There is no standard JBI mechanism for the provider to query what consumer sent the message, and in fact it isn't even meaningful to ask the question. Since the consumer isn't required to activate an endpoint on the ESB, it has no address to which new message exchanges to it may be addressed.

Of course, the JBI container knows to whose delivery channel to send any response the provider may generate, but this is hidden inside the implementation. And of course, the consumer may also play the role of provider, expose an endpoint on the ESB, and send the address of this endpoint as part of the payload it sends to in its request. But from the point of view of the JBI container, this is the address of a provider on the ESB, not of the consumer that send request.

Because there is one delivery channel per component, but a component may expose many services and endpoints to which message exchanges may be addressed, I like to think of components as sending requests, and as the endpoints inside the components as receiving requests. But this is just my way of thinking.

Routing [5.1.7, p. 26]

Message exchanges may be addressed three ways: to a service (implicit routing), to an endpoint within a service (explicit routing), and to an endpoint reference (dynamic routing). When I described my example of a time service fronting several NTP servers, it probably occurred to you that there might be perfectly legitimate reasons to do either implicit or explicit routing, and you would be quite right.

Suppose your application was a hybrid of a Service Oriented Architecture (SOA) and an Event Driven Architecture (EDA). A client component acting as a consumer could make requests of a server component acting as a provider, and those requests would be addressed using implicit routing, that is, with just the service name of the provider. If the request for was for an event stream, the client component could provide a service and a specific endpoint to which those future events would be addressed by the server component. When the server component sends an event it would be acting as a consumer, sending an event to the client who was now acting as a provider, and those events would be addressed using explicit routing, that is, using both the service and the endpoint. (I never said this was simple, but it does illustrates how important it might be to get your nomenclature about roles straight in your mind.)

For example, a client component might sent a request to the server component "Lassie" to "look after Timmie", and pass along the service "Mom" and the endpoint "in the kitchen". In the future, should circumstances warrant, "Lassie" would send events like "Timmie fell in the well" to "Mom" "in the kitchen". The events could have been addressed just to "Mom", but this would require the underlying implementation to resolve the specific endpoint, searching "in the barn", "in the kitchen", and "in the bedroom", and it might pick the wrong one. (For purposes of compliance with any hypothetical non-disclosures, any resemblance of "Mom" and "Lassie" to an actual product is purely coincidental.)

Dynamic routing is a completely different animal, which is discussed in the following section.

Dynamic Endpoint Reference [5.4.4, p. 36] [5.5.4.1, p. 50, Listing 4]

Dynamic routing allows a component to be addressed using a fragment of XML that complies with a schema documented in the JBI spec. The schema is specified using Relax NG. This allows components to specify "call back" addresses for future message exchanges as part of, for example, their XML payloads inside of a JBI normalized message. This could have been used in the example above with for "Mom" to have specified the service and endpoint to which "Lassie" would send future events. Such addresses in XML form are referred to as endpoint references (EPR), and the mechanism through which such EPRs are resolved is called dynamic endpoint reference.

Here is an example of an XML fragment that might be an EPR.

<jbi:end-point-reference
xmlns:jbi="http://java.sun.com/jbi/end-point-reference"
xmlns:martin="http://farm.martin.us/jbi"
service-name="martin:Mom"
endpoint-name="InTheKitchen"
>

In this example, the service name is "Mom", the namespace is "http://farm.martin.us/jbi" which is associated purely within the context of this EPR with the XML tag "martin", and the endpoint name is "InTheKitchen".

If your application supports dynamic routing and EPRs, it is up to you to write the code to parse this XML and determine what service and endpoint, if any, it identifies. Dynamic endpoint reference resolution isn't rocket science. A component gives an XML fragment to the JBI container and asks what service and endpoint it identifies, expecting to get either null or a service endpoint object in return. ServiceMix simply queries every component on the bus that has activated endpoints, passing it the same XML fragment, in effect asking "Is this yours?", and expecting either a null or a service endpoint in return. I wrote a simple XML parser using the Java Document Object Model (DOM) framework to do just this.

You might think that would be the end of it. But you would be wrong.

It turns out there are a lot of third-party JBI components out there that expect to use dynamic routing and EPRs, but whose XML fragments do not conform to the JBI spec. One such component is Intalio's implementation of the Business Process Execution Language (BPEL). (We reported this as a bug, so in all fairness this may have been fixed by now.) Intalio chose to format their service name and namespace using a very commonly used but non-standard form known as the James Clark format. Here is an example.

<jbi:end-point-reference
xmlns:jbi="http://java.sun.com/jbi/end-point-reference"
service-name="{http://farm.martin.us/jbi}Mom"
endpoint-name="InTheKitchen"
>

Note that the namespace is part of the value of the service name attribute and not an XML namespace at all. So I modified my DOM parser to handle this format as well.

And you would still be wrong.

It turns out that ServiceMix itself exposes a managed bean (mbean) for each component on the ESB through which a query can be made and a EPR string identifying that component returned. And indeed, this EPR does not conform to the JBI spec either. Here is an example.

<jbi:end-point-reference
xmlns:jbi="http://java.sun.com/jbi/end-point-reference"
xmlns:martin="http://farm.martin.us/jbi"
jbi:service-name="martin:Mom"
jbi:endpoint-name="InTheKitchen"
>

Note that the "jbi" namespace XML tag is prepended to the service name and endpoint name attributes. Maybe this is a valid variation (my XML books suggest it is not), but the DOM framework does not recognize it. So once again I modified my DOM parser to handle this variation as well.

Thus far things are quiet on the EPR front.

send vs. sendSync [5.5.2.1.3, p. 43]

Initially, the messaging operations send versus sendSync seemed pretty straightforward. The former is asynchronous: a component could send a message exchange and go on its merry way doing other work, and any further response regarding that message exchange would be handled in the future when the exchange arrived on the component's delivery channel. The latter is synchronous: the component is blocked on the sendSync until the far end responds in whatever way is appropriate for that message exchange. These were familiar messaging patterns to the real-time developer in me.

I have to admit, as a long-time real-time developer, I don't believe in synchronous message passing, even though it is the backbone of a lot of web services messaging frameworks like Axis. In thirty years of building message-based systems, I haven't found synchronous messaging to result in scalable, high-volume, robust systems, although it sure does simplify the coding. Having a really cheap, scalable thread implementation makes it more palatable. Several Java-based frameworks and containers help out in this regard, too. But synchronous messaging makes me nervous in a deadlock is really possible unless we are very very careful kind of way. Since I have a track record for producing successful, mission critical, 24x7 products, the thought that one design mistake might cause the whole shebang to go toes up makes me a little nervous.

But with JBI, I discovered one really good reason to use synchronous messaging. When using asynchronous messaging, JBI does not require that order is preserved, and ServiceMix certainly does not guarantee it. That is, when using asynchronous messaging, the order in which one component sends message exchanges may not be the order in which the provider receives them.

The UDP datagram socket developer in me said "Oh, yeah, sure". The real-time embedded messaging developer in me clutched his chest, seized, and has not been heard from since. I had made the mistake of thinking of JBI as a real-time messaging system, like any number of others I had used over the years. But while JBI looks like a duck, it sure as heck doesn't quack like a duck. No doubt about it, this is my fault completely, but I'm not exaggerating when I tell you that when I figured out what was happening in my extensive ServiceMix junit regression test suite, I broke out in a cold sweat and probably turned pale.

Some digging into the JBI spec, more digging into the ServiceMix source code, and a brief e-mail discussion with Guillaume Nodet, one of the lead ServiceMix developers, verified that [1] there is no requirement in JBI that order is preserved, and [2] ServiceMix's use of a pool of threads for handling asynchronous delivery pretty much insures that order is a function of mostly-non-deterministic thread scheduling. I found this ultimately understandable, but very counter-intuitive.

WSDL Binding [5.5.6.1, p. 57]

Service providers on the ESB may choose to describe their messaging interface in the form of a service description. A service description is an XML document written using the Web Services Description Language (WSDL).

WSDLs, as such service descriptions are casually referred, have an abstract part and a concrete part. The abstract part describes both the syntax and the context of any messages used by the service provider. The concrete part describes the nuts and bolts of where to find the service provider and what protocol to use to talk to it.

Service providers may actually have more than one interface that they expose. They may expose one interface to clients external to the ESB. This interface describes a traditional web service and is only reachable through a BC. Service providers may expose another interface to service consumers on the ESB. This interface is available only on the ESB and may expose a much richer set of capabilities available only to other components on the ESB.

The neat thing is, both interfaces can be described in a single WSDL. Such a WSDL would have a single abstract part, but two (or more) concrete parts. One concrete part might specify a SOAP binding so that a SOAP router on the ESB could serve as a proxy for the service provider and route SOAP requests from external web services clients across the ESB to the service provider and handle sending responses back. A second concrete part could specify a JBI binding which would tell internal JBI components, including the SOAP router, how to use the internal interface.

When the JBI container parses the service description to extract the interfaces and JBI services and endpoints exposed by the service provider, it should (as ServiceMix does) only extract those interfaces, services and endpoints which are associated with the JBI binding. Any interfaces, services and endpoints associated with other bindings are purely a private matter between consenting components such as the service provider (an SE) and the SOAP router (a BC).

I didn't personally need to make use of this feature, but I did write code using the wsdl4j tool kit to extract the JBI-bound interfaces from the service descriptions that other developers provided for their components. So it is likely that others may have more to say on this topic.

Service Endpoints [ServiceEndpoint, p. 192]

A service endpoint is an object which contains, among other things, the qualified name (service name plus namespace) of a service, and the endpoint name of an endpoint within that service, for an endpoint which has been activated on the ESB. It is not unusual for a component to have to keep track of the namespace, service name, and endpoint name of an endpoint which has not yet been activated, for example, based on configuration information gleaned from a properties file. You may be tempted to create your own class that conforms to the JBI service endpoint interface just for the purpose of managing such information. But do not be deceived into thinking that just because your class conforms to the service endpoint interface that you can pass instances of your class with the JBI container as service endpoints.

The spec is quite clear on this: the JBI container is the only source of genuine service endpoints, and they are only doled out when an endpoint is newly activated by the container on behalf of the component. Just as only God can make a tree, only the JBI container may make a service endpoint. The underlying reason is of course because the JBI container implementation (ServiceMix) maintains private data inside its own implementation of the service endpoint interface to which you are not privvy.

I did in fact make a class just to keep track of endpoints that were defined but not yet activated, but I deliberately did not implement the JBI service endpoint interface, even though doing so would have been very convenient, just so I couldn't accidentally try to pass an instance of this class into one of the JBI APIs.

That's the current brain dump on JBI. More later as it occurs to me.

Sources

Ron Ten-Hove, Peter Walker, Java Business Integration (JBI) 1.0, JSR-208, Sun Microsystems Inc., August 2005

Peter Walker, private communication, 2006

Guillaume Nodet, private communication, 2006

6 comments:

Anonymous said...

Thanks John, this was a great overview for somebody like me with only cursory knowledge of ESBs and JBI!

Joel

Anonymous said...

Thank you very much for this brain dump, reading between the lines of the JBI spec... I am using JBI for my thesis and found lots of useful practical information in this detailed blog post.

Anonymous said...

I really enjoyed your post about servicemix. I was wondering and confusing about those concepts and you just cleared lots of things...

Thanks a lot.

Anonymous said...

couldn't agree more... if i would have found this bl**dy post months ago, me life would have been so much easier... thumbs up, nevertheless, thumbs up!!

Unknown said...

Really great article explained everything i need to know about servicemix and JBI. Thanks man :-)

Anonymous said...

Extremely useful for a person trying to grasp the concepts on JBI and its corresponding implementation by ServiceMix. Great work!!!