Lookup Library

# Lookup Library - The Solution to Comunication Between Components

$Revision: 1.1.42.1 $
History: Available in CVS

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`
- Source code: directly on netbeans.org on-line CVS view implementation package (org.openide.util.lookup) + classes Lookup, LookupEvent, LookupListener in util package
- Inversion of Control Containers and the Dependency Injection pattern (Martin Fowler)