After my very interesting and enlightening attendance at The Server Side Java Symposium last month, I’ve decided to start exploring new technologies and how better do this than by creating some Open Source tools and libraries. Since I’ve been working almost exclusively with the Calypso API for the last decade, it’s somewhat logical that I would start there. I decided that my first project is to integrate Calypso with GridGain as Dispatcher to distribute Risk Analysis execution on the Grid. Calypso has its own Dispatcher implementation, but they themselves acknowledge it’s not ready for prime-time. They do sell an adapter to plug into DataSynapse as well, but I figured an Open-Source alternative would be a worthwhile tool for Calypso implementors. Besides, once I get it all up and running, I want to play with Scala as it seems to integrate very easily with GridGain.
So last week I launched Eclipse and created a new project. As I began creating a new package, com.steepi
, I paused. In order to plug my package into Calypso, I would need to implement CustomGetPackages
in the calypsox.tk.util package
. But if I do that, how is a Calypso implementor going to use it? After all, they most certainly already have their own instance of CustomGetPackages
! Now granted, they certainly could make the modification to their class to add my packages. Still. What if I truly wanted to provide a library that would attach my packages simply by adding a jar to the CLASSPATH
? This problem merited further investigation…
After a few hours of research, I found a solution by locating an undocumented feature of Calypso. During startup, the AppStarter
class will at some point try to instantiate calypsox.apps.main.UserStartup
. If an instance of this class is found by InstantiateUtil
, the method start()
will be called via reflection. Just the hook I needed! I could place my custom code there to attach my custom packages.
Wait, though…
How would I go about doing so? Calypso’s API does not provide a method to add packages to InstantiateUtil
. It’s all done within a static block when the class is loaded. Thankfully, I’ve encountered limitations with the Calypso API before and the way to circumvent this problem is to use Java reflection to render methods and fields accessible. Here, then, is the code that does exactly what I wanted! If you compile the following code and add it to your CLASSPATH
, you’ll be able to attach custom packages to existing Calypso implementation projects that have their own CustomGetPackages
implementation. It’s a nifty way to provide a third-party library on top of Calypso, don’t you think?
1: package calypsox.apps.main; 2: 3: import java.lang.reflect.Field; 4: import java.util.Collections; 5: import java.util.List; 6: 7: import com.calypso.tk.core.Log; 8: import com.calypso.tk.util.InstantiateUtil; 9: 10: public class UserStartup { 11: public void start() { 12: // In order to attach our packages, we operate on 13: // InstantiateUtil class using reflection so as to 14: // reach through its encapsulation. 15: Class clazz = InstantiateUtil.class; 16: Field field; 17: List packages = null; 18: try { 19: // Retrieve the _packages field in InstantiateUtil 20: field = clazz.getDeclaredField("_packages"); 21: // Since this is a private field, we need to set it 22: // to accessible so we can access it 23: field.setAccessible(true); 24: // Get the value of the field via reflection. 25: // This is the actual List object 26: packages = (List)field.get(clazz); 27: // Add Steepi packages so they are available when 28: // instantiating through reflection 29: packages.add(0,"com.steepi"); 30: } 31: catch (Throwable t) { 32: Log.error("Error", "Unable to locate InstantiateUtil._packages via reflection.", t); 33: return; 34: } 35: // TODO: Apply same logic to update _invertPackages field as well 36: } 37: }
As noted inline, you’ll want to do the same to update the inverted packages field. I’ve omitted the code for brevity.
This solution should work with any version of Calypso prior to 11.1. Who knows whether or not they will eventually remove this logic since it is, after all, undocumented. Still, for the time being, it should be easier to deploy my packages in existing Calypso implementations without needing any code change. Sweet!