NetBeansIdioms InjectableLookupFactory

Revision as of 21:18, 6 November 2009 by Admin (Talk | contribs)
(diff) ← Older revision | Current revision (diff) | Newer revision → (diff)

=== This document is a draft - should not be linked yet. In the meantime, please refer to this DZone informal article about this topic.

Injectable Lookup Factory

Contents


Related patterns and idioms

Related NetBeans Platform APIs


Can be used in JSE applications?

This idiom can be used in plain JSE applications, as the Lookup API can be used outside of the NetBeans Platform.


Family

Creational.

Context

The Lookup API is a simple and powerful mean for designing services with a good separation between interface and implementation. The essence of the Lookup API is the Lookup class, which is used for searching objects:

Lookup lookup = ... // get a Lookup somewhere
MyClass myObject = lookup.lookup(MyClass.class);

Many times a "default" or "global" Lookup is used, which acts a sort of application-wise context:

MyClass myObject = Lookup.getDefault().lookup(MyClass.class);

Often MyClass is an interface (or abstract class) describing a service; it could be implemented in alternate, polymorphic ways (e.g. the real service and a mock for tests). In this form, the Lookup API is clearly used as a "service locator".

By default, the requested object is instantiated as a singleton; and of course implementations may be specified in a different module of the calling code (this is one of the cases that makes most sense). Lookups can search for concrete implementations in many different ways, typically by means of the META-INF/services mechanism. Multiple implementations of the service can be provided; in this case lookup.lookupAll() is used for retrieving all of the results.

Besides the global Lookup, specific instances of Lookup can be bound to model objects in order to implement object capabilities. TBD: better

ModelObject modelObject = ...;
Capability1 capability1 = modelObject.getLookup().lookup(Capability1.class);

if (capability1 != null)
  {
    capability1.doSomething();
  }

For the sake of clarity, we will refer the model object that contains the capabilities as the owner of the capabilities. A typical owner object can be implemented as follows:

public class Owner
  {
    @Nonnull
    private final Lookup lookup;

    public Owner()
      {
        lookup = Lookups.fixed(... list of capability instances ...);
      }

    @Nonnull
    public Lookup getLookup()
      {
        return lookup;
      }
  }

The Lookups.fixed() call in the previous code listing is a utility method from the Lookup API that creates a new immutable Lookup containing the objects passed as parameters. It should be noted that the DataObject class from the DataSystems API (TBD: link) fits well with this approach, as it already exposes a getLookup() method; but as the previous example demonstrates, this approach can be used with any kind of class, including POJOs.


Problem

Once you have modeled your objects as containers of capabilities, a problem with dependencies arise. Looking at the latest code example, it seems that at instantiation time we have a dependency from the owner to each capability. This implies two drawbacks:

  1. The kind and the number of the capabilities are hardwired in code, thus forcing a change and recompilation of Owner if different capability sets are needed.
  2. Some capabilities could be related to specific technologies (e.g. the database, a GUI), thus introducing architectural dependencies too.


Forces

  • An object is implemented as a composition of capabilities contained in a private instance of Lookup.
  • An extensive used of capabilities is being done, including things related to specific technologies such as persistence, user interface, I/O, etc.
  • The binary code for the model object needs to be reused as is in different platforms where different combinations of other modules could be used to add different kinds of capabilities.


Solution

The GoF Factory Method pattern is a well known solution for removing unwanted couplings among classes at instantiation time: so introducing a specific factory (InjectableLookupFactory) for creating the capabilities is the first step. The second, and final, step is to further delegate the creation of capabilities to multiple, specific factories (CapabilityProviders) that are dynamically discovered by the global Lookup.

File:InjectableLookupFactory NetBeansIdioms InjectableLookupFactory NetBeansIdioms InjectableLookupFactory.png


These are the participants of this idiom:

CapabilityOwner
the object that exposes the Capabilities.
InjectableLookupFactory
the core of this idiom, a factory that creates a Lookup populated with the required Capabilities.
Capability
a class modeling a pluggable behaviour of the Owner.
CapabilityProvider
the interface for a factory for Capability. TBD: rename into CapabilityFactory?
ConcreteCapabilityProvider
a concrete implementation of CapabilityProvider. TBD: rename into ConcreteCapabilityFactory?


File:InjectableLookupFactory Sequence NetBeansIdioms InjectableLookupFactory NetBeansIdioms InjectableLookupFactory NetBeansIdioms InjectableLookupFactory.png


Alternate Implementations

TBD: providing pre-made Lookups

TBD: with the use of layer.xml (but this introduces a dependency on FileSystems API).

public class InjectableLookupFactory
  {
    public static Lookup createLookup (@Nonnull final Object owner,
                                       @Nonnull final Lookup ... extraLookups)
      {
        final List<Lookup> lookups = new ArrayList<Lookup>();

        for (final CapabilitiesProvider provider : 
             Lookup.getDefault().lookupAll(CapabilitiesProvider.class))
          {
            if (provider.getManagedClass().isAssignableFrom(owner.getClass()))
              {
                lookups.add(Lookups.fixed(provider.createCapabilities(owner).toArray()));
                lookups.addAll(provider.createLookups(owner));
              }
          };

        lookups.addAll(Arrays.asList(extraLookups));

        return new ProxyLookup(lookups.toArray(new Lookup[0]));
      }
  }



Examples

TBD

TBD: move the description of capability composition to a specific idiom ("Object with Lookup" or a better name)

TBD: this is an immutable Lookup - what if some capabilities have to be added and removed over time? It's a thing for "Object with Lookup". In any case, InjectableLookupFactory could be still used for initial values. But who's in charge for adding and removing capabilities? Maybe this would be a different idiom.

TBD: CapabilityProvider may take decisions depending on the specific instance of CapabilityOwner - that is, we are not forced to provide the same set of capabilities for any instance.


Not logged in. Log in, Register

By use of this website, you agree to the NetBeans Policies and Terms of Use. © 2012, Oracle Corporation and/or its affiliates. Sponsored by Oracle logo