How do i use classloaders to create singletons

I have some code that correctly creates a singleton because the code runs within a clients vm , and there should only be instance of the class per user. But for testing purposes I would like to mimic two users, to do this they each require their own instance of the singleton. I have read that using custom classloaders there could be one instance of each singleton per classloader, but dont understand how to do this. Can someone give me an example

[456 byte] By [paultaylora] at [2007-10-2 19:07:29]
# 1
Your users are sharing the same JVM?You don't need a custom classloader, you just need a new classloader to load the Singleton class, one per user.
CeciNEstPasUnProgrammeura at 2007-7-13 20:47:19 > top of Java-index,Java Essentials,Java Programming...
# 2
Though "one singleton per user" sounds a bit wrong. If you need many instances, even though only one per user, a singleton might not be the correct pattern.
CeciNEstPasUnProgrammeura at 2007-7-13 20:47:19 > top of Java-index,Java Essentials,Java Programming...
# 3
Some example code would bve great.To reiterate I only need to do this within the context of a Junit test to mimic to test the communication between two users, it i snever actaully needed in the production code
paultaylora at 2007-7-13 20:47:19 > top of Java-index,Java Essentials,Java Programming...
# 4

In principal you can load different versions of a class in different class loaders. The problem lies in the delegation model.

When a class resolves a reference to another class, e.g. to your singleton class, it makes the request to the classloader that loaded it, not, for example, to the Thread's "context" classloader. You can't have two versions of a class on the same classloader delegation path. So you need a separate version, not just of the Singleton class, but of every class that references it.

I would suggest that a better approach might be to make what I call a "thread singleton", i.e. it has one copy of the object for each thread where it's first invoked. You could then go to a straight singleton when you finish loading.

Instead of

public static MySingleton getInstance() {

if(_inst = null) {

_inst = new MySingleton();

}

return inst;

}

Try

private static InheritableThreadLocal<MySingleton> _insts =

new InheritableThreadLocal<MySingleton>() {

public MySingleton initialValue() {

return new MySingleton();

}};

public static MySingleton getInstance() {

return _insts.get();

}

malcolmmca at 2007-7-13 20:47:19 > top of Java-index,Java Essentials,Java Programming...
# 5

Sorry dont understand this, this is only test code so just needs to work. Is there a way to write my test code (without changing the existing code) to perform my test. I was thinking of something like, LoginManager is the singleton which needs to return different instances for each thread.

public class test extends TestCase

{

public void test()

{

Login login = new Login(validUsername,validPassword);

Thread t = new Thread(login);

t.run();

Login login2 = new Login(validUsername2,validPassword2);

t2 = new Thread(login2);

t2.run();

}

}

class Login implements Runnable

{

private String username;

private String password;

Login (String username,String password)

{

this.username = username;

this.password =password;

}

public void run()

{

LoginManager= LoginManager.getInstance();

}

}

paultaylora at 2007-7-13 20:47:19 > top of Java-index,Java Essentials,Java Programming...
# 6
The code you were given creates a singleton instance that's unique only in its thread. Meaning other threads can't share it. So if each of your users have their own thread, it'll behave like you'd like it to.
CeciNEstPasUnProgrammeura at 2007-7-13 20:47:19 > top of Java-index,Java Essentials,Java Programming...
# 7
Ok Im being dense but i cant see where this code fits into my example, and the javadoc for Threadlocal and InheritabelThreadLocal makes no sense to me. If anybody could fit this example into my example very much appreciated, (and Im using 1.4.2 not 1.5)
paultaylora at 2007-7-13 20:47:19 > top of Java-index,Java Essentials,Java Programming...
# 8

Just replace the getInstance method and add that static attribute, as described.

Okay, slowly, for you to take notes: A ThreadLocal object only exists within the scope of exactly one thread. No code running in other threads can see the same instance. It's a singleton not by classloader, but by executing thread.

CeciNEstPasUnProgrammeura at 2007-7-13 20:47:19 > top of Java-index,Java Essentials,Java Programming...
# 9

Replace the getInstance() method in LoginManager ? I cant Im writing test cases but Im not allowed to change the Production Code.

