Thursday Nov 01, 2007

UPDATE:  As of 1/14/2008, the message bundle is generated to the source directory, not the build output directory.  The Ant task will not overwrite a file that hasn't changed, so the only time you'll earn a build manager's wrath for mucking with source-managed files is when you forget to check in the generated message bundle file.  So don't forget.  I've added a wiki page detailing most of what's below without the color commentary provided by yours truly.  So don't click it and keep reading...  ;)

Having added an i18n utility for your component and reveled in how nice it is to write your messages directly in the code, you need to actually generate the message properties bundle.  That's where the Hulp i18n Ant task comes in.  You may want to take a quick gander at my blog entry detailing how to add Ant tasks to your Maven project; that'll tell you where to add the targets I'll detail below.  Let's dive right in...

    <!-- define the i18n task -->
<taskdef name="i18n" classname="net.java.hulp.i18n.buildtools.I18NTask">
<classpath>
<pathelement location="${maven.repo.local}/net/java/hulp/i18ntask/net.java.hulp.i18ntask/2.1-SNAPSHOT/net.java.hulp.i18ntask-2.1-SNAPSHOT.jar"/>
</classpath>
</taskdef>
<!-- call the i18n task -->
<i18n dir="${project.build.outputDirectory}"
file="${project.build.sourceDirectory}/com/sun/jbi/engine/xslt/msgs.properties"
prefix=""
pattern="(XSLTSE-[4-7]\d\d\d)(: )(.*)"/> 
<!-- Copy the generated file to the build output directory to be packaged with jar -->
<copy file="${project.build.sourceDirectory}/com/sun/jbi/engine/xslt/msgs.properties"
todir="${project.build.outputDirectory}/com/sun/jbi/engine/xslt"/>

The taskdef is straightforward, though you'll need to add a dependency on the Hulp i18n Ant task library in your pom.  A closer look at i18n's attributes:

dir
The Ant task parses the compiled binary files searching for messages by the specified message identifier pattern, which is why the task is called after the compile phase.  This attribute points to the build output directory for your component project.
file
This is the location to which the message bundle file is generated. Note the generation occurs to the build source directory, which is usually a no-no because no build step is allowed to overwrite source-managed files.  The Ant task will not overwrite a file that hasn't changed since the last generation.  Keep this in mind when managing your source files in version control and ALWAYS check in the newly generated bundle file.
prefix
The component prefix which begins every message, comprising the alpha portion of the message's unique id.  Remember, pass an empty value if the prefix is already part of the message identifier pattern.
pattern
The message identifier pattern, which MUST match the pattern given to your component's I18n utility implementation's constructor.

Here's the dependency to add to your pom to ensure that the Hulp i18n Ant task is available for the taskdef's classpath:

        <dependency>
<groupId>net.java.hulp.i18ntask</groupId>
<artifactId>net.java.hulp.i18ntask</artifactId>
<version>2.1-SNAPSHOT</version>
</dependency>

Add the taskdef and i18n targets, plus the dependency, to your pom and you should be ready to go.  Feel free to email me with questions. 

Friday Oct 26, 2007

One of the systemic requirements is making sure our log and exception messages are appropriately internationalized.  Thanks to Frank Kieviet, we have a new utility in CRL common-util that does most of the heavy lifting.  At a high level, there's two steps: 1) extend the utility; and 2) run the Ant task to generate the message bundle.  That's right, generate.  Now you put your messages directly in your code; no more having to keep track of message keys and making sure you didn't forget to provide a corresponding message in the properties file.  (I've never done that, but I've heard it happens... ;-) )  This entry will cover the first step while a forthcoming entry will cover the second.  Let's dive right into the code...
    /*
     * NOTE: This is NOT the utility; this is an example of how to USE the utility.
     *       The example below is XsltSE's i18n implementation.
     */
    public class I18n extends LocalizationSupport {
        private static final I18n mI18n = new I18n();

        protected I18n() {
            super(Pattern.compile("(XSLTSE-[4-7]\\d\\d\\d)(: )(.*)", Pattern.DOTALL), 
                  "",
                  null);
        }

        public static String loc(String message, Object... params) {
            return mI18n.t(message, params);
        }
    }
The utility: LocalizationSupport
This utility has two primary responsibilities: managing the resource bundle of messages and storing the unique identifier pattern.  The former is fairly straightforward; messages are still stored in a properties file.  The latter is part of our systemic requirements to have a unique identifier for every message, logged and/or thrown.  This requirement comes in handy when it comes to generating the bundle properties file.
The constructor
pattern
This is the regular expression that identifies the pattern of unique identifiers used in your component.  In the example above, you can see that XsltSE's codes all start with "XSLTSE-" and a four-digit numeric code.  Alternatively, the pattern could be "([4-7]\\d\\d\\d)(: )(.*)"; in that case, I would specify a prefix of "XSLTSE" (the dash is added when the prefix is non-empty).
prefix
The prefix prepended to a message's numeric code is used as the unique message identifier.  The convention is the prefix describes your component.  If the prefix is empty, the pattern is expected to reflect a descriptive name for your component (as in the example above).
bundleName
The name of the genrated message bundle file.  Specifying null will generate the file using the default name: msgs.properties
The method: loc
This is the method called by your component's classes to provide a locale-specific string at runtime.  The first parameter is the message itself; the utility will use its pattern to parse the code from the message content.  The second parameter(s) are the replacement tokens a la java.text.MessageFormat.  Your implementation can choose a different name for this method; check out the snippet below and decide for yourself.  Whatever name you choose, the implementation will be identical to the above example.
Example Usage:
String err = I18n.loc("XSLTSE-6005: XsltSE cannot find provisioning endpoint (name={0},srvc={1}) for message (id={2})",  
                      ept.getEndpointName(), ept.getServiceName(), mex.getExchangeId());>
Generated message bundle (abbreviated)
# com.sun.jbi.engine.xslt.XsltseMessageListener
XSLTSE-6005 = XsltSE cannot find provisioning endpoint (name\={0},srvc\={1}) for message (id\={2})

Method returns:
XSLTSE-6005: XsltSE cannot find provisioning endpoint (name=evaluator,srvc={http://j2ee.netbeans.org/wsdl/CandidateEvaluation}CandidateEvaluator) for message (id=125059124664434-16983-134126666809870206)

So you have an i18n utility.  Big deal, right?  Not really, until you incorporate the Ant task which generates the messages bundle file.  A future post will cover how to integrate the Ant task, but you'll have to wait.  It's Friday, after all:  go home, go out, whatever.  Ciao. [UPDATE:  Hope you had fun over the weekend, cuz here's the post detailing the Hulp i18n Ant task I promised...]

Tuesday Oct 02, 2007

"Get on board the Sun Shuttle!"  Huh?  There's a shuttle?  Where are we going?  Patience, grasshopper...

I wish I could say that I've been swamped with all the transformation use cases for which I asked... I did get a few and a great big thank you goes out to those who emailed me.  Instead, I've been bogged down planning for the systemic qualities we're adding to our components.  Things like logging standards, transaction and security propagation, monitoring and management... the list is pretty big.  Anyhoo, much of this functionality will be across components, so we needed someplace to put it (since most of our components are not using CRL... ahem).

Also, XsltSE is moving away from our custom wsdl model and has integrated wsdl4j.  This required some extensions for the BPEL-specific elements, such as PartnerLinkType and message properties.  These wsdl extensions were part of a new shared library (SL), Wsdl4jExt, and that's when things went downhill.  Turns out JBI classloading does not allow SLs to reference each other.  All props to JBI, but c'mon!  This meant that TransformSL, which needed the Wsdl4jExt, could only access the them by explicitly packaging the jars.  Duplicate jars in multiple SLs should immediately crop up as a no-no; sure did for me.  Our resident JBI gurus, Mark White and Keith Babo (who I guess is too busy to have a blog), have assured me this gap is part of the JBI 2.0 discussion.

Typical... I finally get to the point several paragraphs in.  There's a new JBI shared library!!!  (I suppose if I were more concise, I'd be someone else...)  It's called the Sun Shared Utility Library, or ShUtil pronounced "shuttle" for short.  The big marketing slogan is something along the line of "get on board the Sun Shuttle!"  The slogan came about because this new SL contains several reusable libraries, including CRL, Wsdl4jExt, and (in the future) some logging and i18n apis from Frank Kieviet

So check it out.  To use CRL now, or any other library riding the "shuttle", all you need do is declare the dependency on the new SL, "sharedutilsl".  In the next few weeks, I'm going to try and delve into Maven and figure out how to package just the bootstrap utilities into a separate jar.  Right now, if you're using the BootstrapFilter utility, the crl.jar must still be packaged (though not referenced in the component classpath).  Ciao!

Tuesday Apr 17, 2007

The first few entries in this series have focused on some of the smaller utilities.  But what about the JBI component itself.  There are three core JBI interfaces for which every component must provide an implementation: Bootstrap, Component, and ComponentLifecycle.  We already talked about the first in the entry on the BootstrapFilterChain utility.  The latter two interfaces were combined in CRL into a single interface: ComponentManager.  The primary reasons for this strategy were three-fold: 1) both the Component itself as well as its lifecycle would need access to the same utilities; 2) making the component manage its own lifecycle reminded me of a finite state machine (I was a CogSci major in college) and resulted in a simpler abstract base class; and 3) one interface is easier than two. 

I will point out before I continue that there's a lot of information in this entry, and not just me yapping; I've linked a few things that merit your time.  First, you should take a moment to review Chapter 9 of the JBI spec, which describes the javax.jbi.component interfaces.  When you're ready, review the tables below (copied from the forthcoming CRL development guide) that describe the current implementation of the AbstractComponentManager.  This utility is an abstract base class that follows the conventions that our JBI components are supposed to be following.  It's important to note that these conventions, detailed on this GlassFish wiki page courtesy of Andi Egloff, are not explicitly defined in the spec.  The only aspect of these conventions not yet implemented is the idea of "pausing" a service endpoint.  I strongly recommend you read these conventions if you're going to use the AbstractComponentManager utility.

