blob: 0d68d9b5f57b657eb1399a6b62ce1a585693634a [file] [log] [blame]
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
= DevFaqLookupLazyLoad
:jbake-type: wiki
:jbake-tags: wiki, devfaq, needsreview
:jbake-status: published
:keywords: Apache NetBeans wiki DevFaqLookupLazyLoad
:description: Apache NetBeans wiki DevFaqLookupLazyLoad
:toc: left
:toc-title:
:syntax: true
==== How do I lazy-load an item in the Lookup?
A node is typically used to represent some business object and it's a common idiom to place that business object in the node's lookup so that, for example, a context-sensitive action can operate on it. Sometimes fully initializing that business object can involve an expensive operation that would be wasted effort if the user never invoked the action that used it anyway.
So how can you defer loading or initializing the business object until it is truly needed?
There are probably several ways, but two common ones are:
==== Override the `beforeLookup(Lookup.Template<?> template)` method
If you are using the `AbstractLookup` class to create the lookup, you can override the `beforeLookup(Lookup.Template<?> template)`. By doing this, you will be notified just before a lookup query is processed and you could check to see if the template would match the objects for which you've deferred loading, giving you an opportunity to load them now and add them to the `InstanceContent` used by the `AbstractLookup`.
==== Use `InstanceContent.Convertor` to create a placeholder object
The `InstanceContent.Convertor` class can be registered in an `AbstractLookup` such that it provides a typesafe placeholder until the actual object type is requested, and at that point, the convertor can create and return the actual object.
Consider the following example in which you have a `Token` class which represents a database record ID and a business object class `AnExpensiveClass` which will be populated from the database based on the supplied token's ID.
[source,java]
----
public final class Token {
private final long id;
public Token(long id) {
this.id = id;
}
public long getId() {
return id;
}
}
----
Now we will write a converter. Until the first time something calls `theLookup.lookup(AnExpensiveClass.class)`, only our quick-to-create `Token` object is in memory. On the first such lookup call, the following code is run:
[source,java]
----
public class LazyLoadingDelegate implements InstanceContent.Convertor<Token, AnExpensiveClass> {
@Override
public AnExpensiveClass convert(Token token) {
// Return an instance based on the supplied token (i.e. assume that
// the AnExpensiveClass constructor will load data from the database
// and populate the instance we're returning).
return new AnExpensiveClass(token);
}
@Override
public Class<? extends AnExpensiveClass> type(Token token) {
return AnExpensiveClass.class;
}
@Override
public String id(Token token) {
return String.valueOf(token.getId());
}
@Override
public String displayName(Token token) {
return "my lazy loading delegate";
}
}
----
==== Code that creates a Lookup and registers the InstanceContent:
[source,java]
----
ic = new InstanceContent();
al = new AbstractLookup(ic);
Token token = new Token(12345);
ic.add(token, new LazyLoadingDelegate());
----
Your link:http://bits.netbeans.org/dev/javadoc/org-openide-awt/org/openide/awt/Actions.html#context[context-sensitive action] will behave normally&mdash;it does not need to know about the lazy loading (code not relevant to lazy loading has been removed for the sake of brevity):
[source,java]
----
public final class ExpensiveClassAction implements ActionListener {
private final AnExpensiveClass expensiveClass;
public ExpensiveClassAction(AnExpensiveClass a) {
this.expensiveClass = a;
}
public void actionPerformed(ActionEvent ev) {
// now you have the actual do AnExpensiveClass instance,
// in variable expensiveClass
// so do something with it...
}
}
----
==== Lifecycle With InstanceContent.Converter
Objects created using an InstanceContent.Converter are only weakly cached by default. That means that, after AnExpensiveClass is instantiated, it can be garbage collected if no object holds a reference to it in a field. If the object is going to be queried for repeatedly, you may want your InstanceContent.Converter to cache the last-created value, either for some period of time, or using a SoftReference or hard reference or other caching strategy.
=== Apache Migration Information
The content in this page was kindly donated by Oracle Corp. to the
Apache Software Foundation.
This page was exported from link:http://wiki.netbeans.org/DevFaqLookupLazyLoad[http://wiki.netbeans.org/DevFaqLookupLazyLoad] ,
that was last modified by NetBeans user Jtulach
on 2010-07-24T20:19:40Z.
*NOTE:* This document was automatically converted to the AsciiDoc format on 2018-02-07, and needs to be reviewed.