Java Development News:

Components, Design, and Functions

Components, Design, and Functions
...or some rambling about IoC and design in webapps. Basically, I want to look at some idioms that
have proven really useful for ubiquitous components in web applications over the last year or
so.

First, nano
got the container scopes exactly right, I think. The key here is three component containers -- one
at the application scope, one at the session scope, one at the request scope, each has the previous
as its parent. The application container is initialized and destroyed with servlet context
startup/shutdown, the session with session creation/destruction/activation/passivation, and request
container is rebuilt for each request.

So, lets look at an example, we'll steal a page from Matt Raible and simply look at a user
registration/authentication use case. To accomplis this we need a few things -- a User class, a
persistence system (Apache OJB), a use DAO (optional, but usually worthwhile), and a transaction
system (awfully handy). Let's start at the lowest level and look at data access.

Because datastore and transactions are so closely tied together in most apps (not a bad thing,
if you don't need distributed transactions, don't use em), we'll go ahead and build a TxRunner component called TxRunnerImpl which knows OJB. This component just
knows about OJB, and can run Tx instances. Usage looks something like (credit a
coworker of mine for a lot of the look of this particular runner, in a different form, for a
different system):

This design doesn't hide that OJB is being used, if that needs to happen, you can pass some
interface which knows how to execute queries, inserts, etc. I just expose the broker. The TxRunner
wraps the Tx in a transactions, rolls back on exceptions, etc. It can also be very nicely matched
by a cflow ;-)

Now, take a look back at the TxRunnerImpl and look at its constructors. It, really,
isn't dependent on anything. When instantiated in unit tests the String constructor can be used,
when in a container the ServletContext. I am open to arguments about allowing it to be dependent on
the ServletContext, but it works well for auto-wiring. If this were Spring, I'd get rid of the ctx
and just specify the string parameter in the config xml. Right now there is no configuration xml,
and I don't want to add it for this.

Okay, lets now look at something to use this, our UserDAO implementation, UserDAOImpl. The impl depends on the TxRunner,
declared in its lone constructor. It uses this in order actually find/insert/etc User instances.
Nothing terribly fancy here. Do notice that it wraps exceptions in a service layer exception, again
no biggie.

We have two final components, a Session data holder, and an Authenticator. The SimpleSession is dirt simple with no dependencies. It
just holds session state (the logged in user). The SimpleAuthenticator is more interesting. It depends on
the UserDAO and the Session components. It also, finally, provides a service method
(authenticate(String,String): void) which uses those components (sets found user in session if
valid, throws exception if invalid (you can argue this point as well, I like exceptions for auth
failure, other people like returning error codes)). It is worth noting that the only reason there
is an interface/impl seperation between these particular components is for unit testing (maniax is
allowed to argue this one, but notice they are seperated ;-)

Okay, so we have these components, nothing too fancy anywhere here. What do we do with them?
Let's see an app which can use them. The example will be a simple little nanoweb thing. We wire up
the components as follows:

One subtle thing here... The application scope components are pretty straightforward, and the
session scoped component is obvious. The Authenticator is a request scoped object though. It is
dependent on the Session in the session container, and the UserDAO in the application container, so
its deps can be met going up the chain. It could fit in the session container and still meet its
deps as well. It is in the request, though, so that it is only instantiated for actions (or other
requst scoped components) which actually require it. So, let's see it used:

This action will be instantiated via a PicoContainer whose parent is set to the request scoped
container. It will, therefore, receive the authenticator and can do its stuff. Sweet and simple =)
Now, the authenticator could as esily be used as a service backend to a single-signon service,
desktop app, etc. I used nanoweb here as it is a great for short-and-sweet type things (like this
example) and has mostly replaced ruby/cgi for minimal web apps for me as it simply give syou so
much for so little.

About the author

Brian McCallister doesn't particularly like writing bios or writing about himself in the third
person. He does love programming and systems work though, and tends to find himself doing a lot of
both. Brian has also quite enjoyed giving presentations and seminars in the past, which isn't too
hard as he loves teaching and exploring new ideas.

TechTarget provides technology professionals with the information they need to perform their jobs - from developing strategy, to making cost-effective purchase decisions and managing their organizations technology projects - with its network of technology-specific websites, events and online magazines.