javax.jbi.component.Component

MethodDescription
ComponentLifeCycle getLifeCycle()A reference is provided to the component's lifecycle: ITSELF!
org.w3c.dom.Document
getServiceDescription(ServiceEndpoint endpoint)
The current implementation provides no default behavior.
ServiceUnitManager getServiceUnitManager()A reference is provided to the component's ServiceUnitManager, which is initialized by a template method: initServiceUnitManager().
boolean isExchangeWithConsumerOkay(ServiceEndpoint endpoint, MessageExchange exchange)By default returns true, allowing the component to act as a provider with any consumer.
boolean isExchangeWithProviderOkay(ServiceEndpoint endpoint, MessageExchange exchange)By default returns true, allowing the component to act as a consumer with any provider.
ServiceEndpoint resolveEndpointReference(org.w3c.dom.DocumentFragment epr)The current implementation provides no default behavior (i.e. returns null).

javax.jbi.component.ComponentLifeCycle

MethodDescription
javax.management.ObjectName getExtensionMBeanName()A reference is provided to the component's extension MBean, if set. Reference is unset by default.
void init(ComponentContext context)The current implementation provides template methods to properly initialize a CRL-based JBI component by executing the following steps:

  1. Stores reference to the ComponentContext provided by the JBI implementation.

  2. Initializes the component's CRLMessageExchangeFactory.

  3. Sets reference to the component's EndpointManager by invoking the template method: initEndpointManager().

  4. Sets reference to the component's javax.jbi.component.ServiceUnitManager by invoking the template method: initServiceUnitManager().

  5. Sets reference to the component's AcceptManager by invoking the template method: initAcceptManager().

  6. Initializes the component's CallbackRegistry and CorrelationMap with CRL's default implementations, DefaultCallbackRegistry and DefaultCorrelationMap, respectively.
void shutDown()Shuts down the component's AcceptManager via its corresponding shutDown() method.
void start()Starts the component's AcceptManager via its corresponding start() method.
void stop()Stops the component's AcceptManager via its corresponding stop() method.

ComponentManager


MethodDescription
AcceptManager getAcceptManager()
void setAcceptManager(AcceptManager amgr)
A reference is provided to the component's AcceptManager.
ComponentContext getComponentContext()
void setComponentContext(ComponentContext ctx)
A reference is provided to the ComponentContext provided by the JBI implmentation.
CorrelationMap getCorrelationMap()
void setCorrelationMap(CorrelationMap cmap)
A reference is provided to the component's CorrelationMap.
CallbackRegistry getCallbackRegistry()
void setCallbackRegistry(CallbackRegistry registry)
A reference is provided to the component's CallbackRegistry.
CRLMessageExchangeFactory getExchangeFactory()A reference is provided to the component's CRLMessageExchangeFactory.
EndpointManager getEndpointManager()
void setEndpointManager(EndpointManager emgr)
A reference is provided to the component's EndpointManager.

Template methods

One of the primary goals of CRL is to provide JBI developers with the core building blocks to build a JBI component as quickly and easily as possible. In the case of AbstractComponentManager, design discussions led to template methods as the appropriate solution since the challenge of creating a ComponentManager is not so much how it's customized, but rather with which subcomponents it's customized. There are three template methods as follows:
MethodImplementation
AcceptManager initAcceptManager()Most components can take advantage of CRL's default implementation, DefaultAcceptManager, and focus on configuring it with the appropriate Processors, as described in the previous blog entry.
EndpointManager initEndpointManager()For most components, managing its endpoints is relatively straightforward and CRL's default implementation, DefaultEndpointManager, will suffice. In this case, designing effective Endpoints is the biggest challenge and will be covered in an upcoming blog entry.
ServiceUnitManager initServiceUnitManager()The ServiceUnitManager interface is not explicitly required by the JBI specification. In this utility class, it is primarily used in conjunction with a component's EndpointManager to manage the component's endpoints at various points in their lifecycle. This is the only template method that does not require explicit implementation. The current implementation instantiates a DefaultServiceUnitManager with the component's JBI context and its EndpointManager.

If you've gotten this far, pat yourself on the back.  And accept my hearty thanks for bearing with the bombardment of information.  I'm waiting on some pretty graphics so I can describe the path a message exchange takes from the NMR to your component's Processor implementation.  I'm thinking the next entry will either try and give a higher-level view of putting your component together by listing the pieces you'll need or review the Endpoint interface.  You will all be subject to my mercurial whim....(insert cackling laughter here).

Friday Apr 13, 2007

So you've survived my lengthy dissertation about the AcceptManager and want to see how it's actually used, which means learning about the ExchangeRouter.  This is the only utility available via AcceptManager that components will have to explicitly configure.  Its purpose is to map a message exchange received from the NMR to the Processor responsible for handling it.  A Processor is a discrete slice of business logic for your component, designed as a command pattern interface.  The default ExchangeRouter implementation, PatternExchangeRouter, "slices" your component's business logic based on the four spec-defined message exchange patterns (InOut, InOnly, Robust In-Only, In Optional-Out) and the role of the message exchange (Provider, Consumer).  This means that your component will have at most eight Processor implementations, one for each combination of ME pattern and role.  I'll use XSLT SE's initialization of its AcceptManager as an example of how to configure a PatternExchangeRouter.  You might also want to review section 5.4.2.2-5 of the JBI spec to (re)familiarize with the standard ME patterns, focusing on the diagrams of InOut and InOnly.  Here's the code:

01      AcceptManager amgr = new DefaultAcceptManager(this);
02 ExchangeRouter router = amgr.getExchangeRouter();
03 router.register(PatternRoleKey.IN_OUT_PROVIDER, new SimpleProcessorFactory(new XsltseInOutProvider()));
04 router.register(PatternRoleKey.IN_OUT_CONSUMER, new SimpleProcessorFactory(new XsltseInOutConsumer()));
05 router.register(PatternRoleKey.IN_ONLY_PROVIDER, new SimpleProcessorFactory(new XsltseInOnlyProvider()));
06 router.register(PatternRoleKey.IN_ONLY_CONSUMER, new SimpleProcessorFactory(new XsltseInOnlyConsumer()));

And here's a line by line description of the code:

  1. Instantiates the default implementation of AcceptManager, passing in a ComponentManager instance.  ComponentManager is a CRL interface that combines the JBI Component and ComponentLifecycle interfaces as well as providing a single access point for a few other component utilities.  There'll be a blog entry about that pretty soon.
  2. Acquire the default ExchangeRouter implementation, PatternExchangeRouter, from the AcceptManager.  Note you don't need to deal with it as a specific type of ExchangeRouter.  As you can see in lines 3-6, you will need to know the appropriate RouterKeys to use (explained below).
  3. Adds a Processor to handle the "provider" role of the InOut message exchange pattern. This Processor handles the initial input data and possibly a status response from the Consumer of the service.
  4. Adds a Processor to handle the "consumer" role of the InOut message exchange pattern. This Processor handles either the output data or fault data from the Provider of the service.
  5. Adds a Processor to handle the "provider" role of the InOnly message exchange pattern. This Processor handles the initial input data from the Consumer of the service.
  6. Adds a Processor to handle the "consumer" role of the InOnly message exchange pattern. This Processor handles a status response from the Provider of the service.

A few other notes about the code example:

  • PatternRoleKey is an enum of the RouterKey used by the PatternExchangeRouter.  Because each message exchange is unique, it would be problematic at best to try and register Processors with an ME.  Therefore, the idea of a RouterKey is introduced: a static representation of a type of message exchange.  In this case, each PatternRoleKey enum represents a unique combination of an ME pattern and role.  Custom ExchangeRouter implementations would define their own RouterKey enum to identify a type of message exchange.  It goes without saying (though that's clearly not stopping me) that each Processor registered should be capable of handling the type of ME corresponding to the RouterKey with which it's registered.
  • SimpleProcessorFactory is a simple CRL utility that provides either the singleton instance, or newly-created instances, of a Processor.  ExchangeRouter's don't need to know if your Processors are singleton or not; it simply keeps track of Processor factories and provides an instance on cue.
  • You'll notice the four Processors registered only correspond to InOut and InOnly.  XSLT SE only supports these two message exchange patterns.
  • The Processor interface is a simple command-pattern with one method: "process".  The four Processors referenced above implement four extensions related to the same pattern-role combinations mentioned previously.  Skip to the next paragraph if you're not curious about implementation details.  For example, XsltseInOutProvider extends AbstractInOutProvider, which implements the "process" method by routing the message exchange (based on its current state) to "processIn" or "processStatus".  This means as a Processor implementor I don't have to explicitly determine the ME's state; that is, should I process the input data or have I received a status response indicating the ME pattern is complete.
And that's it.  If the default AcceptManager implementation is sufficient for your component, then you only need to focus on the functional logic of your component.  The bulk of XSLT SE's implementation is in support of two things: its Processors (applying XSL transformations) and its Endpoints (knowing which XSL stylesheet to apply).  We'll talk about the endpoints later.  The point is by using CRL, I need to understand the ME patterns and make sure that I'm completing them, but I don't need to worry about writing code for accepting MEs from the NMR, routing them to the appropriate Processor (other than lines 3-6 above), determining at which point in the ME pattern I need to handle, and various other low-level JBI concerns.  CRL handles all the rest.  I hope this has been helpful.  As I proofread this entry, I'm concerned I'm glossing over parts that I take for granted having written the code myself.  So, as always, please post any questions or comments and I'll be happy to fill in any gaps I may have left in your understanding of this (or any) CRL utility.  Regards!

Wednesday Apr 11, 2007

One of the core aspects of a JBI component is sending and receiving messages from the normalized message router (NMR).  To simplify the interaction, CRL provides a utility called the AcceptManager.  It's named for the DeliveryChannel.accept() method from which incoming messages are received by the component.  The AcceptManager is designed around the idea of a MessageListener: an event-driven interface that has a single method, onMessage(), that's responsible for handling a message exchange. The "event" in this case is the arrival of an exchange from the NMR.  Keep this concept in mind for later...

The AcceptManager has two primary functions: 1) coordinating with a component's lifecycle state (i.e. started, stopped, shutdown) to determine whether or not to accept incoming message exchanges from the NMR; and 2) act as a hub of other CRL utilities that can process those incoming exchanges.  There is a default implementation provided by CRL that satisfies both these responsibilities, which should be sufficient for most components.  If not, then like most CRL utilities, it can be easily customized to support the specific needs of your component.  Note that all the utilities available in this "hub" are interface-driven with default implementations of their own, each of which can be replaced with custom implementations as the need arises.  Have I mentioned CRL strives hard to be optional?  Future blog entries will delve into the complexities of implementing custom versions of the utilities that an AcceptManager provides, but for the purposes of this entry I will be discussing the default implementation: DefaultAcceptManager.  In fact, a great deal of the following refers to the default implementations of these utilities. Also note that since the default implementation should suffice for most components, you can focus on assembling your component rather than implementing each piece.

