Tuesday, January 12, 2010

Book "SOA with Java": Rough cut now online

image

A few months ago I got a request from Satadru Roy, one of the authors of the book "SOA with Java", to write a section on Open Source ESBs for this book.

This was a good opportunity to advertise OpenESB, so I eagerly said yes. Satadru suggested that a practical example should be the core of the chapter, so I sat down with two of my colleagues, Murali Pottlapelli and Sujit Biswas, to discuss how the example would look like.

The result is a 17 page chapter that gives an overview of OpenESB. The book is now available for review on Safari. This link will probably be invalidated when the review period ends, but perhaps the link to the book itself is more permanent (the book is also on Amazon).

Friday, November 6, 2009

Remote learning, graduate projects, and open source

Last week, an ex-colleague asked me if I could be a reviewer on a graduation project at National University where he is now a professor. Flattered, and finding myself with a little bit more time on my hands than usual, I accepted.

The goal of the project was to let a team of seven students build a real-life application as a learning experience about how software development is done in the industry, for a "real" customer. The task was to develop a tracking application for the Boys & Girls Clubs of the Sequoias.

There were several interesting aspects of this project: first of all, the end result was a working application that in quality and functionality exceeds a good portion of similar applications built by IT departments. Key to this was the use of off-the-shelf frameworks such as Spring MVC, Hibernate, BIRT, and jQuery. I'm glad that students are using frameworks like these rather than reinventing their own, although that might have been even more fun.

Another interesting aspect was that the project was done as an open source project on code.google.com. The practical advantages are the infrastructure is provided completely ready by the code forge (in this case code.google.com), so that little time needs to be spent on setting up an infrastructure. This is especially important for students that are remote and hence don't have a shared work environment (e.g. office). Of course there's a lot more work to be done to make it a successful open source project, but that's not important in the scope of the project. I'm glad universities expose students to an open source way of development.

Lastly, the presentation of the project was done using a tool called ClassLive Pro. This is a JNLP application that provides similar functionality to WebEx. Although I've developed a few JNLP applications myself, and I'm convinced of its great utility, I haven't encountered any other JNLP applications so I was glad I ran into this application.

Tuesday, September 22, 2009

A SEED certificate

With the Oracle acquisition looming on the horizon, and the uncertainty that comes with it, it feels like many organizations within Sun are bringing projects in a state in which they can be transitioned in a clean way. Transitioned meaning adopted or abandoned.

I also find myself doing this: for instance I'm trying to put the finishing touches on JMSJCA, and trying to put Hulp in a state where other people can use it, etc.

Maybe it was in that light that a few days ago, I got a certificate from the SEED organization within Sun. SEED is a mentoring program within Sun in which I had the good fortune to participate. I also was a SEED mentor. Or perhaps I should let the speak for itself.

image

Monday, September 21, 2009

Lessons of an interesting deadlock problem

Two years ago I wrote a blog entry about Nested Diagnostics Contexts in GlassFish. The approach was based on custom Logger objects. Now, two years later when running GlassFish on AIX, an issue with that turned up: a deadlock. Digging into it, there are two lessons I'd like to share: one about deadlocks, and the other one about workarounds.

Deadlock in the JDK

At the time of my writing the NDC facility, calling addLogger() and getLogger() from different threads may cause a deadlock in the JDK classes. Why is this?

This is how the code in the Sun JDK was:

public class Logger {
...
    public static synchronized Logger getLogger(String name) {
	LogManager manager = LogManager.getLogManager();
	Logger result = manager.getLogger(name);
	if (result == null) {
	    result = new Logger(name, null);
	    manager.addLogger(result);
	    result = manager.getLogger(name);
	}
	return result;
    }
}
public class LogManager {
...
    public synchronized boolean addLogger(Logger logger) {
...
        Logger plogger = Logger.getLogger(pname);
    }
...
}

There is a problem if there are two threads calling these two methods. Say Thread 1 calls Logger.getLogger() in its application code, e.g.

public void doSomething() {
  Logger.getLogger("com.stc.test").info("doSomething!");
}

Now let's consider another thread Thread 2 tries to register a custom logger using addLogger(), e.g.

LogManager.getLogManager().addLogger(new Logger() {
...
});

There are two locks that come into the picture: one is the lock on Logger.class, and the other one on LogManager.getLogManager(). Thread 1 simply calls Logger.getLogger() which first locks Logger.class, and while having this lock, will call LogManager.addLogger(). This call will get a lock on LogManager.getLogManager(). This will try to lock Logger.class again, which is no problem because it already had the lock on that. Now consider Thread 2: it will first lock LogManager.getLogManager() through its call to addLogger(), and while having this lock, it will try to lock Logger.class through its call to Logger.getLogger().

So Thread 1 will lock first A and then B, while Thread 2 will first lock B and then A. A classical deadlock situation.

This is clearly a bug in the JDK. With the knowledge of this bug, as the developer of the custom logger, we can use a simple workaround for this problem. Before calling addLogger(), first lock Logger.class. By doing that, we can guarantee that the locks are called in the same order: first Logger.class and then LogManager.getLogManager().

