JSTL Config voodoo

I'd like to create a persistent (probably singleton) class to marshal database access for my servlets and jsps. I was browsing around and I stumbled upon the following information regarding database implementation for JSTL:

(from http://www.onjava.com/pub/a/onjava/2002/09/11/jstl2.html?page=3)

An alternative for containers that do not support JNDI is to let an application (servlet context) lifecycle listener create and configure a DataSource and set it as the default using the JSTL Config class:

import javax.servlet.*;

import javax.servlet.http.*;

import oracle.jdbc.pool.*;

publicclass AppListenerimplements ServletContextListener{

private OracleConnectionCacheImpl ds =null;

publicvoid contextInitialized(ServletContextEvent sce){

ServletContext application =sce.getServletContext();

try{

ds =new OracleConnectionCacheImpl();

ds.setURL("jdbc:oracle:thin:@voyager2:1521:Oracle9i");

ds.setMaxLimit(20);

ds.setUser("scott");

ds.setPassword("tiger");

}

catch (Exception e){

application.log("Failed to create data source:"+

e.getMessage());

}

Config.SQL_DATA_SOURCE;

}

...

}

After reading this, I posited to conclusions:

1. A ServletContextListener is a persistent class that is fair game for marshaling database connections...though I'm not sure how one would actually keep a library of queries within it... which would probably shovel the actual SQL query code back on a servlet (probably not good, please advise).

2. JSTL has magical powers! WTF is this line?:

Config.SQL_DATA_SOURCE;

It looks like it's just naming a member of Config without doing anything with it. To invoke a method, doesn't it at least requre a '()'?! Furthermore, by adding this one line, now somehow it

a. Knows when a servlet needs a connection

b. Knows which servlet needs the connection

c. Knows how to pass the connection back

...all without implementing any other methods or interfaces!

either that or his '...' is a very powerful DWIM implementation.

What is going on here? Please!

[2942 byte] By [dcaudella] at [2007-11-27 11:17:25]
# 1

> I'd like to create a persistent (probably singleton)

Why singleton? So you'll force every thread to share a single database connection? There's a word for a design like that: "bottleneck".

> class to marshal database access for my servlets and

> jsps. I was browsing around and I stumbled upon the

> following information regarding database

> implementation for JSTL:

>

> (from

> http://www.onjava.com/pub/a/onjava/2002/09/11/jstl2.ht

> ml?page=3)

This reference is from 2002. Be careful about "best practices" that are five years old.

> An alternative for containers that do not support

> JNDI is to let an application (servlet context)

> lifecycle listener create and configure a DataSource

> and set it as the default using the JSTL Config

> class:

What container are you using that doesn't support JNDI?

There might have been Java EE containers that didn't support it in 2002, but I'm betting that the one you're using does.

> After reading this, I posited to conclusions:

>

> 1. A ServletContextListener is a persistent class

> that is fair game for marshaling database

> connections...

What do you mean by persistent class? All it does is listen for the events that signal the start and end of a servlet's lifecycle. So when it gets the event for "servlet created", it can create the database connection. When it gets the event "servlet destroyed", it can close the database connection. One connection per servlet.

> though I'm not sure how one would

> actually keep a library of queries within it

That you shouldn't do.

> ... which

> would probably shovel the actual SQL query code back

> on a servlet (probably not good, please advise).

>

> 2. JSTL has magical powers! WTF is this line?:

> > Config.SQL_DATA_SOURCE;

>

>

> It looks like it's just naming a member of Config

> without doing anything with it. To invoke a method,

> doesn't it at least requre a '()'?!

What if it's a public static variable? Would you need a "()" then? (Hint: No.)

This is just a reference to a static SQL data source.

> a. Knows when a servlet needs a connection

When the servlet is created.

> b. Knows which servlet needs the connection

The servlet that generated the "created" event.

> c. Knows how to pass the connection back

"pass the connection back" to whom? It's just create/destroy here.

See servlet context listener above.

You're better off with a JNDI connection pool. It's 2007.

%

duffymoa at 2007-7-29 14:24:48 > top of Java-index,Java Essentials,Java Programming...
# 2

> Why singleton? So you'll force every thread to share a single database connection? There's a word for a design like that: "bottleneck".

Right, just like that, only one connection pool, instead of one connection.

> What container are you using that doesn't support JNDI?

For me, this isn't really the issue. Say I want to write every line of database access code from loading the JDBC driver forward, myself, just because I feel like it. Anyway, my purpose is to understand what's going on in this example...even if it was going on 5 years ago.

> What do you mean by persistent class?

This is a clencher. Sorry, I was working under the mistaken impression that servlets were instantiated on a per-session basis. By persistent, I meant instantiated at the time the container is loaded and not destroyed until the container is unloaded.

Honestly & sincerely, here, forgive if I'm being exceptionally dense, but...

>> Config.SQL_DATA_SOURCE;

> What if it's a public static variable? Would you need a "()" then? (Hint: No.)

Right... Config is a 'javx.servlet.jsp.jstl.core.Config' and SQL_DATA_SOURCE is apparently a public string within that class. But...

I tried the example myself, and I probably just can't figure what I'm leaving out, but it kinda seems like the compiler is having the same reaction to that line that I did:

D:\...\MyListener.java:40: not a statement

Config.SQL_DATA_SOURCE;

So going line by line, here:

public void contextInitialized(ServletContextEvent sce){

// This will be called once when the container is built.

ServletContext application =sce.getServletContext();

// This gets the ServletContext, which is 'persistent' information about the

// container.

try {

ds = new OracleConnectionCacheImpl();

ds.setURL("jdbc:oracle:thin:@voyager2:1521:Oracle9i");

ds.setMaxLimit(20);

ds.setUser("scott");

ds.setPassword("tiger");

}

// This builds a connection pool as implemented by Oracle (I guess)

//...I've only really worked with postgres & informix

catch (Exception e){

application.log("Failed to create data source:"+

e.getMessage());

}

// ^^pretty obvious

Config.SQL_DATA_SOURCE;

// This isn't even compiling for me. Seems like it probably isn't supposed to.

}

...

}