So back to the two primary functions of the AcceptManager.  The first function is to manage incoming message exchanges from the NMR, for which there are three methods that correspond to the component's lifecycle state:

  • startAccepting() - when the component is started, the AcceptManager starts accepting message exchanges received from the NMR
  • stopAccepting() - when the component is stopped, the AcceptManager stops accepting message exchanges...
  • shutDown() - when the component is shut down, any resources associated with listening on the NMR are cleaned up (e.g. threads stopped, etc.)

The DefaultAcceptManager maintains a set of AcceptPoller threads to listen on the NMR.  An AcceptPoller (another interface with a default implementation) is an extension of Runnable with a reference to the component's DeliveryChannel.  Each AcceptPoller, once started, listens on the DeliveryChannel for incoming message exchanges. Once an exchange is received, it's passed to a MessageListener for processing and the AcceptPoller returns to listening on the DeliveryChannel.  The default implementations of these three lifecycle methods are fairly straightforward: startAccepting() creates and starts the AcceptPollers, stopAccepting() stops them, and shutDown() clears out the set. This implementation should be sufficient for most components; keep in mind that the actual processing the message exchanges is handled elsewhere.  A review of the elsewhere follows...

The second function is to collect the various utilities involved in handling incoming message exchanges.  Allow me a brief digression to reinforce CRL's goal: in terms of the overall functionality, there probably doesn't need to be so many pieces.  The reason there are is to maintain the optionality of CRL's utilities.  Ideally, if one of the default implementations is insufficient for your component, you should only need to implement that one and NOT all the others. Therefore, each of these utilities is responsible for only a small portion of the exchange handling. The AcceptManager provides getters and setters for each of the following utilities:

  • ComponentManager - this is a reference to the component itself. A future blog entry will detail the usage of this CRL utility.
  • ListenerContext - this is the context of your component's MessageListener. For now, I'm still hoping the default implementation will be sufficient for most components, so you shouldn't need to explicitly use this utility unless you're implementing your own MessageListener.
  • MessageListenerFactory - another utility you only need if you're implementing your own MessageListener.  Another future blog entry, I think...
  • ThreadManager - the purpose of this utility is to manage the resources allotted to your component's MessageListeners. CRL provides two default implementations of this interface: 1) SingleThreadManager is for singleton MessageListener implementations (which includes the default) and invokes the MessageListener in the current thread; and 2) PooledThreadManager, which uses JDK 1.5's concurrency package to spawn a new thread for each message exchange received from the NMR. It's up to your MessageListenerFactory, if you've created one, to determine if a new MessageListener is also created for each thread.
  • Poller count - not so much a utility as an attribute, this determines the number of AcceptPoller threads created to listen on the NMR.
  • ExchangeRouter - this utility analyzes an exchange to determine which Processor should handle it. A Processor is a simple command-pattern interface that should only contain the business logic of your component.  The default implementation, PatternExchangeRouter, will get its own blog entry by the end of this week.
There's a lot of exposition in this entry, for which I apologize. Remember that CRL does not want to hide the complexity of implementing a JBI component.  Rather, the goal is to draw your attention to the important parts so that you can make informed decisions about how to implement your component, and then hopefully make use of CRL's utilities to do so.  As I stated before, the next blog entry will describe the PatternExchangeRouter using the XSLTSE's use of AcceptManager as a demonstration of its use.  The entry after that will have pretty graphics and will follow a message exchange from the NMR all the way through the DefaultAcceptManager until it's handled.  Until then....

