@DataSourceDefinition — A Hidden Gem from Java EE 6

In the old days, DataSources were configured — well, they were configured in lots of different ways… That’s because there was no ‘one way’ to do it — in JBoss, you created an XML file that ended in ‘-ds.xml’ and dumped it in the deploy folder… in Glassfish, you either use the admin console or muck with the domain.xml file… in WebLogic you used the web console… and this was all well and good — until I worked with an IT guy who told me just how much of a pain in the ass it was…

Up until then, it wasn’t such a big deal to me — I set it up once, and that was that… then I ran into this guy a few jobs ago who liked to bitch and complain about how much harder it was to deploy our application than the .NET or Ruby apps he was used to… he had to deploy our data source, then he had to deploy our JMS configurations — only then would our application work… in the other platforms, that was all built into the app (I’ll have to take his word for it, since I haven’t actually deployed anything in either platform)… I was a but surprised at first, and then I realized that maybe he had a point… nah, it couldn’t be, he must just be having a bad day (lots of us were having bad days back then 🙂 )…

Then I ran into Grails, which is dead simple — you have a Groovy configuration file that has your db info in it… you even have the ability to specify different ‘environments’, which can change depending on how you create your archives or run your app… pretty slick…

The Gem

Well, lo and behold, we now have something that’s nearly equivalent in Java EE 6 — the @DataSourceDefinition attribute… it’s a new attribute that you can put on a class that provides a standard mechanism to configure a JDBC DataSource into JNDI, and as expected, it can work with local JNDI scopes or the new global scope, meaning you can have an Environment Configuration that uses this attribute making it shareable across your server… it works like this:


import javax.annotation.sql.DataSourceDefinition;
import org.jboss.seam.envconfig.Bind;
import org.jboss.seam.envconfig.EnvironmentBinding;

@DataSourceDefinition (
className="org.apache.derby.jdbc.ClientDataSource",
name="java:global/jdbc/AppDB",
serverName="localhost",
portNumber=1527,
user="user",
password="password",
databaseName="dev-db"
)
public class Config {
...
}

As you would expect, that annotation will create a DataSource that will point to a local Derby db, and stick it into JNDI at the global address ‘java:global/jdbc/AppDB’, which your application, or other applications can refer to as needed… no separate deployment and no custom server-based implementation — this code should be portable across any Java EE 6 server (including the Web Profile!)…

It’s almost perfect!

In typical Java EE style, there’s one thing that just doesn’t appear to be working the way I’d like it — it doesn’t appear to honor JCDI Alternatives (at least not in Glassfish)… Here’s what I’m thinking — we should be able to have a different Config class for each of our different environments… in other words, we’d have a QAConfig that pointed to a different Derby db, a StagingConfig that pointed to a MySQL db somewhere on another server, and a ProductionConfig that pointed to kick ass, clustered MySQL db… we could then use Alternatives to turn on the ones that we want in certain environments with a simple XML change, and not have to muck with code… unfortunately, it doesn’t appear to work — it appears in Glassfish that it is processing them in an undeterministic order, with (presumably) the class that is processed last overwriting the others that came before it…

There is a solution, though, and it is on the lookup side of the equation — using JCDI Alternatives, we can selectively lookup the DataSource that we’re interested in, and then enable that Managed Bean in the beans.xml file… it’s definitely not ideal, since we need to actually inject all of our DataSources into JNDI in all scenarios, but it works, it’s something I can live with, and is probably easily fixed in a later Java EE release… Update: Looks like it’s in the plan, according to this link — thanks, Gavin 🙂

Here’s how it works — first the ‘common’ case, probably for a Development environment:


@RequestScoped
public class DSProvider {
@Resource (lookup="java:global/jdbc/AppDB")
private DataSource normal;

public DataSource getDataSource() {
return normal;
}
}

Simple enough — has a field that looks up ‘jdbc/AppDB’ from JNDI, and provides a getter… now for QA:


@RequestScoped @Alternative
public class QADSProvider extends DSProvider{
@Resource (lookup="java:global/jdbc/AppQADB")
private DataSource normal;

public DataSource getDataSource() {
return normal;
}
}

Pretty much the same, except this does the lookup from ‘jdbc/AppQADB’, and it is annotated with @Alternative… so how do these things work together? Take a look:


@Named
public class Test {
@Inject
private DSProvider dsProvider;

...
}

Again, simple — we’re injecting a DSProvider instance here, and presumably running a few fancy queries… Nothing Dev-ish or QA-ish here at all, which is the beauty of Alternatives… finally, when building the .war file for QA, we turn on our Alternative in the beans.xml, like so:




com.mcorey.alternativedatasource.QADSProvider


You’ll notice that this solution requires us to rebuild our .war file for QA, which I obviously don’t like — not to worry, there will be support for this in the Seam 3 Environment Configuration Module, which will effectively create a binding by mapping from one JNDI key to another… I have no idea what the syntax will look like at this point, but it should be pretty straight forward, and will allow us to — you guessed it — build our .war one, and copy it from place to place without modification…

M

http://pagead2.googlesyndication.com/pagead/show_ads.js

Say hello to the Seam 3 Environment Configuration module

A funny thing happened after my last post — I got an email from Dan Allen, from RedHat, with some interest in making my last JCDI Portable Extension — EnvironmentBindingExtension — into a Seam 3 Module… pretty cool for a fairly modest effort at finding a new way to solve a problem I’ve faced in the past… it will be my first official foray into open source (not counting that one line NetBeans patch I submitted in, like, 2000), so it will be interesting to see how this will actually work from the authoring side, as opposed to the user side, especially in a relatively well organized project like Seam

What it’s about

The idea behind the Environment Configuration module is to inject fairly static configuration information into any JEE 6 environment… it’s typically done outside of your application, in a deployment that isn’t regularly deployed or updated, so you can configure each of your environments separately, including Development, Testing, QA, Staging and Production — once this is done, you can build your application once (or better yet — have a Continuous Integration server build it!), and copy the same binary from server to server without having to reconfigure it, ensuring that the archive that you deploy to production is the same exact archive that you tested in QA… this allows you to streamline your deployment processes, removing any possible human error involved in building your code over, and over, and over again (and in some cases, it’ll save a lot of time if you have a particularly slow build!)

How’s it work? It takes advantage of JNDI — one of the resources that all JEE servers provide… say, for example, that you have a system that needs to access a database, a filesystem, and has a batch process that runs at a specific frequency — in development, you’ll want to point to a personal Derby database, use a local folder on your Windows box for your filesystem, and run the batch process very frequently for testing… QA is similar, although it has different database, but say Staging and Production run on a cluster of Linux boxes that access a MySQL database, use a mounted shared drive for its’ filesystem, and have its’ batch processes run once an hour…

With the Seam 3 Environment Configuration module, you can create a simple .ear file for each of these environments that contains all of this data — create them once, deploy them once, and you’re good to go… take a look at the following example of a configuration that you could use in development:


/**
* An Environment Configuration for Development
* @author Matt
*/
@EnvironmentBinding
@DataSourceDefinition (
className="org.apache.derby.jdbc.ClientDriver",
name="java:global/jdbc/AppDB",
serverName="localhost",
portNumber=1527,
user="user",
password="password",
properties={"create=true"},
databaseName="dev-db"
)
public class Config {
@Bind ("myApp/fs-root")
String rootFolder = "C:\fs-root";

@Bind ("myApp/batch-frequency")
long batchFrequencyInMs = 60 * 1000;
}

Pretty simple — toss this class into its’ own .war file, and it will define three global JNDI entries, one for each of the items mentioned above… your other applications are now free to read these resources in whatever way they need to, even using the standard @Resource(lookup=”java:global/myApp/fs-root”) notation… a similar configuration file would be created for QA, but perhaps the @DataSourceDefinition annotation will use a MySQL datasource, and likewise for Staging and Production…

What next?

Well, there are a few things on my list of features here, including, but not limited to:

  • Test, Test, Test!
  • Using the @Bind attribute on methods, including @Produces methods
  • Support ‘unbinding’, if needed
  • Create a Maven Archetype that could be used to quickly and easily setup an Environment Configuration deployment
  • Create an interface of some kind to be able to review the available findings — either web app or simply JAX-RS based

I am, of course, interested in any ideas or feedback anyone would have, but one goal I would have here is to keep it simple and portable — what this module is intended to do isn’t exactly brain surgery, so I don’t think it’s necessary to throw in too many ‘extras’…

M

http://pagead2.googlesyndication.com/pagead/show_ads.js