tags:

views:

682

answers:

4

I'm part of a team that develops a pretty big Swing Java Applet. Most of our code is legacy and there are tons of singleton references. We've bunched all of them to a single "application context" singleton. What we now need is to create some way to separate the shared context (shared across all applets currently showing) and non-shared context (specific to each applet currently showing). However, we don't have an ID at each of the locations that call to the singleton, nor do we want to propagate the ID to all locations. What's the easiest way to identify in which applet context we're running? (I've tried messing with classloaders, thread groups, thread ids... so far I could find nothing that will enabled me to ID the origin of the call).

A: 

(I'm replying instead of editing as I somehow managed to create a second user) @Mcdowel: All in context of the applet. The application context is a singleton in the applet.

Ran Biron
A: 

If I understand you correctly, the idea is to get a different "singleton" object for each caller object or "context". One thing you can do is to create a thread-local global variable where you write the ID of the current context. (This can be done with AOP.) Then in the singleton getter, the context ID is fetched from the thread-local to use as a key to the correct "singleton" instance for the calling context.

Regarding AOP there should be no problem using it in applets since, depending on your point-cuts, the advices are woven at compile time and a JAR is added to the runtime dependencies. Hence, no special evidence of AOP should remain at run time.

Hugo
A: 

@Hugo regarding threadlocal:

I thought about that solution. However, from experiments I found two problems with that approach:

  1. Shared thread (server connections, etc) are problematic. This can be solved though by paying special attention to these thread (they're all under my control and are pretty much isolated from the legacy code).
  2. The EDT thread is shared across all applets. I failed to find a way to force the creation of a new EDT thread for each applet. This means that the threadlocal for the EDT would be shared across the applets. This one I have no idea how to solve. Suggestions?
Ran Biron
You should be able to get a new EDT thread by using a different value for the archive tag. I think you can just add a random jar name to the end even if it does exist.
Tom Hawtin - tackline
+1  A: 

Singletons are evil, what do you expect? ;)

Perhaps the most comprehensive approach would be to load the bulk of the applet in a different class loader (use java.net.URLClassLoader.newInstance). Then use a WeakHashMap to associate class loader with an applet. If you could split most of the code into a common class loader (as a parent of each per-applet class loader) and into the normal applet codebase, that would be faster but more work.

Other hacks:

If you have access to any component, you can use Component.getParent repeatedly or SwingUtilities.getRoot.

If you are in a per-applet instance thread, then you can set up a ThreadLocal.

From the EDT, you can read the current event from the queue (java.awt.EventQueue.getCurrentEvent()), and possibly find a component from that. Alternatively push an EventQueue with a overridden dispatchEvent method.

Tom Hawtin - tackline
This is (by far) the best collection of ideas I saw on the subject. I especially like the "push a customized eventqueue" - and I'm going to try it.
Ran Biron