Not sure if this would work anyway, as I see it if the LoginManager was to call a Singleton in another class, both instances of LoginManager would return the same instance of the the second class wouldnt they ?

paultaylora at 2007-7-13 20:47:19 > top of Java-index,Java Essentials,Java Programming...
# 10

As I understand it you are simulating what amounts to a number of instances running in separate JVMs (probably on different machines) by running multiple instances in the same JVM. The natural way to do this would be to start multiple threads, each representing the action of one of these clients. (To do it sequentially would be a very poor test, since you need to cope with multiple, simultaneous activities).

The use of ThreadLocal enables you to have a separate instance of the "singleton" class for each thread. Any calls to the getInstance() method in the class made within one of the threads will return the details of the user "logged in" on that thread.

InheritableThreadLocal extends this by passing the same instance to any child threads formed in one of these threads after initially intanciating an instance in a Thread (quite possibly uneccessary).

And you can, if you wish, leave this in in the production version providing you do the login in the root thread of the client JVM.

This, I have to say, would be a vastly less messy solution (and a much milder distortion between test and production) than anything based on ClassLoaders could possibly provide. Using custom class loaders quickly gets very messy indeed.

If you have existing code you aren't allowed to change, then the best solution is probabllly to run multiple JVMs, exactly as in the real live case.

malcolmmca at 2007-7-13 20:47:19 > top of Java-index,Java Essentials,Java Programming...
# 11

> As I understand it you are simulating what amounts to

> a number of instances running in separate JVMs

> (probably on different machines) by running multiple

> instances in the same JVM. The natural way to do this

> would be to start multiple threads, each representing

> the action of one of these clients. (To do it

> sequentially would be a very poor test, since you

> need to cope with multiple, simultaneous

> activities).

Yes, correct

>

> The use of ThreadLocal enables you to have a separate

> instance of the "singleton" class for each thread.

> Any calls to the getInstance() method in the class

> made within one of the threads will return the

> details of the user "logged in" on that thread.

>

Ok,fine but Ive simplified the use case there are a number of singletons involved (most of which are not called directly by the test code but by each other) , all of these would have to be identified and modified.

> InheritableThreadLocal extends this by passing the

> same instance to any child threads formed in one of

> these threads after initially intanciating an

> instance in a Thread (quite possibly uneccessary).

Not needed, (thanks for explaining it though)

> And you can, if you wish, leave this in in the

> production version providing you do the login in the

> root thread of the client JVM.

>

We do not want to allow the client to do such things.

> This, I have to say, would be a vastly less messy

> solution (and a much milder distortion between test

> and production) than anything based on ClassLoaders

> could possibly provide. Using custom class loaders

> quickly gets very messy indeed.

>

I was hoping that by having two threads, each defining their own instance of a classloader it would get round the singleton behaviour and this is the only problem I am trying to solve. Obviously this would not be desirable in production but if it solves my testing problem Ill be happy, whether or not this is possible I still cant ascertain.

> If you have existing code you aren't allowed to

> change, then the best solution is probabllly to run

> multiple JVMs, exactly as in the real live case.

We are using junit and taking advantage of its reporting facilities,ant integration and so on. If I was to have two JVMs I would have to split my test into two coorporating tests that would have to run in parallel but as far as Junit was concerned were two seperate tests, I can see this causing problems with reporting and causing side effects on other tests if something failed. Im aware that I am not really writing 'unit' tests in the strict test but the Junit framework provides advantages over plain old java.

paultaylora at 2007-7-13 20:47:19 > top of Java-index,Java Essentials,Java Programming...
# 12
You'd probably have problems with report interleaving anyway with multi-threading tests.You might be able to do something with Java RMI, coordinating multiple JVMs.
malcolmmca at 2007-7-13 20:47:19 > top of Java-index,Java Essentials,Java Programming...
# 13
>>> You'd probably have problems with report interleaving anyway with multi-threading tests.Well i dont think so, because all the code is in one place I can make sure that i wait for threads to complete and so on..
paultaylora at 2007-7-13 20:47:19 > top of Java-index,Java Essentials,Java Programming...