howesd
asked on
Help me understand static!
I've the following code which I am using to implement a pool of database connection pools ( our development environment needs each of our developers to have their own db pool - it's a long story.... )
Anyway, what I thought would happen is that as the applications make calls to DatabasePoolFactory.getIns tance(...) I would create one and only one hashtable and put and get poolmanager objects from it. Here's the code:
package BslDatabasePool;
import java.util.*;
import SPAR.BslException.*;
public class BslDatabasePoolFactory
{
static private Hashtable dbList = null;
/**
* Retrieves an instance of the named PoolManager. This should be used when you
* want to connect to a pool which you know ( or hope! )to be available, and you don't want to
* go to the trouble of having to define the db context. If the Pool is actually
* NOT running, then an UnknownPoolException is thrown.
*/
static public synchronized PoolManager getInstance(String PoolName) throws Exception
{
return getInstance(PoolName,(Spar DatabaseCo ntext)null );
}
/**
* Retrieves an instance of the named PoolManager, creating a new one with
* the supplied name and database context if one does not already exist. If
* a pool manager exists with the specified name, YOU WILL BE RETURNED A
* REFERENCE TO IT REGARDLESS OF WHETHER OR NOT ITS CONTEXT MATCHES THAT
* WHICH YOU PASSED IN. This means that there is a possibility that you
* may end up connecting to a database that you don't want to. Making sure
* that this doesn't happen is dependent upon sensible naming standards.
*/
static public synchronized PoolManager getInstance(String PoolName,
SparDatabaseContext SdbC)
throws Exception,
UnknownPool
{
if (dbList == null)
{
System.out.println("Creati ng New Database Factory");
dbList = new Hashtable();
}
PoolManager tmp = (PoolManager)dbList.get(Po olName);
if (tmp == null)
{
System.out.println("PoolMa nager Not Found - Creating New One called " + PoolName);
if (SdbC == null)
{
throw(new UnknownPool(PoolName));
}
tmp = new PoolManager(SdbC);
tmp.setName(PoolName);
dbList.put(PoolName,tmp);
}
else {System.out.println("Pool Already Available");};
return tmp;
}
}
My understanding of static ( which I'm sure is wrong! ) is such that, as the first call on the static getInstance method is received, a dbList hashtable will be created and the message "Creating New Database Factory" will be produced. After that, any subsequent calls to getInstance will go to the hashtable and retrieve the specified poolmanager object. This appears to happen as long as only one tomcat servlet is running. When a second servlet calls getInstance, I would expect it to see that the static hashtable dbList is already in existence and just put any new pool manager instances in to the same hashtable. What _actually_ happens is that I see another "Creating New Database Factory" message, which I guess means that a new hash table is being created and populated.
My understanding was that a static class would exist once in the JVM. This doesn't appear to be happening. Where is my understanding letting me down?
Dave
Anyway, what I thought would happen is that as the applications make calls to DatabasePoolFactory.getIns
package BslDatabasePool;
import java.util.*;
import SPAR.BslException.*;
public class BslDatabasePoolFactory
{
static private Hashtable dbList = null;
/**
* Retrieves an instance of the named PoolManager. This should be used when you
* want to connect to a pool which you know ( or hope! )to be available, and you don't want to
* go to the trouble of having to define the db context. If the Pool is actually
* NOT running, then an UnknownPoolException is thrown.
*/
static public synchronized PoolManager getInstance(String PoolName) throws Exception
{
return getInstance(PoolName,(Spar
}
/**
* Retrieves an instance of the named PoolManager, creating a new one with
* the supplied name and database context if one does not already exist. If
* a pool manager exists with the specified name, YOU WILL BE RETURNED A
* REFERENCE TO IT REGARDLESS OF WHETHER OR NOT ITS CONTEXT MATCHES THAT
* WHICH YOU PASSED IN. This means that there is a possibility that you
* may end up connecting to a database that you don't want to. Making sure
* that this doesn't happen is dependent upon sensible naming standards.
*/
static public synchronized PoolManager getInstance(String PoolName,
SparDatabaseContext SdbC)
throws Exception,
UnknownPool
{
if (dbList == null)
{
System.out.println("Creati
dbList = new Hashtable();
}
PoolManager tmp = (PoolManager)dbList.get(Po
if (tmp == null)
{
System.out.println("PoolMa
if (SdbC == null)
{
throw(new UnknownPool(PoolName));
}
tmp = new PoolManager(SdbC);
tmp.setName(PoolName);
dbList.put(PoolName,tmp);
}
else {System.out.println("Pool Already Available");};
return tmp;
}
}
My understanding of static ( which I'm sure is wrong! ) is such that, as the first call on the static getInstance method is received, a dbList hashtable will be created and the message "Creating New Database Factory" will be produced. After that, any subsequent calls to getInstance will go to the hashtable and retrieve the specified poolmanager object. This appears to happen as long as only one tomcat servlet is running. When a second servlet calls getInstance, I would expect it to see that the static hashtable dbList is already in existence and just put any new pool manager instances in to the same hashtable. What _actually_ happens is that I see another "Creating New Database Factory" message, which I guess means that a new hash table is being created and populated.
My understanding was that a static class would exist once in the JVM. This doesn't appear to be happening. Where is my understanding letting me down?
Dave
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
I agree in that it seems like your assumptions are correct and that there should only be a single Hashtable. Is it possible that multiple VM's are running somehow inside the servlet container? (I don't do much servlet work so forgive my ignorance :)
Listening Curiously...
-K
Listening Curiously...
-K
On the other hand, if you want to construct a BslDatabasePool explicitly at a certain point, you could make this class a singleton as an extra safeguard, if Tomcat will allow it. This means that you would have only *one* possible BslDatabasePool to get only *one* possible PoolManager from.
I say if Tomcat will allow it as Tom might not allow private constructors.
I say if Tomcat will allow it as Tom might not allow private constructors.
An instance of each static variable exists for every *class loader*. Tomcat uses a seperate class loader for each servlet which is resulting in what you are experiencing.
ASKER
cehjohnson - After I posted the message I realised that making it a singleton class would be a good idea ( that was what I was actually trying to achieve but I'd made a hash of it! )
objects - given what you're saying about the separate class loader for each servlet, am I wasting my time in trying to produce a poolfactory which will serve up poolmanagers across a complete tomcat installation?
Dave
objects - given what you're saying about the separate class loader for each servlet, am I wasting my time in trying to produce a poolfactory which will serve up poolmanagers across a complete tomcat installation?
Dave
>>you could make this class a singleton as an extra safeguard, if Tomcat will allow it
Even that won't work as the paper girionis mentions explains, so my suggestion won't cure the problem. The problem can be treated by applying the principles the paper's author describes beginning 'Consequences'.
Even that won't work as the paper girionis mentions explains, so my suggestion won't cure the problem. The problem can be treated by applying the principles the paper's author describes beginning 'Consequences'.
ASKER
Unfortunately, I can't read the paper - I think the firewall I'm behind might be getting in the way. I'll try to read it when I can get access from another machine.
Thanks
Thanks
ASKER
I still can't get hold of the paper .... but, if I understand objects comment about each servlet having its own classloader correctly, does this mean that I need to instantiate the DatabasePoolFactory in one servlet ( probably one that loads on startup ) and then push it into the servlet context using getServletContext().setAtt ribute(... ) and then get any other JSP's or servlets which want to use the pool to use getServletContext().getAtt ribute(... ) ( or what ever it's called - I don't have my documentation with me at the moment )?
Dave
Dave
Probably easier if we somehow get you the paper! I wonder if you can't it because of the mime type of the url? You could try this if that's the case - the pdf file is converted into html:
http://access.adobe.com/perl/convertPDF.pl?url=http://www.javageeks.com/Papers/JavaStatics/JavaStatics.pdf
If that doesn't work, let me know and I'll mail you the file.
In the meantime you can save yourself some time by implementing the singleton anyway, as we were discussing, although as you'll see when you read the document, this will not be sufficient in itself to cure the problem.
http://access.adobe.com/perl/convertPDF.pl?url=http://www.javageeks.com/Papers/JavaStatics/JavaStatics.pdf
If that doesn't work, let me know and I'll mail you the file.
In the meantime you can save yourself some time by implementing the singleton anyway, as we were discussing, although as you'll see when you read the document, this will not be sufficient in itself to cure the problem.
ASKER
CEHJ - That's very kind of you. I'll read it and let you know what I make of it
Dave
Dave
Or you can send me an e-mail to p_konstantinidis@hotmail.c om and I will mail the file to you. I rarely ever use his address anymore. It's mainly full of junk mail so I do not mind getting some more. I have just deleted all my mails cause my mail box was full, so there is space for your e-mail (if you decide to send me one).
Hope it helps.
Hope it helps.
> am I wasting my time in trying to produce a poolfactory
> which will serve up poolmanagers across a complete
> tomcat installation?
No, what you need to do is ensure your singleton pool factory is loaded by the system class loader. You can do this by ensuring the classes are found in the ext directory or the classpath.
> which will serve up poolmanagers across a complete
> tomcat installation?
No, what you need to do is ensure your singleton pool factory is loaded by the system class loader. You can do this by ensuring the classes are found in the ext directory or the classpath.
No comment has been added lately, so it's time to clean up this TA.
I will leave a recommendation in the Cleanup topic area that this question is:
- points to girionis
Please leave any comments here within the
next seven days.
PLEASE DO NOT ACCEPT THIS COMMENT AS AN ANSWER !
girionis
Cleanup Volunteer
I will leave a recommendation in the Cleanup topic area that this question is:
- points to girionis
Please leave any comments here within the
next seven days.
PLEASE DO NOT ACCEPT THIS COMMENT AS AN ANSWER !
girionis
Cleanup Volunteer
1. If you're going to use some kind of pool manager, you could arrange for it to be preloaded by the context.
2. If you're going to do that, you may as well create dbList as soon as the class is loaded:
static private Hashtable dbList = new Hashtable();
3. Since this reference will never change, why not:
private static final Hashtable dbList = new Hashtable();
4. On an unrelated note, I would rename UnknownPool to UnknownPoolException.