This bug was actually reported by a customer, see bug report, and was fixed in 6u11 and 5.0u18. The LogManager now no longer calls Logger.getLogger(), so there's no locking of Logger.class anymore.

Deadlock in GlassFish

GlassFish installs its own LogManager, and there's some locking going on there too. It has an internal lock which it locks in addLogger():

    public boolean addLogger(Logger logger) {
...
    super.addLogger(logger);
...
    synchronized (_unInitializedLoggers) {
...
        doInitializeLogger(logger);
    }
}

And this calls Logger.getLogger() again.

    protected void doInitializeLogger(Logger logger) {
...
    Logger newLogger =
        Logger.getLogger(logger.getName(), 
            getLoggerResourceBundleName(logger.getName()));
...
    }

As a developer of the custom logger, we can still use the same fix: first lock Logger.class before calling addLogger() so that the locking sequence becomes: Logger.class, transient lock on LogManager.getLogManager() followed by a lock on _unInitializedLoggers, lock on Logger.class().

A fix in GlassFish would simply make addLogger() synchronized. An alternative fix is to make the synchronized block smaller: it should not extend over doInitializeLogger().

Deadlock with the IBM JDK

All was well until this was run on the IBM JDK. As it turns out, Logger.getLogger() doesn't lock Logger.class, it locks LogManager.getLogManager(). Now there is a new deadlock: Thread 1 calls Logger.getLogger() and by doing so, locks LogManager.getLogManager(), and then tries to lock _unInitializedLoggers and later tries to lock LogManager.getLogManager() again. Thread 2 calls addLogger() and by doing so locks first _unInitializedLoggers which later tries to lock LogManager.getLogManager(). The problem is back: the sequence of locking is reversed.

Lessons learned

The first lesson is that of the deadlock itself: one should be extremely careful when locking an object, and then calling into another object, especially if that object is meant to be a baseclass in a public API. Both Logger and LogManager may be overridden, and are clearly very public.

The second lesson is that instead of building workarounds, try to get a fix the original bug. Or at least try to have the original issue addressed while adding a workaround. In my case, I never filed a ticket against the JDK or against GlassFish. I should have known better.

... or not?

At this very moment, GlassFish v2.1.1 is about to be shipped, and we need GlassFish v2.1.1 on AIX for the upcoming CAPS release. A bug fix in GlassFish v2.1.1 is probably not going to get in. So I'm making yet another workaround: don't use a custom logger at all as to avoid the whole addLogger() problem. Instead, use standard Logger objects, but provide a custom filter that manipulates the log record. This will work on both unpatched versions of GlassFish, and also on unpatched versions of the JDK. Still, I hope the GlassFish problem will be fixed.

Friday, August 28, 2009

JavaOne 2009 TS-5341: Rethinking the ESB: lessons learned challenging the limitations and pitfalls – audio recording uploaded

image

At JavaOne 2009 I gave a number of presentations. One was "Rethinking the ESB: lessons learned challenging the limitations and pitfalls" which I did with Andi Egloff. JavaOne sessions were not recorded this year, that is not by the JavaOne Organization. But I used an mp3 player to record the sessions I was involved in. I finally processed the audio and uploaded it. I also uploaded a PDF of the presentation:

Thursday, August 6, 2009

Message interceptors with JMS

Interceptors are a way to add behavior to a system without directly invoking this behavior in from code. The typical anti-example is that if you would want to log the entry and exit of methods on a class, you could do that of course by adding log statements in each and every method. The downside is that you would have to change each and every method, and that all these methods now have repetitive code in there. With the interceptor approach on the other hand, you could do that by adding an interceptor that is invoked before and after the method is invoked. In the code of the interceptor you would then add the log statement. The advantage is that the existing methods are not changed, that repetitive code is avoided, and that the logging concern is concentrated in one part of the code base rather than spread all over.

I think that this logging example is pretty dumb, but I guess it drives home the message of adding behavior non-invasively, and a separation of concerns. I'll discuss some more interesting examples in a minute.

Interceptors in EE

Interceptors have long been the domain of AOP (Aspect Oriented Programming) packages that add interceptors through byte code manipulation, either at runtime or as a post-compile step. For EE developers, things changed with the advent of EE5 in which interceptors were added to EJBs.

An interceptor can be added to all the methods or individual methods of an EJB by adding an annotation to either the class or to individual methods. In the following example, the NoConcurrency interceptor is invoked when the getUnclaimedAccounts() method is called.

