Hello I have encountered a problem with the Singleton pattern. Essentially an instance of the class is created in a static which is initialized when the class is loaded. However, subsequent code finds that this instance has not yet been created. Clearly the class is being loaded more than once. Is there way to determine if this is caused by the code executing in different JVMs or simply caused by a different classloader? The different JVMs in this case are the JVM in which the Admin Service runs, and the JVM in which the App Server runs. (I have set Module Visibiity property to "Server", but one thing I've discovered with WAS is that nothing is as it appears to be ;-) I read an article which suggested moving the singleton code into an EJB. Does this guarantee that only one instance of it will ever be created? thanks
<i>Truth is one; the wise call it by many names</i> (Rig Veda I.64.46)
The key here is to make sure that your Singleton is only ever loaded by one Classloader. What is happening is that you have multiple classloaders in WAS (just read the InfoCenter) and so if you attempt to reference it from multiple places you might have more than one active. On the other hand, if you "Gate" access to your singleton through a stateless session EJB you can guarantee that only one will be used. Kyle
Well, yes, but I don't know for sure whether its caused by multiple class loaders or running in a different JVM. If its the latter, there's not much I can do about it. Also, I have read the InfoCenter article, which is why I mentioned having set the Module Visibility property to "Server". According to the documentation that's supposed to ensure only one classloader for all apps in that app server. If that's really working as it should, then it seems to me that the problem is that the second piece of code accessing the singleton is running in a different JVM. Again, I don't know for sure. Hence I was wondering if there was some way either in Java or in Websphere to determine the current classloader and/or JVM instance? thanks
<i>Truth is one; the wise call it by many names</i> (Rig Veda I.64.46)
Sure -- at any point any object can ask for it's classLoader -- just compare the OID's of the ones you get in your singleton method and you'll see that there are > 1. And also, even when you use Server mode, you still have > 1 classloader -- I seem to remember there are at least 4... Kyle
Hi Kyle, I've been monitoring this post because I have a similar problem. It seems that the post has addressed the classloader issue but, what if the singleton is being loaded into multiple WAS clones? We have a Singleton object that caches some objects that can be retrieved by an application. On ocassion we would like to communicate with the singleton to tell it to release the objects (flush the cache if you will). However, we cannot predict which JVM we are communicating with. So, one might flush where the other does not. Works great until we introduce WAS load balancing. What types of techniques would be available to address this? Ultimately, I would prefer one copy of the singleton. but, if I must communicate with each one across all the JVMs that's fine too. Thanks, Fran Varin
I solved a similar cache flushing problem some time ago by having the singleton (loaded by the system classloader) receiving the flush() invocation to forward the call to the other servers (poor man's cache synchronization ).
Hi Lasse, thanks for responding. I think I see where you're heading. Would it be possible for you to elaborate just a bit. I'm not sure I know how to proceed based on your response. I'm confused about how the forwarding mechanism works? Is there some doc I should read to get a clearer picture?
Well, we had multiple, physically separate boxes and each box was running a J2EE application. Each application had an internal cache of a part of the shared database. Let's call these servers app-1 and app-2 for convenience. In addition to this, we had yet another box running administration tools only. One of the tools was used to tweak the data that the other servers were happily caching. The nature of those changes required instant effect on all of the applications' behaviour (i.e. once the admin clicked "update" and received an "ok" page, he had to be able to trust that after that point in time, none of the applications were using the cached data). Let's call the admin server adm-1. What we did was the following:
Once the admin tool on adm-1 updated the database, it read a list of "remote caches" from a configuration file on the adm-1 machine. According to our example here, the configuration file would've listed "app-1" and "app-2" with certain properties needed for doing a remote JNDI lookup.
The admin tool executed a JNDI lookup for our cache flushing EJB component, and requested an immediate flush one at a time.
The cache flushing component simply said Cache.flush(), which was a static method of a class that was being loaded by the system classloader. Since the application was reading its cached data through the same utility (loaded by the system classloader), this method call flushed all cached regardless of where the call came from (from which J2EE module).
Ok, that's a bit clearer. Your situation apparently worked because the JVMs resided on separate physical machines (app. servers & containers). Thus, enabling you to use JNDI to sync the access to the machines. The problem I'm faced with is somewhat different. We are running a single box that exploits WebSphere's load balancing. Simply put the single image of WSA manages 4 independent JVMs, each with a "clone" of the application. WSA load balancing uses a round robin approach in dispatching requests. The only affinity is at the session level. So, objects like a Singleton have a unique instance in each JVM. This is somewhat problematic when you need to manage the content of the Singleton object. The Singleton in question caches Database query results. On occasion we would like to flush the cache manually. But, because of the way WSA load balancing is designed, i.e. round robin between the cloned JVM's we apparently cannot direct a request to a specific JVM and thus a specific Singleton instance. It seems that WSA's approach to load balancing leaves us out in the wind a bit. It would seem that WSA should be allowing for long-lived stateful objects (global, not bound to a user session). We resist using EJB because of the complexity and overhead involved. I've seen some posts that suggest that a session bean could possibly be used. This approach seems like overkill, big time!
I've done some more digging and the sys admin and I came up with a simple solution. It seems that WebSphere maintains an internal http server and configures a port for each JVM in the plugin-cfg.xml. So, you can actually create a simple jsp (or servlet) and access it through a url in a browser by specifying the port associated with a specific JVM. If you consider the potential, its not hard to realize that you could automate the process and fire an http request to each JVM programmatically.