Tuesday, April 10, 2007

Where Java EE goes horribly wrong

Sure, Java EE covers everything but the corner cases... but why, oh why are there so many corner cases?!

Java EE rocks, it really does. I'm usually quite happy working with it. But it strikes me -- while it handles nearly everything but the corner cases, it leaves so many corner cases as to make itself less useful than it could or should be. It's the Achilles' heel of Java.

For example, look at my recent travails with getting a JMS destination populated for an EIS component. This shouldn't be that big of a deal, really, considering that I've an inbound EIS component that communicates with a resource in JNDI.

Here's the backstory: I'm writing an EIS component to receive mail. It needs to falsify email addresses (i.e., all addresses are dynamic) and my intent was, as email came in, to forward each email to a JMS queue. The JMS queue would be listened to by a message-driven bean, which would ignore the email or ... well... not ignore it.

I wanted this in an EIS component because that way I don't have to remember to start up all of my application components: I'd start my database and my application server, and be done with it.

Thus, my EIS component wants to have JMS ready to go when it starts, because otherwise it'll bind to a port and have nowhere to go with it. That's where my "problem" comes in.

It turns out that in Glassfish, JNDI isn't populated until after server startup finishes. Thus, my EIS component initializes, and it will never have JNDI available to it when it starts. That's by design, apparently, and is the source of a bug I filed with Glassfish already, if I'm not mistaken. (Bug #1950, which happens to be the year I wasn't born.)

I need a Glassfish Lifecycle module, to watch for when the server is ready, and then I can get the JNDI context from the lifecycle process. I can start threads there (as long as I shut them down) and do whatever I need. This is in some ways a cleaner solution than what I'd done, because instead of balkanizing SubEthaSMTP, I can just start SubEthaSMTP in a lifecycle module and have done.

But... what happens if I want to move to, say, JBoss? Or OC4J? Or WebLogic? Or WebSphere? Geronimo? JONAS? RESIN? I'm using Glassfish for the moment, for development - primarily because it's the reference implementation of the specification, not for any magical qualities it has as an application server. Writing a lifecycle event is fine if I'm staying on Glassfish, but I have no desire to be tied to a specific server if I can help it. These lifecycles are specific to Glassfish - other servers aren't likely to follow its lead.

Java EE has, in this case, failed me. This isn't that big of a deal, except for this is the kind of corner case that you run into over and over and over and over again with Java EE.

You want to know why people look at Spring as if it's the Messiah? You want to know why TheServerSide.com keeps yakking about OSGi and grids and Ruby and AJAX and other stuff? THIS IS WHY. They provide ways around the corner cases. Not always - I'm waiting for an OSGi or Spring template for an application server (i.e., "inject an app server into this bean and start it...") but that allows us to treat the corner cases like what they are - corner cases instead of barriers to constantly be confronted.

Java EE doesn't suck - not really - but let's be real, it DOES suck in ways it shouldn't. The spec has to have ways to address these corner cases, provide things that developers like me can rely on. I know I have options here, I'm just dissatisfied with every cotton-pickin' one of them.

Some people are going to argue that providing injection points for these problems will increase complexity - witness people complaining about all the phaselistener things in JSF 2.0. Hey, I get that. But let's be realistic: you don't have to use the capabilities if you don't need them. It's just that if you do need them, right now, you're left adrift, screwed over by spec authors who feel that it's more important to address common capabilities instead of common NEEDS.

This has got to change, or else Bruce Tate's proclamation that Java is "dead like COBOL" - meaning quite alive, but not extremely vibrant - will come true after all.

No comments: