Summary
Okay this came from a little idea I had last night for Neon, and from a bit of playing around with those ideas - dependency injection from Jini configuration files.
Advertisement
Dependency injection, for those few who haven't heard of it, is closely linked to moving the responsibilty for creation and retrieval of dependent objects, outside of your classes and modelling that responsibility within a framework environment, essentially the opposite of Service Locator.
DI is also closely linked (for better or worse) with XML configurations. One of the things that I've been considering in Neon, is whether Dependency Injection can work across an environment where mobile code is employed and objects can move around a network. As part of this, I've not really wanted to increase the number of things you have to deal with in Neon - you have to build an agent, and you can supply a Jini configuration file, but you can also supply a constraints file (a kind of simple set of QoS requirements) which can also be decribed in a Jini configuration file......so the next step when looking at Neon, was "Could I model DI in a Jini configuration?". This is a blog of my experiences so far.
Okay, a bit of background on Jini configuration files. Basically Jini allows you to specify deployment time considerations in a separate file, that can be read by your service at runtime, so for instance you may want to export your service in development with a simple non-secure exporter, however when you move into production, you can specify secure SSL exporters with JAAS, etc. without having to mess with your code. Here there is a similarity in what happens with DI.
However, DI also does the injection (hence the name) of field values (through either setter or constructor injection) from this configuration file, so that when you want to know the name of, say, the JDBC driver you will use, you don;t have to retrieve it yourself. With Jini you have to obtain this from a Configuration instance, using Configuration#getEntry(component,entry,typeclass). Jini Configuration files have a java like syntax and perform construction of objects when you ask for the entry. An example is given below
So a Jini configuration provider will take care of creating your objects, and you can call static methods in a configuration file, but not methods on an instance so for instance I could call String.valueOf(...), but not simpleString.substring(...)
Now here's where a bit of magic comes in (but only a little), to do some form of Dependency Injection. If we assume certain things about the component name, and look for certain type of setter methods, we could do the following.
Parse the configuration files (in some way)
Use the component names as recognisers for classes passed to the injector
For methods in the class passed that match set<entryname> for any given entryname in the Jini component, we get the value out of the Jini configuration and then call the method to set it.
I'll go through an example with some simple POJOs and a Jini configuration file.
import net.jini.lookup.entry.*;
import net.jini.core.entry.*;
import net.jini.jeri.*;
import net.jini.jeri.tcp.*;
org.jini.projects.neon.di.Simple{ // <= This refers to a class name
SimpleString = "abc";
testString=SimpleString;
logLevel="FINEST";
groups=new String[]{"production"};
initialLookupAttributes = new Entry[] {new Name("TestingConfigScan")};
myExporter = new BasicJeriExporter(TcpServerEndpoint.getInstance(0), new BasicILFactory());
theDependent=new DIReference("org.jini.projects.neon.di.Dependent$Test1");
}
And a class definition (I've removed getters for brevity)
You'll note that the configuration file contains this line: theDependent=new DIReference("org.jini.projects.neon.di.Dependent$Test1");
This line refers to a dependent reference that also needs to be created, so we can add the following lines to the configuration file
class Dependent {
private String myString;
public String getMyString() {
return myString;
}
public void setMyString(String myString) {
this.myString = myString;
}
public String toString() {
return myString;
}
}
I can then change the reference in the org.jini.projects.neon.di.Simple component from theDependent=new DIReference("org.jini.projects.neon.di.Dependent$Test1");
to theDependent=new DIReference("org.jini.projects.neon.di.Dependent$Test2");
And the injection that occurs will refer to a "differently set" instance of org.jini.projects.neon.di.Dependent.
So calling Dependent#toString() will now output "There" instead of "Hello"
Although, this is not anywhere near as complicated or powerful as say Spring's DI framework and configration files, it's not bad for a morning's work!