Wednesday Apr 04, 2007

Well, look what we have here: a CRL post!  For those not familiar with CRL, please read the What is CRL? blog entry.  I've decided to begin this series of blog entries with a review of CRL's BootstrapFilterChain, a utility to help implement one of the core JBI interfaces: javax.jbi.component.Bootstrap.  Per the JBI spec, a component's Bootstrap is implemented "to provide any special processing required at install/uninstall time."  See Chapter 9 of the spec for more info on the Bootstrap interface.

The BootstrapFilterChain (BFC) utility is a list of BootstrapFilters, each of which implements one aspect of the component's install/uninstall functionality.  The idea stemmed from the idea of filters in a web application and is implemented in a similar fashion.  The BFC implements the Bootstrap interface itself, so when one of the Bootstrap methods is called, the BFC iterates through all the filters and calls the corresponding method on each filter.  Rather than a single class implementing all the Bootstrap behavior, the BFC allows slivers of functionality (i.e. the BootstrapFilter instances) to be chained together in sequence.  This follows a common theme in CRL, that of assembly: the Bootstrap implementation is assembled by adding existing and new filter types versus a single class attempting to implement all the behavior by itself.  The second advantage, other than assembly, is that each Bootstrap filter is executed in its own try-catch block, thus limiting the impact of one filter (say a thrown exception) on another.

Let's take a look at the XSLTSEBootstrap implementation.  Here it is in its entirety:

 1  public class XSLTSEBootstrap extends BootstrapFilterChain {
2 public XSLTSEBootstrap() {
3 StandardMBean mbean = null;
4 try {
5 mbean = new StandardMBean(new XSLTSEInstallerConfigurationMBean(),
6 XSLTSEConfigurationMBean.class);
7 }
8 catch (NotCompliantMBeanException ncme) {
9 String msg = Messages.getMessages(XSLTSEBootstrap.class)
10 .getString("XSLTSEBootstrap.installMBeanNotCompliant",
11 ncme.getMessage());
12 LogUtil.getLogger(XSLTSEBootstrap.class).log(Level.WARNING, msg, ncme);
13 }
14
15 addFilter(new DefaultBootstrapFilter(this, mbean));
16 addFilter(new ConfigPersistenceFilter(this));
17 }
18 }

Granted, XSLT SE is a fairly simple component and doesn't need much bootstrap behavior to be successfully installed/uninstalled; thus it only needs two filters (which I'll review in a sec).  Assuming I'm not retarded, I probably don't need the try-catch block since I know the MBean that's instantiated is compliant with the specified interface, but I'm a little overzealous sometimes with error handling.  Which means my entire Bootstrap implementation could be all of two lines, specifically lines 15 and 16.  Not to beat a dead horse, but this is the whole point of CRL. ;)  By extending the BFC utility, you've implemented the Bootstrap interface; then add the filters your component needs.  The first filter added in the snippet above, DefaultBootstrapFilter, registers/unregisters the (optional, per the spec) installer configuration MBean during init() and cleanUp(), respectively.  Simply pass the instantiated MBean to the constructor and the rest is handled by the filter.  Note that both install() and uninstall() are no-ops in this filter and can be overridden as needed.  The second filter, ConfigPersistenceFilter, persists the initial configuration to the component's installation directory as a properties file.  These two filters could have been combined into one; however, one of CRL's other goals is to provide optional utilities, not a framework that locks you in.  Use both or either at your discretion.

One final note about the BFC implementation.  The spec indicates that it's not guaranteed that the same Bootstrap instance will be used at install and uninstall time.  Therefore, the Bootstrap implementation must persist any instance data in the event of a component or system shutdown.  CRL's implementation currently uses a static map, keyed by the fully-qualified classname of the component's bootstrap implementation, to store the instance data in memory.  This accounts for component shutdown, but not system shutdown.  There have not been any issues so far, but a future revision will account for system shutdowns as well.  Also note that you get this functionality for free; I only mention it because I'm a full-disclosure kind of guy.

As always, questions and comments are welcome.  For the time being, I've been promised a reprieve from BPEL bugs.  So I should be able to write a few more of these blog entries as well as work on the CRL development guide in the coming weeks.  The next blog entry will likely focus on CRL's AcceptManager utility, which simplifies the interaction between the component and the NMR.  If I've written this entry well enough, that should be of interest to you.  Here's hoping... ;)  Regards!

Thursday Mar 15, 2007

I promised a How To post for CRL a while back and since there hasn't been one yet, I feel obligated to provide an explanation why.  There's been much discussion over the last couple of weeks about the goals and future of CRL, very little of it concluding in a satisfactory manner for me.  So please indulge me a little as I attempt to vent some frustration in a constructive manner.

