This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

Bug 34057 - Suggest ability to create merged Context's permitting inherited + overridden settings
Summary: Suggest ability to create merged Context's permitting inherited + overridden ...
Status: RESOLVED FIXED
Alias: None
Product: platform
Classification: Unclassified
Component: -- Other -- (show other bugs)
Version: 3.x
Hardware: All All
: P1 blocker (vote)
Assignee: rmatous
URL:
Keywords: API
Depends on:
Blocks: 32701 33980 35110
  Show dependency tree
 
Reported: 2003-05-30 17:01 UTC by Jesse Glick
Modified: 2008-12-22 16:50 UTC (History)
4 users (show)

See Also:
Issue Type: ENHANCEMENT
Exception Reporter:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Jesse Glick 2003-05-30 17:01:35 UTC
It seems to be somewhat common that you want to
gather registered settings for some kind of
configuration from several Context's (~ SFS
folders) with parallel structure, where the
contexts are automatically merged together, meaning:

- all subcontexts and bindings in the delegates
are present in the supercontext, with earlier
delegates taking precedence over later in case of
name conflicts

- attributes should probably be merged similarly;
TBD whether if delegates C1 and C2 both define
attrs with different names on a binding B, whether
the merged binding B should have both attrs etc.;
probably attrs on the context (binding name ==
null) ought to be merged

- changes to the merged context should be written
only to the first delegate ("writable layer");
should support "masking" (deletion)

- ideally ordering could be supported somehow; at
least the merged context needs to support
orderContext; preferably it would be possible in
the registration method (e.g. layers) to define
the merged order somehow

Without the Registry API, using Filesystems +
Datasystems + InstanceCookie/FolderInstance, all
of the above are possible using MultiFileSystem:
files and folders and attributes are all merged in
the (perhaps) natural way; changes are always
written to the first delegate, incl. masks; order
is controlled by relative ordering constraints,
which merge well since they are independent folder
attributes.
Comment 1 Jesse Glick 2003-05-30 17:02:27 UTC
Brought up as part of issue #33980 - requested inheritable settings
for editor kits.
Comment 2 David Konecny 2003-06-02 08:33:14 UTC
Vita, you could take advantage of this as well in new projects, right? 
Comment 3 Vitezslav Stejskal 2003-06-02 11:27:55 UTC
I think we could, but it depends on how it will look like. In projects
we have ProxyContext which does something similar like what Jesse is
suggesting. This functionality is exposed through the API -
Contexts.createContext(Context writable, Context[] delegates) - which
is sufficient for most case. However, we also need to have the
possibility to create ProxyContext which dynamicaly changes the set of
its layers. IMO that would require to have the ProxyContext in the SPI
and be able to subclass it.

If you are interested in our implementation look in the projects/core
module (packages **/settings) - it's not still rewritten to new
Registry API so the Context here is the JNDI Context.
Comment 4 Jesse Glick 2003-06-02 16:34:37 UTC
Vita - do you need ability to subclass, or would it suffice to have a
final class that you could create an instance of and call some method
to change the delegates? If you need to subclass, please try to list
all of the things you might want to override.
Comment 5 Vitezslav Stejskal 2003-06-03 15:52:08 UTC
Right now the subclass of ProxyContext changes the delegates and also
keeps some internal data and registers listener to the settings
inheritance manager and updates appropriately. If I couldn't subclass
I will have to either create BasicContext and delegate all methods to
the ProxyContext or create some special class which will hold the
internal data, implement the listener and keep reference to the
ProxyContext and which will be cached somewhere. It's possible, but
subclassing would be easier.
Comment 6 Jesse Glick 2003-06-03 16:54:55 UTC
OK - but you don't need to override any particular methods, just e.g.:

public class MergedContext implements ResettableContext, RootContext {
    public MergedContext(BasicContext writable, BasicContext[] readables);
    protected BasicContext getWritableLayer();
    protected void setWritableLayer(BasicContext);
    protected BasicContext[] getReadableLayers();
    protected void setReadableLayers(BasicContext[]);
}

Of course this would be in org.netbeans.spi.registry.*. Would that
suffice?

Not exactly sure about the details as far as how the RootContext
methods are handled. You might want to require that all the layers
have the same RootContext ancestor. Or use only the RootContext from
the writable layer. Or implement them specially, e.g. findObject to
look in all the delegated-to RC's.
Comment 7 Vitezslav Stejskal 2003-06-03 18:42:38 UTC
No, I don't need to override any particular method, the MergedContext
is sufficient IMO. BTW, I think you meant to make its methods final,
right?

Another question: Would it be possible to create MergedContext for
Context (API) instances. I think that clients will usually have
Context instances and they still may want to merge them together. The
example I have in my mind is that dialogs customizing some settings
persisted in Context could use two-layer Context for implementing
OK/Apply/Cancel logic. The writable layer of composite Context would
be memory implementation of Context which will be flushed to the
second layer on OK/Apply. The memeory Context could be BasicContext
subclass, but the real-data Context (second layer) will usual be
obtained from the API and thus will be the API Context.
Comment 8 Jesse Glick 2003-06-03 20:19:46 UTC
Final, yes, sorry.

