This is the home page of the lookup library implementation, which is intended to solve a general problem that every component-based system has had to face: how different components register to the system and how other parts of the system can look them up.
There already are libraries trying to solve this problem, usually by querying for an interface and finding its appropriate implementaion. The most famous is Jini, the platform for development of distributed network services. Our library does something similar, but tries to stay small and easy to use. The NetBeans Lookup Library's main focus is a modular application consisting of independent modules that want to communicate with each other. It does not try to solve networking or legacy application integration. It is simple but powerful.
The most simple and most often used method for allowing other implementations to be plugged in is the system property pattern:
public Toolkit getDefaultToolkit () { java.awt.Toolkit t = null; String classname = System.getProperty ("java.awt.Toolkit"); if (classname != null) { try { Class c = Class.forName (classname); t = (java.awt.Toolkit)c.newInstance (); } catch (Exception ex) { System.out.println ("Cannot initialize toolkit: " + classname); ex.printStackTrace (); } } // fallback if (t == null) { t = new GenericAWTToolkit (); } }The idea is simple. The deployer can start the Java VM with the flag
-Djava.awt.Toolkit=org.myorg.MyToolkit
where the MyToolkit
is his class with default constructor and the code in the getDefaultToolkit
method will instantiate the class and use it.
In principle this is general enough of a solution and works well, except that writing the
code above is error prone and it also requires passing the arguments to the virtual machine.
It would be much nicer if the registation could be done just by putting a JAR file with the MyToolkit
class
into the application classpath.
Actually this has been realized also by the JDK development team and addressed in
JDK 1.3 as part of the provider extension mechanism.
The MyToolkit
could be registered by adding a file
/META-INF/services/java.awt.Toolkit
with one line
org.myorg.MyToolkit
into the JAR file that contains the
MyToolkit
implementation. The code in getDefaultToolkit
will scan all JAR files in classpath and search for that file,
create an instance of MyToolkit
and use it.
The deployer can influence which toolkit will be created by
adding the right JAR files into the classpath.
Of course the code to access the META-INF/services/
files is even
more error prone than the property pattern. And this is exactly the
place where the lookup library can help. It provides an implementation of
the search algorithm with an easy interface. Just write:
import java.awt.Toolkit; import org.openide.util.Lookup;; Toolkit t = (Toolkit)Lookup.getDefault().lookup(Toolkit.class);and if the JAR with
MyToolkit
is in the class path, the simple call
above will do the rest.
So whenever one writes an application divided into several independent modules (jar files)
that are being developed and deployed independently, there is a need for registering
and discovering components. First of all, a set of interfaces can be defined to enable
inter-module communication (like the abstract class java.awt.Toolkit
).
After that a set of modules providing implementation can written (MyToolkit
and other concurent implementations)
and after that, whenever a module trying to utilitize the functionality wants to access
the Toolkit
via lookup, the real implementation is returned.
It is the responsibility of lookup to find a suitable implementation of the requested service and return an object implementing the service. This is the the basic functionality and while the library provides you with a little bit more, even this simple usage might be extremaly useful: the client code knows nothing about the implementation and the implementation can be switched in deployment time by simply replacing one implementation jar with other. There is no code change required.
Lookup.getDefault()
call). One can also
consider another scenario where the lookup can help.
Let's switch hats to be an API designer for a while. The goal is to introduce a new object into the system. But you either are not sure yet what all the roles of the new object will be or you (more importantly) want to be able to add (or change) roles of the object dynamically. So why not to introduce following method to the object's interface:
public class MorphingObject { public Lookup getLookup() { return myLookup; } ... }By exposing the method getLookup you can attach different functionality to the MorphingObject at runtime and whoever gets a reference to your object can ask it whether the object supports a given interface like this:
MorphingObject morph = ... AnInterface impl = (AnInterface)morph.getLookup().lookup(AnInterface.class); if (impl == null) { return;/* AnInterface not supported now! */ } impl.useIt();
org-openide-util.jar