org.openide.util.lookup.doc-files.lookup-api.html Maven / Gradle / Ivy
Lookup Library API
Lookup library API
This document describes usage of the API provided by the Lookup Library. In this
document we assume that someone has already provided us with a lookup
implementation (for those seeking how to write a lookup implementation please
check the SPI document).
Getting the lookup
The first question you might ask is this: how can I get hold of a
lookup instance? There are basically two ways how you can get it.
Global lookup
As you can see in the
Lookup
Javadoc there is a static method
public static Lookup getDefault()
The object returned from this method is
a global lookup that can serve as a central place for registering services.
The default implementation is a lookup that implements
the JDK JAR services
mechanism and delegates to META-INF/services/name.of.Class files.
If you want to add your class to this lookup just create a file in your
jar file under the META-INF
directory (e.g. META-INF/services/com.my.APIClass)
and let the file contain only one line of text
com.foo.impl.ImplOfTheAPI
(This is more easily done using the @ServiceProvider
annotation.)
The following code will return you a newly created instance of
com.foo.impl.ImplOfTheAPI
:
import org.openide.util.Lookup;
return Lookup.getDefault().lookup(com.my.APIClass.class);
Local lookup
This is just a reminder that whenever you find a method called getLookup
or similar returning a lookup instance, the provided lookup is not the
general lookup described in the previous paragraph. Rather, it is a private lookup
implementation that is usually bound to the object you invoked the method on.
Use of Lookup.Template and Lookup.Result
There are more ways how you can ask lookup besides the variant with one class
parameter. If you want more functionality, you have to implement the interface
Lookup.Template and pass an instance of such object to the lookup call.
Note: If you use Lookup.Template, the object returned from the lookup is
not the object you are looking for but rather a result object
(Lookup.Result). You can call methods on such a result object to get the actual
results.
Let's examine following example:
import org.openide.util.Lookup;
Lookup lookup = ...;
Lookup.Template template = new Lookup.Template(MyService.class);
Lookup.Result result = lookup.lookup(template);
Collection c = result.allInstances();
for (Iterator i = c.iterator(); i.hasNext(); ) {
MyService s = (MyService)i.next();
s.callMyService();
}
In this example the call to method lookup(...) returns immediately because the
result object can be constructed even without real results. The first time you
ask for the result object by calling r.allInstances(), the lookup has to supply you
the real results and this method can block until the required data are really
available.
If you are not interested in all objects as in the previous example, you can use the
template to ask for one resulting object (wrapped in special Item instance):
import org.openide.util.Lookup;
Lookup lookup = ...;
Lookup.Template template = new Lookup.Template(MyService.class);
Lookup.Item item = lookup.lookupItem(template);
MyService s = (MyService)item.getInstance();
s.callMyService();
Again, the Item object can construct the real instance only if you call
getInstance. The item can be useful even without calling getInstance - you can get
its display name or an unique id. You can use this information, for example, for
constructing menu items without the need to instantiate (or even load!)
the class implementing the functionality. Only when the real functionality is
needed (e.g. the user has selected the menu item) you can call getInstance
and call the real meat of the implementation.
Listenning on lookup changes
There is one additional piece of functionality bound to the Lookup.Result object worth
mentioning: you can attach a listener to it and be informed about any changes in
the lookup. This might be extremly usefull when the lookup dynamically changes
(from other threads). The listener can keep state of your object up-to-date even
in cases where the lookup changes asynchronously.
So here is some sample code using the listenner:
import org.openide.util.Lookup;
import org.openide.util.LookupListener;
import org.openide.util.LookupEvent;
Lookup lookup = ...;
Lookup.Template template = new Lookup.Template(MyService.class);
final Lookup.Result result = lookup.lookup(template);
result.addLookupListener(new LookupListener() {
public void resultChanged(LookupEvent e) {
reaction(result);
}
});
reaction(result);
}
private static void reaction(Lookup.Result r) {
for (Iterator i = r.allInstances().iterator(); i.hasNext(); ) {
MyService s = (MyService)i.next();
s.callMyService();
}
}
Please note that we first attach a listener and then call the reaction method.
This ensures that we always get the newest possible state. Also you must be
careful in the reaction method since it can be called from two different
threads simultaneously (your code has to be prepared for this).