Re. use of Context vs. BasicContext - good question. This is the price
you pay for trying to separate API from SPI - you limit the ability of
the client to actually use the object freely. One option is to provide
a method in Context

public final BasicContext getBasicContext();

or equivalently, to keep the API package clean, in SpiUtils:

public static BasicContext basicContextFor(Context c);

Or skip these public methods but have the MergedContext privately
extract the BasicContext from a Context using some backdoor. (I
dislike this option because it implies that MergedContext could not be
written correctly if implemented in another module, which seems like
poor design to me.)
Comment 9 David Konecny 2003-06-04 08:38:05 UTC
I admit something like that might be necessary. The 

  public static BasicContext basicContextFor(Context c);

in SPIUtils sounds reasonable to me, but I would add it only if there
is no other solution for the usecase. :-)

Your customizer dialog usecase could be solved also this way. In API
will be 

  public static Context Context.merge(Context[] delegates);

which allows clients to create a merged context from API Contexts. In
your case you have memoryContext (=API Context which BasicContext is
memory implementation) and realContext (=API Context which
BasicContext has real data). You can merge these two contexts by the
above method and pass result to the customizer. When user pressed
OK/Apply you can enumerate memoryContext content and commit all values
into the realContext. Would this work?
Comment 10 Vitezslav Stejskal 2003-06-04 13:50:22 UTC
Sure, it would work. I am perfectly ok with the 'API' version of
MergedContext. 

I am just curious - are you going to use the backdoor or to have two
different impl - APIMergedContext and SPIMergedContext? Personally I
am in favor of having two implementations.

Comment 11 David Konecny 2003-06-04 16:52:14 UTC
"are you going to use the backdoor or to have two different impl" - I
do not know yet. Depends on what is easier. :-) And better. At first
glance I would also said that two diff impls are better.
Comment 12 Jesse Glick 2003-06-04 16:56:15 UTC
The problem with

public static Context Context.merge(Context[] delegates);

is that you cannot later change the delegates. For some use cases it
matters.
Comment 13 David Konecny 2003-06-04 17:08:13 UTC
Yes.
Comment 14 Jaroslav Tulach 2003-06-05 09:34:06 UTC
Changing delegates can be implemented in the nicest way by having:

interface MergeContextProvider {
  public add/removePropertyChangeListener (..);
  public Context[] getContexts ();
}

maybe also letting the add/remove listener method to throw
TooManyListenersException because we want and need only one listener
to be attached. Btw. this seems like a clear SPI.

The more simpler and more hackier way is to trick everything as
Lookups.proxy does:
http://www.netbeans.org/download/dev/javadoc/OpenAPIs/org/openide/util/lookup/Lookups.html#proxy(org.openide.util.Lookup.Provider)
and have only 

public static Context Context.merge(List delegates);

and say that (for example) resultContext.getSubContext (null) will
retrieve the delegates from the list again, update the content and
fire changes.

Comment 15 Vitezslav Stejskal 2003-06-05 10:34:42 UTC
The result of Lookups.proxy(L.P) doesn't fire events correctly when
L.P changes the set of Lookups, right? This is not acceptable for
settings IMO.

The MergedContextProvider iface looks good. Why do you think that one
MCP can't be used to create more ProxyLookups?
Comment 16 Jaroslav Tulach 2003-06-05 18:10:26 UTC
Ad1: Not sure what you are talking about. Lookups.proxy fires changes
as good as ProxyLookup.setLookups.

Ad2: I think that this simplifies the implementation on the SPI side.
You need just pointer to the listener and not whole
PropertyChangeSupport. If some SPI wants, then it can support multiple
listeners, no problem with that, but usually that will not be the case
IMHO.
Comment 17 David Konecny 2003-06-11 14:00:15 UTC
Projects needs this now and so I'm going to work on it.
Comment 18 David Konecny 2003-06-11 15:37:41 UTC
Btw. if I implement context merging properly (ie. including "masking"
for deletion, etc.) then I do not need to use SessionManager
internally at all. I can create two SPI contexts - one for
installation dir root and second for customization dir root - and
merge these two contexts. This brings lot of open possibilities for
future........
Comment 19 David Konecny 2003-06-12 13:36:13 UTC
Radek volunteered to implement this.
Comment 20 David Konecny 2003-06-16 11:04:22 UTC
In
<http://openide.netbeans.org/proposals/settings/mergedcontextsmasking.html>
I tried to summarize how the masking of deleted items should work in
merged context. It is inspired by MultiFS impl and on examples it
illustrates how it should be done. I started it mainly because it was
not clear to me in which cases the masking is needed.

Then I also added slightly modified version which stores masking attrs
in external storage (properties file, registry context, ...).

I tried to make examples very accurate and complete. If you disagree
with something or think that semantic should be different or see some
other case not covered in doc please let me know.
Comment 21 Tomas Zezula 2003-07-22 14:05:03 UTC
Blocker for Java Module, increasing priority to P1.
Comment 22 David Konecny 2003-07-22 14:24:06 UTC
I just talked with Tomas and gave him solution which should help them.
Once they try it they will update this issue.
Comment 23 rmatous 2003-09-30 16:19:50 UTC
Implemented in trunk.