Accessing and sharing modules' resources

$Revision: 1.2 $
Changes: available in CVS

Abstract:

Description of problems that we have to face when converting settings from a memory storage and using them in modules is given here. Sample usecases of expected usage of the settings for communication are described and common mistakes and usual problems investigated.

Known problems

  • Scalability is an obvious task. User should pay as less as possible for the amount of installed modules. The current style of storing settings (SharedClassObject) does not scale bad, but still influences startup more than needed.
  • Duplication of ugly code. there is a bunch of ugly code duplicating our the codebase that tries to access objects on system filesystem. We need a solution to kill code like PersistenceManager.java line 408, FileEntityResolver.java line 242 method findObject and the bunch of similar code that would have to be introduced in openidex/commands, openidex/looks and other modules.
  • Simplicity. The current API for accessing composable settings - the FolderInstance - is not easy to deal with. One has to subclass and override a set of methods to do what he wants and still not receive everything. The Window System guys decided to not use FolderInstance because of not beying able to control the synchronization between own modification of settings (component written to disk) and external changes (module installed, session switched). That is why they copied part of the functionality and got into deep problems with stabilization of their solution. Their code should be refactored to use a common solution thus preventing copy-paste spread of bugs.
  • Common inteface. There is a lot of code that wants to access settings and interact with user and other modules (popup menu creation, URL providers, BeanInfo and PropertyEditor searchers) and a lot of them wants to stay far way from Filesystems and Datasystems API needed for the current solution. There is a need to have a simple API accessible to everyone (means packaged in openide-util or JDK itself).
  • Lazy initialization. In the inter-modules communication we are searching for a solution to that will allow lazy registration and lookup. Modules should not execute any code in order to register, instead they should provide a declarative description of what they register that will be converted into the live object when needed.

Usage examples

This section tries to describe expected usecases without implementation details. It uses method Object find (String) to say that we are looking for a resource with specified name and Enumeration findAll (String) if we are looking for all objects registered under the given name. Also consider a method register (String, Object) that will allow any module to associate new object with the given name.

Please check discussion summary for more opinions on this subject.

Example 1: Looking up an implementation of URLHandler
The goal is to find proper java.net.URLHandler for nbdocs:/mydocs.html URL. Because the set of supported URLs is pluggable and we want the lazy registration, we will use the method find to request the handler. First of all we choose a root namespace ("/Providers/URLHandlers") and then locate the correct handler by:
        find ("/Providers/URLHandlers/nbdocs");
Example 2: Looking up actions
Imagine Java module trying to find out which actions to show in popup menu of a node representing a java source. Right now it just displays the actions associated with the loader, but that works really badly for other modules that want to extend the Java object. The right solution would be to specify common name for the loader and read actions registered by different modules there.
        Enumeration en = findAll ("/Loaders/Actions/org/netbeans/modules/java/");
while (en.hasMoreElements ()) {
Object obj = en.nextElement ();
if (obj instanceof Action) {
popupMenu.add ((Action)obj);
}
}
Example 3: Update on changes
Right now the window system listens on changes in "Windows/Workspaces" directory and updates the actual screen content by changes it recieves from filesystem and datasystem layers. The code is very complicated, because it spans around three different subsystems (fs, ds, instance convertion) and thus potentially (and actually) buggy. We need to take divide and conquer approach and simplify it by splitting the implementation out of the window system.

The window system shall deal just with instances of Workspace, Mode and TopComponent, exactly as described in example one and two. Plus it needs a notification mechanism that allows it to update when ever a change is made.

Example 4: Own changes
Let's demonstrate another problem on the example of window system. As described in example 3, the window system has to react to external changes made on the instances pool (module uninstall, programmatic changes, etc.). But it also needs to reflect the changes made by a user like component opening or closing to the persistent instances pool. For it there shall be a update method
    register ("Windows/Workspaces/Mode5", mode5);
that will store the object mode5 under the desired name.

Connected to this is another problem - the ability to recognize its own changes from changes made by somebody else. Because own changes can be ignored, because they were already made (btw. current FolderInstance is very weak exactly in this).


Suggested solution

In order to solve the above given problems we should define an interface that supports queries based on names, lazy initialization, update and change notification. Morever it shall be relatively independent on the rest of NetBeans API to be usable from any module in NetBeans.

Well, we can design such, but there seems to already exist such general purpose one - JNDI. It has methods to lookup object or set of objects by a name and provides the register/unregister facility. Also it has interface to a voluntary extension - the EventContext that provides the ability to be notified when an object is registered/unregistered.

Here is the rewrite of the general examples in the terms of JNDI.

Example 1: Looking up an implementation of URLHandler
        InitialContext ic = new InitialContext ();
ic.lookup ("/Providers/URLHandlers/nbdocs");
Example 2: Looking up actions
        Enumeration en = new InitialContext ().list ("/Loaders/Actions/org/netbeans/modules/java/");
while (en.hasMoreElements ()) {
Object obj = en.nextElement ();
if (obj instanceof Action) {
popupMenu.add ((Action)obj);
}
}
Example 3: Update on changes
    Context c = new InitialContext ().lookup ("/Windows/Workspaces");
if (c instanceof EventContext) {
EventContext ev = (EventContext)c;
ev.addNamingListener (myNamespaceListener);
}
Example 4: Own changes
    Context c = new InitialContext ();
Object o = c.lookup ("Windows/Workspaces");
if (!o instanceof Context) {
return;
}
c = (Context)o;
c.bind ("Mode5", mode5);

// and in the namespace listener use
if (event.getChangeInfo () == c)
// to recognize changes made thru the context c

Comments? Send them to
nbdev!

Project Features

About this Project

openide was started in November 2009, is owned by Antonin Nebuzelsky, and has 92 members.
By use of this website, you agree to the NetBeans Policies and Terms of Use (revision 20160708.bf2ac18). © 2014, Oracle Corporation and/or its affiliates. Sponsored by Oracle logo
 
 
Close
loading
Please Confirm
Close