I (and the rest of the team) have spent a great deal of time building utilities and interfaces that (we think) incorporate some "best practices" for developing a JBI component.  That's the part upon which most everyone agrees.  That said, concerns have been expressed about whether CRL hides the JBI interfaces and what that says about JBI.  To be clear, this is a totally valid concern.  My response to that is simple: In no way is CRL attempting to undermine and/or replace the JBI interfaces.  Augment, maybe; but disparage or replace, not a chance.  As I stated in the What is CRL? post, we'd stumbled into the copy-and-paste effect and wanted to escape.  That's all.  A statement about the quality of JBI was neither intended nor warranted.  If anything, we're totally committed to JBI and wanted to build our components in the best way possible.  Considering the second-class status CRL has "enjoyed" so far, it's not there yet.  But I believe it could be, and I'm gonna need your help.

As per my usual rambling style, it usually takes me a couple of paragraphs to get to the point, so here it is: CRL's not going anywhere.  I mean that in a good way and a bad way.  The good meaning is that its source is at the open-jbi-components site and soon we'll be developing directly off that repository.  Anyone who's interested can look at it, use it and ask me questions from now until doomsday.  The bad meaning is that the concerns that have been raised (again, valid concerns) will keep it from getting the attention internally that I think it needs to really shine.  I'll be working on it as time permits, but I own the XSLT SE and have been fully absorbed by the BPEL SE team, so my plate's pretty full.  That said, I still believe in CRL and have not given up hope that (with your help) it can provide real value to JBI component developers. 

So I invite you to take a look, read my entries (which I swear are forthcoming) that describe how to use it, ask questions and provide tons of feedback.  The more input I get, the more time I can carve out to improve the quality of the utilities that CRL provides.  But I owe it to anyone who's interested in CRL to acknowledge two very critical points: 1) CRL is evolving, so expect changes; and 2) CRL's lack of manpower support is something anyone who uses it will have to take into account.  The latter should not be construed as an indictment of CRL's overall quality but rather the reality of where it stands now and the foreseeable future.  Thanks for listening.


Wednesday Feb 28, 2007

We interrupt this blog with a newsflash.  We have confirmed reports of the existence of an XSLT service engine packaged with the upcoming release of the Enterprise Pack.  Our sources indicate this component will allow the deployment of XSL stylesheets as provisioned services in the JBI environment.  For more information on this breaking story, we have the lead engineer live via satellite....

Ok, so maybe it's less a breaking story than a bad newscaster-infested blog joke.  Either way, the punch line's the same: the XSLT SE is getting released.  And this blog entry will help you understand what it does and how to use it.  (I'll point out that the spell checker in the entry editor is flagging blog as misspelled.  Let's all take a moment to appreciate the irony.  Moving on...)

So you want to implement an operation using an XSL stylesheet.  First thing to do is associate the operation you're implementing with your stylesheet.  XSLT projects have a custom configuration file, xsltmap.xml (described in detail here), to do just that.  Endpoints in JBI are uniquely identified by a combination of portType, partnerLink and its role name.  These three values correspond, respectively, to the interface-name, service-name and endpoint-name attributes in JBI descriptor entries ( i.e. "provides" and "consumes" ).  By specifying these values along with the operation name and the stylesheet, the XSLT SE has enough information to provision a service endpoint using that stylesheet.  We're not delving into the actual configuration here because A) the XSLT Project wiki page already has the details; B) I'm trying to change the structure of the xml to be more user-friendly and my blog entries aspire to age well (aka not be outdated); and C) it would make this entry even longer than it's already going to be.  Did I mention I'm a little verbose?  Anyhoo....

There's a simple activity diagram on the wiki page, but let's look a little closer at what's going on, starting with the ubiquitous request-reply scenario.  When an XSLT service is invoked and the message comes into the engine, it's currently wrapped in the WSDL 1.1 wrapper element, "jbi:message".  The engine first extracts the payload of the jbi:part element (multi-part messages are described below).  The XSL stylesheet is looked up by its endpoint configuration and the transformation is applied ONLY to the payload.  Assuming the transformation succeeds, the transformed content is wrapped in a jbi:message wrapper and sent back to the NMR and routed to the original consumer.

That may be a bit low-level, but it's important to note two things: 1) that the stylesheet is applied to the payload regardless of its type, and 2) the stylesheet only transforms one part of the message.  The first item is significant because the stylesheet you deploy must transform the input of the WSDL operation you're implementing to its output.  In the future, I'd like to add some type validation, but it's not there now.  If you see denormalization failures during the response, double-check your stylesheet.  The second item is important because not all messages have only one part defined.  Read on...