>> a. Knows when a servlet needs a connection

> When the servlet is created.

>> b. Knows which servlet needs the connection

> The servlet that generated the "created" event.

So in the code, we see a connection pool being instantiated when the container kicks off... but what we don't see in this code is any reference to that connection pool being passed anywhere... let alone back to the servlets.

You'll notice that 'application' isn't even referenced. If there were some line like:

application.setAttribute("here's the database", ds);

or

Config.set(application, "here's the database", ds);

or maybe even something as retarded as

Config.SQL_DATA_SOURCE = ds.toString();

I could handle it. But there's nothing like that in this code snippet from the article. So I'm wondering if it was just left out, or if I don't get something.

Anyway, I really appreciate you having a look at this, and if I really am being dumb here, and you can tolerate it a little longer, I'd love a little more insight. Thanks.

dcaudella at 2007-7-29 14:24:48 > top of Java-index,Java Essentials,Java Programming...
# 3

> > Why singleton? So you'll force every thread to

> share a single database connection? There's a word

> for a design like that: "bottleneck".

>

> Right, just like that, only one connection pool,

> instead of one connection.

Pools not a bottleneck in this case. It'll get the connections out fast enough for you. The way you were describing it, I thought you meant one connection.

> For me, this isn't really the issue. Say I want to

> write every line of database access code from loading

> the JDBC driver forward, myself, just because I feel

> like it.

For education's sake, perhaps. But not for anything that you'd deploy for someone else to use.

> Anyway, my purpose is to understand what's

> going on in this example...even if it was going on 5

> years ago.

Plenty of stuff to keep up with from today.

> This is a clencher.

"Clincher"?

> Sorry, I was working under the

> mistaken impression that servlets were instantiated

> on a per-session basis.

Better read about the servlet life cycle. I don't think you understand how it works.

> By persistent, I meant

> instantiated at the time the container is loaded and

> not destroyed until the container is unloaded.

Servlets have a lifecycle that's distinct from their context. That's why there are separate Listeners for Context and Servlet.

Servlets can be pooled by the container, so you might have several servlets for a single context depending on how you've configured your container.

> Honestly & sincerely, here, forgive if I'm being

> exceptionally dense, but...

>

> >> Config.SQL_DATA_SOURCE;

> > What if it's a public static variable? Would you

> need a "()" then? (Hint: No.)