@Interceptors(NoConcurrency.class)
public void getUnclaimedAccounts(String category) {...

The interceptor class is a simple Java class that has to have a method with the following signature:

@AroundInvoke
Object <METHOD>(javax.interceptor.InvocationContext) throws Exception

The interceptor method is called when a client calls an EJB method. The interceptor typically calls InvocationContext.proceed(). This will call into the EJB method (or the next interceptor, should there be one).

Interceptor classes are typically packaged as part of an EAR file: they are part of the application.

Interceptors are referenced in an EJB using the @Interceptors annotation. They can also be referenced from the EJB's deployment descriptor. In either case, the application needs to be modified to specify interceptors.

Another limitation of EJB interceptors is that they only work on EJB methods. When common behavior needs to be added to other interactions, for instance if an EJB invokes something like an outbound resource adapter, a different mechanism must be used.

Interceptors in CAPS

A Java CAPS customer had an interesting case for using interceptors. The customer had hundreds of integration applications that all received and sent JMS messages. If a message cannot be processed, the message is sent to an error handling system using JMSJCA's dead letter queue facility. An operator will monitor the dead letter queue, and may resubmit the message. If a resubmitted message is processed successfully, the error handling system needs to be notified of that fact. One way of adding this behavior would be to add a chunk of code to all MDBs. That would of course lead to a lot of duplicated code. It also leads to mixing this system level behavior with the business logic in the integration applications. This is clearly undesirable.

Because Repository based projects in Java CAPS generate all the MDB code and assembles the applications, it is difficult to make use of EJB interceptors. What is needed is to specify the use of interceptors on a global basis, that is outside of the applications, and preferably for all applications at the same time.

Another requirement is that the customer wanted to add common behavior not just when messages are received, but also when messages were sent from an EJB. Upon sending a message, payload validation should happen. Since EJB interceptors can only be used for EJB methods, this was another reason that EJB interceptors could not be used.

The solution was to add a new feature to JMSJCA to support interceptors.

Interceptors in JMSCA

Interceptors in JMSJCA are invoked not only before / after a message is delivered to the MDB, but also any time a message is sent.

Rather than introducing a new Java interface, which would bring with it the complication of compile time dependencies on JMSJCA jars, the JMSJCA interceptors use the same annotations as in EJB3: any class with a method with the right signature and the @AroundInvoke annotation can serve as an interceptor.

Which classes will JMSJCA consider as interceptors? For this, it uses the service locator mechanism from JDK 6. This is done without introducing dependencies on JDK 6 by the way. With the service locator mechanism, a jar that holds the interceptor should have a special manifest file that lists the class names of the interceptors. The name of this manifest should be META-INF/services/myinterceptor where myinterceptor is the name of the interceptor. This name needs to be specified in the JMSJCA configuration. If no name is specified, the default name jmsjca.interceptor is used. This means that interceptors using the service name jmsjca.interceptor are automatically loaded and invoked if not overridden in the JMSJCA configuration.

With this, it's easy to add interceptors to all applications running in the application server, whenever they send or receive messages through JMSJCA, without having to change any application.

For more information, see http://jmsjca.dev.java.net/ .

Sunday, May 31, 2009

JavaOne 2009

I'm writing this on my way to JavaOne 2009. San Francisco airport was fogged in so my flight was cancelled. I have some time to burn: I'm waiting for a train to take me from Santa Clara to San Francisco.

As usual it has been immensely busy in the two months before JavaOne.

For this JavaOne, I'm the lead of the SOA/Services track. A track lead is responsible for assembling a program of sessions and BOFs. Or in more practical terms, going through the proposals with the other volunteers that make up the selection committee, and picking the proposals so that not only the quality but also the variety of the track is optimal. The selection committee consists of subject matter experts. There are three from Sun and four from other companies: RedHat, Cap Gemini, Adobe.

This year there again were many hundreds of proposals for sessions and BOFs. Going through them to make a first cut took a lot of time. Refining the first cut to the final selection is difficult: there were many good and interesting proposals. But in the end only 22 sessions could prevail. Getting consensus on the selections, scheduling them, ensuring that presentations are ready, reviewing the presentations, the inevitable change requests, etc. took a lot more time than I expected. But I think these efforts have paid off: I think we have a very interesting lineup of presentations.

My second JavaOne activity is presenting at Java University, the day before JavaOne. Like last year, Joe Boulenouar invited me to present a few hours on SOA and integration middleware. The course title is "Using Java EE and SOA to Help Architect and Design Robust Enterprise Applications." Last year there were four hundred or so people in attendance. I haven't heard yet how many people there will be this year. Perhaps fewer on account of the poor the economy.

Thirdly, I'm presenting a session titled "Glassfish ESB: get your apps on the bus". The original plan was that Keith Babo would pull that wagon, but unfortunately he had to pull out. I'm now doing that session with Sujit Biswas. In this session I'm making a case for ESBs or integration middleware in general. This has led me to some more thoughts on how we can widen the applicability of ESBs. More about that in a future post.

I'm also doing a session titled "Rethinking the ESB: lessons learned challenging the limitations and pitfalls". Andi Egloff is co-presenter. The idea of this session is to show a number of things that went wrong in previous product releases and how we changed that in subsequent releases. The interesting part for the audience is that it gives a set of requirements or "things to avoid" in middleware products.

The fifth activity I'm involved in is the OpenESB community BOF. The idea of this BOF is to discuss experiences with OpenESB and discuss what's on the wish list for OpenESB.

So, yes, it was busy running up to JavaOne. I'm sure that JavaOne itself will also be very busy: not only will there be the presentations I need to give, others I have to be in attendance for, but there will also be the numerous customer meetings.

I think I'll need a break after JavaOne!