Multi-part messages are supported, but there were no answers to questions like: Is the stylesheet applied to all message parts at the same time?  Sequentially?  If one transformation fails, do we roll back other successful transformations?  After much discussion, we decided Ockham's Razor was applicable: the simplest solution was the best.  So we punted.  Rather than answering these questions, the stylesheet is applied to the whole jbi:message element, meaning the stylesheet must construct the WSDL 1.1 message wrapper as defined in section 5.5.1.1.4 of the JBI spec.  Design-time support is forthcoming to help build such a stylesheet (and in writing this, it occurs to me that we can further enhance the configuration to specify a stylesheet for each part, whether the transformations are executed in a transactional manner, etc.  Please leave a comment on this blog if that idea has appeal).  For now, to indicate to the engine it must apply the stylesheet to the whole message (not just the first part), specify the 'transformJBI' attribute as "true" in the configuration file.

What if you want to chain an XSLT service with another service?  This too is possible, with the filterOneWay and filterRequestReply use cases.  The XSLT endpoint is configured in the same manner as the request-reply scenario, but in these scenarios a second service endpoint (not necessarily XSLT) is specified as well.  When the message comes into the engine and after the transformation is applied, the transformed content is sent as input to the chained service.  To support transactions, these chained services are synchronous, meaning the original consumer does not receive a response until after the XSLT SE receives a response from the invoked service.  The same constraints about stylesheet type and multi-part messages described above still apply, along with two additional notes: 3) filterOneWay chains two one-way services and filterRequestReply chains two two-way services: the WSDL operations MUST be defined accordingly; and 4) the filterRequestReply scenario involves two XSL transformations.  The second transformation is applied to the reply of the chained two-way service, and it is the result of this second transformation that is sent back to the original consumer.

Well, I've reread this entry and edited as best I can, but there's just a lot of info I wanted to convey.  If anyone would like further exposition on ANY aspect of what I've described, please do not hesitate to leave a comment.  I can go into more detail on further entries and/or maybe we can start a forum for XSLT SE.  That's all for now...

We now return you to your regularly scheduled broadcast. 

Sunday Feb 25, 2007

What is CRL?  Where to begin?  There's a lot of information I can throw at you, but I don't want to overwhelm anyone into thinking it's too complicated to merit its use.  At the same time, I need to not only explain clearly what it is but also make a case for using it.  I'll start with a little background and then delve in while trying to avoid turning this into a development guide.

As our teams started building JBI components, we soon found ourselves in a typical development quicksand-like scenario known as the copy-and-paste effect.  We've all done it at one time or another; you need to get your component/module/etc. ramped up quickly but don't want to reinvent the wheel.  So you look at a similar piece of code, imagine that you'll still respect yourself in the morning, and there you are.  Doesn't mean the code is bad or doesn't work (on the contrary), but the cost of supporting code like this is always higher in the long run.  CRL is the antithesis of this quagmire.  I'd had experience building reusable libraries for a homegrown SOA at my previous job (and loved the complexity of designing for scenarios of which I couldn't even conceive), so I found incriminating photos of a few of our team leads and enlisted their help.  To give credit where credit is most certainly due, I present the heart of the CRL team:

  • Me, myself, and I - XSLT SE
  • Murali Pottlapelli - BPEL SE
  • Alex Fung - HTTP BC
  • Sherry Weng - File BC
  • Andi Egloff - JBI component guru/architectural advisor
  • other contributors included Keith Babo and Ron Ten-Hove

Yeah, yeah, background, schmackground.  What is it?!?  CRL stands for the Common Runtime Library ( pronounced "coral" ) and it's a set of utilities which can be assembled into a JBI component.  That's it.  There are certain parts of JBI components that are fairly consistent across components, both service engines and binding components.  These are the areas in which we focused to create utilities that not only could support any conceivable component but also incorporated the best practices as determined by our collective experience.  The XSLT SE was the first guinea pig, but at least two other SEs are using CRL and the BPEL SE will soon undergo refactoring to incorporate CRL.  In a perfect world, we'll get HTTP BC to refactor as well.

There are three aspects of CRL that I think differentiate this library from other similarly intentioned frameworks.  First, it does not attempt to hide all the complexity of the JBI environment.  You should have a decent understanding of the defined message exchange patterns, especially InOnly and InOut, but you won't have to have memorized the JBI spec.  Second, the various interfaces will guide you to the important decisions you'll need to make about the composition of your component.  There was a point at which hiding the complexity would have risked hindering the functionality CRL could provide; instead we settled on designing the interfaces to clearly identify the parts to which you must pay attention when building your component.  Finally, it's optional.  Once you start using one part of CRL, you're not forced to plug in all the other parts in order for your component to work.  Mind you, some things require support; but the focus was on interface-driven design.  So if you don't like how we implemented something, make sure you include how you did it when you tell us where we went wrong (which of course will never happen).  In summary, building a JBI component is not a trivial task, but ideally CRL makes it a much more manageable one.

Over a series of blog entries in the coming weeks, I will describe the process of building a JBI component using CRL.  I'm also working a detailed user manual, which the aforementioned blog entries will complement but not replace.  Until then, enjoy Oscar night.  (And the previously mentioned incriminating photos will be available to the highest bidder...admit it, you're curious!  LOL!)

This blog copyright 2009 by kevansplace