org.openide.util.lookup.doc-files.index.html Maven / Gradle / Ivy
Lookup Library
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.
Why would you want to use it?
A well-written modular program separates development
and deployment.
There are many situations where a component needs some functionality but
does not actually care about the implementation. It is up to the system
adminstrator that deploys (installs) the application to decide which
implementation to use.
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.
Local lookup usage
The example in previous paragraph demostrated the usage of lookup as a global
registry (by using the 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();
Additional functionality
The NetBeans lookup library also provides:
- Support for dynamically changing the lookup content.
- The ability to return multiple results.
- Notification of changes. After retrieving the result, the client can attach a
listener and be notified when the result of the lookup is changed.
- Lazy initialization of the implementation. The implementation objects are
initialized only after someone asks for them. Even the implementation classes
are not loaded if they are not going to be used!
Further information
- Lookup Library APIs for those writing the client code.
Specifying the query, getting the result and listenning on changes.
- Lookup Library SPIs for those writing the
implementaion code and registering it with lookup. Includes also writing own
lookup implementation.
- Download NetBeans platform which
contains
org-openide-util.jar
implementation package (org.openide.util.lookup)
+ classes Lookup, LookupEvent, LookupListener in
util package
- Inversion of Control Containers and the Dependency Injection pattern (Martin Fowler)