Toni Epple works as a consultant for Eppleton (http://www.eppleton.de) in Munich, Germany. In his spare time he's an active member of the Open Source community as a community leader for JavaTools community (http://community.java.net/javatools/), moderator of the XING NetBeans User Group (http://www.xing.com/group-20148.82db20), founder of the NetBeans User Group Munich (http://tinyurl.com/5b8tuu), member of the NetBeans Dream Team (http://wiki.netbeans.org/NBDTCurrentMembers) and blogger (http://www.eppleton.de/blog). Toni is a DZone MVB and is not an employee of DZone and has posted 51 posts at DZone. You can read more from them at their website. View Full User Profile

NetBeans Lookups Explained!

02.12.2009
| 44155 views |
  • submit to reddit

Lookups are one of the most important parts of the NetBeans Platform. They're used almost everywhere and most of the time when you ask something on a mailing list the answer is "Use Lookups!". Many times when the use of Lookups is explained it's in a very specific context, e.g. selection management or ServiceLoaders. That makes Lookups look complicated and hard to understand, while actually they are very simple and extremely powerful.

That's why I guess it's time to write an article that explains what lookups actually are and how they work. In the subsequent parts I'll explain how they can be used to solve some common problems.

Lookup as a Data Structure

So first let's have a look at Lookup as a data structure. A Lookup is a map with Class Objects as keys and a Set of instances of the key Class object as values. An additional feature of a Lookup is that you can listen for changes of what's in there. It's as simple as that! If you want to ask a lookup for it's contents, you can do so like this:

Lookup  lookup = //get a lookup somewhere...
Collection <String> strings =lookup.lookupAll(String.class);

If you want to listen for changes, you add your Listener to Lookup.Result an inner class that represents a query result. This way you add a Listener that listens for addition or removal of objects of a certain class:

Lookup.Result <String> strings = lookup.lookupResult(String.class);
strings.allItems();
strings.addLookupListener(new LookupListener(){
@override
public void resultChanged(LookupEvent e){
// do something
}}
);

This is how you usually use an existing lookup. If you want to create one, there are some implementations to help you. The most basic one is Lookups.Singleton, a Lookup that only contains one object:

Lookup simple = Lookups.singleton("Hello World!"); 

There's also an implementation for creating a lookup with more than one entry, still with fixed content:

Lookups moreElements = Lookups.fixed( "Hello", "World", new Integer(5) ); 

If you want to use a Lookup to dynamically put in stuff you'll need to choose an implementation that supports that. The most flexible one is using an InstanceContent Object to add and remove stuff:

InstanceContent content = new InstanceContent();
Lookup dynamicLookup = new AbstractLookup(content);
content.add("Hello");
content.add(5);

Listeners registered for the matching class will be informed when something changes. If you would like to query more than one Lookup at a time you can use a ProxyLookup. This for example, combines two of the Lookups created above into one:

ProxyLookup proxy = new ProxyLookup(dynamicLookup, moreElements); 

Lookup.Provider

If your Object has a Lookup to store a bunch of stuff, you can make it accessible to others by implementing Lookup.Provider an interface with only one method:

public Lookup getLookup();

Again, extremely simple. Someone interested in what's in your Objects Lookup can ask for it and register a listener. In NetBeans TopComponents implement this interface, so you can ask any TopComponent for it's Lookup. The easiest way to get hold of most of the TopComponents is via their ID:

TopComponent tc = WindowManager.getDefault().findTopComponent("AnInterestingTopComponent");
Lookup tcLookup = tc.getlookup();

As most TopComponents put into their Lookup whatever is selected, for example the entries in a list, you can add a Listener to track the Selection in a TopComponent. If your for example interested in the selected Nodes you can do it like this:

Lookup.result <Node> noderesult = tcLookup.lookupResult(Node.class);
result.allInstances();
noderesult.addLookuplistener(myLookupListener);

That's especially handy when you want to provide a Master-Detail-View. If you want to provide your own Lookup in your TopComponent you do it like this:

associateLookup(mylookup); 

Global Selection

Sometimes you might be interested not only in what is selected in one specific TopComponent, but in whatever TopComponent currently has the focus. That's easy as well because NetBeans provides a Lookup that proxies the Lookup of the TopComponent that currently has the focus. To use this you simply need to do this:

Lookup global = Utilities.actionsGlobalContext();

You can use this like any other Lookup and register your listeners, no magic involved.

Nodes

Nodes also implement Lookup.Provider so you can ask them for their Lookup as well. Something useful to store inside a Node's Lookup is the DataObject it may represent. If you're using Nodes you probably do so in combination with the Explorer API to display them. If you do that you'll usually create a lookup for your TopComponent with the help of the ExplorerManager:

associateLookup(ExplorerUtils.createLookup ( explorermanager, this.getActionMap() ) );

The resulting Lookup also proxies the content of the selected Nodes Lookup. This way everything someone might be interested in shows up in your TopComponent's Lookup.

Service Loader and other uses

As you've seen Lookups are actually a very simple yet powerful concept. Some articles here on NetBeans Zone also cover the use of Lookups for loading services in a NetBeans RCP application, which is also an important use. To do that NetBeans provides a default Lookup that looks in certain places for service registrations, e.g. in the META-INF/services folder of a modules jar file and in the modules layer.xml. If you're interested in getting an instance of a Service implementation you can do it like this:

Collection <ServiceInterface> services= Lookup.getDefault.lookupAll(ServiceInterface.class); 

If you register your service in the layer.xml you can get a lookup for a certain Folder like this:

Lookup lkp = Lookups.forPath("ServiceProviders");

I guess that's all you need to know to get started with Lookups, so have fun trying it out, it's really simple.

Published at DZone with permission of Toni Epple, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

denis leurquin replied on Wed, 2009/03/04 - 3:30am

In the 3rd Lookup.Provider snipet, I was expecting

"Lookup.result <Node> noderesult = tcLookup.lookupResult(Node.class);"

(as explained in article's second example); but the code shows 

"Lookup.result <Node> noderesult = tcLookup.lookupAll(Node.class);"

Are they both correct?

 

Jirka X1 replied on Sun, 2010/02/21 - 3:25pm in response to: denis leurquin

lookupAll(Node.class) returns the Collection of Nodes not a Lookup.Result

this is the actual definition:

public <T> Collection<? extends T> lookupAll(Class<T> clazz) {
return lookupResult(clazz).allInstances();
}

 

Jirka X1 replied on Sun, 2010/02/21 - 5:39pm

The code with the listener is wrong, one has to call allItems() before assigning the listener.

Lookup.Result<String> strings = lookup.lookupResult(String.class);
strings.allItems(); // THIS IS IMPORTANT
strings.addLookupListener(new LookupListener(){
@Override
public void resultChanged(LookupEvent e){
// do something
}}
);

Nicholas Dunn replied on Tue, 2010/03/30 - 8:45am in response to: Jirka X1

Thank you SO much for this comment - I was at my wits end trying to figure out why that didn't work.  So frustrating.

Toni Epple replied on Wed, 2010/04/07 - 9:40am in response to: Nicholas Dunn

Hi Nicholas,

 sorry I didn't see your comments earlier. Thanks for answering Jirka, I've fixed the snippets.

 --Toni

Joseph Okharedia replied on Tue, 2010/06/08 - 5:02am

Thank you for the post. Can someone explain to me what is the essence of
strings.allItems() and result.allInstances(). I would like to know what these functions do and also the code...
Lookup.result noderesult = tcLookup.lookupResult(Node.class);
result.allInstances();
shouldn't it be...
Lookup.Result noderesult = tcLookup.lookupResult(Node.class);
noderesult.allInstances();

Olivier Dalang replied on Fri, 2011/12/23 - 10:41am

Thanks for your post... Helped me very much ! I've summarized what I've learned in another mini-tutorial (which will maybe help some other newbies) : http://netbeans.dzone.com/news/mini-tutorial-netbeans-lookup

Manikantan Nare... replied on Tue, 2012/04/17 - 11:58pm

Use case: Service providers are tagged with some values and I would like to lookup a SP with a particular tag. How can this be done.

Carla Brian replied on Sat, 2012/05/19 - 9:11pm

This is interesting. I will study more about this one. I want to learn this. - Joe Aldeguer

Matt Coleman replied on Thu, 2012/05/24 - 1:18am

this has enlightened me indeede...thanks for the through explaination

Regards,

website design buffalo

Mateo Gomez replied on Fri, 2012/05/25 - 12:56am

yes,help us please..it's kinda complicated

mexican bread
 

Eduardo Fonseca replied on Mon, 2012/05/28 - 5:25pm

I have this code 

result = Utilities.actionsGlobalContext().lookupResult(com.contvent.facturacion.dataobject.Wrap.class);

result.addLookupListener(this);  

Collection<? extends com.contvent.facturacion.dataobject.Wrap> facturaProducto = result.allInstances();

but when I try to do its  facturaProducto.clear() its match an Unsopported Exception, why??

Stork Club replied on Fri, 2012/10/19 - 1:51am

Oh,I get this now...thanks for explaining

 club stork

Winston Dehaney replied on Mon, 2013/07/01 - 10:05pm

Hey guys, I just wanted to be sure about something. I have an action that is in the toolbar. whenever the action is clicked, I wanted to effect some change in the currently viewed topcomponent. I'm assuming that I would need to utilize the lookup api for this. Any suggestion or guidance in this?

Cata Nic replied on Mon, 2013/09/02 - 4:13am

These explanations are really helpful for a noob like me. I hope you will publish a complete tutorial with the entire procedure.

Black Men replied on Sun, 2014/04/13 - 1:32pm

  That makes Lookups look complicated and hard to understand, while actually they are very simple and extremely powerful.

soundcloud downloader

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.