Foreign compile-time dependencies in SelfDiagnose

In the upcoming release 1.1 of the SelfDiagnose task library, a new task has been added called CheckEndecaService. Endeca is commercial software that provides excellent Search services to e.g. e-commerce web applications. This particular task checks the availability of that service and can perform a simple query. To implement this, the following snippet has been used:

HttpENEConnection connection = new HttpENEConnection();
connection.setHostname(host);
connection.setPort(port);
UrlENEQuery eneQuery = new UrlENEQuery("N=0", "UTF-8");
ENEQueryResults eneResults = connection.query(eneQuery);
Navigation navigation = eneResults.getNavigation();
long numERecs = navigation.getTotalNumERecs();
double time = eneResults.getTotalNetworkAndComputeTime();

Without a full understanding, you can see that this snippet is using classes which belong to the Endeca API package. SelfDiagnose is a open-source library and therefore can and will not have any dependencies on commerical software. So how can we still use this code without the compile time dependencies?. Of course, in order to execute this code, the runtime dependencies must be available. It does not make sense to use the CheckEndecaService if your application is not using it.

One way is to use some scripting language that dynamically binds the objects. But then the SelfDiagnose package will have a dependency to that scripting language. Therefore, I choose a more lightweight solution which is completely based on the standard Java Reflection API. To make the code a bit more fluent, I created the class Instance which hides all the exception handling stuff.

Instance connection = Instance.create("com.endeca.navigation.HttpENEConnection");
connection.invoke("setHostname", eneHost);
connection.invoke("setPort", enePort);
Instance eneQuery = Instance.create("com.endeca.navigation.UrlENEQuery",new Object[]{query,"UTF-8"});
Instance eneResults= connection.invoke("N=0",eneQuery);
Instance navigation = eneResults.invoke("getNavigation");
long numERecs = navigation.invoke("getTotalNumERecs").longValue();
double time = eneResults.invoke("getTotalNetworkAndComputeTime").doubleValue();

Although the compilation no longer depends on the client jar of Endeca, it still does depend on the API. Future changes in the API may invalidate this solution. Putting a version identification in the class name of task will accomodate this.