>

> Right... Config is a

> 'javx.servlet.jsp.jstl.core.Config' and

> SQL_DATA_SOURCE is apparently a public string within

> that class. But...

Yes.

> I tried the example myself, and I probably just can't

> figure what I'm leaving out, but it kinda seems like

> the compiler is having the same reaction to that line

> that I did:

>

> > D:\...\MyListener.java:40: not a statement

> Config.SQL_DATA_SOURCE;

What import do you have for the Config class?

>

> So going line by line, here:

>

> [code]

> public void contextInitialized(ServletContextEvent

> sce){

> // This will be called once when the container is

> built.

>

> ServletContext application

> =sce.getServletContext();

> // This gets the ServletContext, which is

> 'persistent' information about the

> // container.

>

>try {

> s = new OracleConnectionCacheImpl();

> ds.setURL("jdbc:oracle:thin:@voyager2:1521:Oracle9i")

> ;

> ds.setMaxLimit(20);

> ds.setUser("scott");

> ds.setPassword("tiger");

>}

> // This builds a connection pool as implemented by

> Oracle (I guess)

> //...I've only really worked with postgres &

> informix

>

>catch (Exception e){

> pplication.log("Failed to create data source:"+

> e.getMessage());

>}

> // ^^pretty obvious

>

> Config.SQL_DATA_SOURCE;

> // This isn't even compiling for me. Seems like it

> probably isn't supposed to.

>

> ...

> }

>

This code is not what I'd recommend. If you're really interested in education, you can start by at least externalizing your database connection information. Hardwiring it in the servlet is a bad idea.

What is a servlet doing with database info? Servlets handle HTTP requests. If you're doing a good OO design, wouldn't you want to move database stuff into a separate persistence layer? It'll be easier to test (no servlet or container involved) and you can use it even if you don't use the servlet.

Sorry, this is just not the best way to do this.

> Anyway, I really appreciate you having a look at

> this, and if I really am being dumb here, and you can

> tolerate it a little longer, I'd love a little more

> insight. Thanks.

I'll do my best. Don't worry about being "dumb", we're all ignorant, just about different things.

When I've seen the default data source used, it's been in the context of JSTL-based JSPs that use <sql> tags. I do not see any value at all in doing it the way you're doing it. You're tying yourself unnecessarily to Oracle, you've hard-wired your connection information needlessly, you aren't using JNDI - just not a good thing.

I would recommend abandoning that 2002-vintage example. It's simply not the way to do it in 2007.

%

duffymoa at 2007-7-29 14:24:48 > top of Java-index,Java Essentials,Java Programming...
# 4

> Plenty of stuff to keep up with from today.

Thought I ought to have a good handle on how to do things myself before I jump into J2EE, EJBs, auto-generated code, persistence layer api...et al. But yeah, point taken. So forget that example.

> If you're doing a good OO design, wouldn't you want to move database stuff into a separate persistence layer?

Yes! That's exactly what lead me to that (outdated) example in the first place. What's really eating me is how to properly build that persistence layer. It seems as though it should be a class that:

1. gets instantiated essentially once per container

2. is the sole element responsible for accessing the database

2.a: is the sole owner of connections to the database

2.b: has a pool of connections

2.c: is threadsafe so it can operate many requests for data simultaneously

2.d: encapsulates all of my SQL

3. can be accessed by servlets/jsps via invoking said class's public methods

So I went to a bookstore and picked up a book (originally written 2000, last updated 2005) from a publisher whose catalog might be mistaken for the San Francisco zoo... and it had examples of servlets implementing their own connection pools, basically from their init() methods.

<shrug>...well that doesn't satisfy any of the requirements I just listed.

So what is this mysterious element within the java web-services architecture? And _most_importantly_ how do I write it, instantiate it, and pass a reference of it to my servlets & jsps?

And I want to write my own code, here, including all of my own SQL, so no fair using the 'New Entity Class Wizard' or 'New Persistence Unit Wizard'. In fact, it would be best if I could figure out how to create my aforementioned mystery class without having to touch anything with the word 'Enterprise' in its acronym...

So does such a thing exist? Thanks again for the help :)

dcaudella at 2007-7-29 14:24:48 > top of Java-index,Java Essentials,Java Programming...