org.netbeans.spi.registry.BasicContext
which provides this basic functionality: merges subcontexts,
bindings and context attributes according their names for arbitrary
number of delegates and takes precedence in case of name
conflict. This implementation of org.netbeans.spi.registry.BasicContext
and also its API context is bellow called Merged Context.public static Context
org.netbeans.api.registry.Context.merge (Context[] delegates)
public static BasicContext
org.netbeans.spi.registry.SpiUtils.merge (MergeContextProvider)
org.netbeans.spi.registry.MergeContextProvider:
public interface MergeContextProvider {
public static final String PROP_DELEGATES_CHANGED = "PROP_DELEGATES_CHANGED"; //NOI18N
public void addPropertyChangeListener (PropertyChangeListener listener);
public void removePropertyChangeListener (PropertyChangeListener listener);
public BasicContext[] getDelegates ();
}
Implementation of Merged Context registers its PropertyChangeListener
and as soon as PROP_DELEGATES_CHANGED
is fired, then method getDelegates
()
is called and this invokes refresh of root context and all
live descendant subcontexts. This may cause, that ContextEvents
are fired.
Implementation of method getDelegates ()
requires
to return instances of some implementation of BasicContext
.
In ther words it means probably to provide its own implementation of
BasicContext
.
Return value of this factory method can be passed to method SpiUtils.createContext
to
get org.netbeans.api.registry.Context.
All descendant subcontexts of this instance lives so long as some non-Registry code is holding a reference to the object, subsequent calls will return the same object.
On the other hand Merged Context does not create new instances for bindings, but delegates calls to its delegating contexts and then there is only one object and it should be the same without regard whether it was created from the regular Context or from the Merged Context.
Subcontext, bindings and attributes provided by their delegates are merged according their names. There is important that there is taken precedence in case of name conflict. There is true: the lower index in the array the higher priority.
Merged Context provides subcontext for subcontext name only if at least one of its delegates provides this subcontext.
Attributes related to bindings are not merged at all. On the other hand attributes related to context are merged from all delegates.
If name for binding comes from two or more delegates, then the instance from delegate with highest priority is returned from Merged Context and also only this delegate with highest priority provides attributes and attribute names for this binding.
Listener registered on Merged Context will receive events about modifications of this context and all its descendant live subcontext instances.
Destroy of subcontext destroys all descendant subcontexts and naturally all descendant subcontetxs must fire SubcontextEvents.
There is obvious, that as soon as event is fired, then Merged
Context must be in consistent status, which means that added or modified
subcontext, binding or attribute must be reachable and on the other hand
removed suncontext, binding or attribute can't be reachable.
Active delegate is the one and the only one delegate with special meaning among others: all modifications go into active delegate (newly created, destroyed or modified subcontexts, bindings or attributes). All other delegates are considered as read-only. There is true that active delegate is the one with index zero.
Delegates of Merged Context may be instances of Merged Context again.
Method merge with zero delegates returns instance of context impl., that has no content (subcontexts, bindings, attributes). This is true for root context, else there won't be returned no subcontext instance if there is zero delegates. Zero-delegate merged context is automatically read-only.
Destroyed subcontexts, bindings and attributes from read-only delegates must be masked on active delegate. Merged Context isolates its clients from this mechanism and masks must be considered as implementation detail.
Binding has default value if there exists binding on one of read-only delegates Binding is modified if this binding comes from active delegate or there doesn't exist default value for this binding. Revert of binding means destroy of binding on active delegate and also destroy its mask.
In the merged context, Context.hasDefault(null) will be true when at least one read-only delegate has a context with the same path. Context.isModified(null) will be true in case a context with the same path exists on the active delegate (whether or not contexts with that path exist on any of the read-only delegates). Context.revert(null) will remove the context with the same path from the active delegate, if it exists.