Skip to main content

Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

E4/Contexts/Lookup

< E4‎ | Contexts

Historical Document: The lookup strategy was not implemented

Lookup Usecases

We have the IEclipseContext hierarchy and we provide our framework data and framework services by a pattern of lookup strategies. E4/Contexts#Available_Services_in_Eclipse_e4 contains some examples that we look up.

The lookups are done for explicit requests and for DI. Our general guiding principle is "When you ask your context a question, you should get back the appropriate answer."

But that translates into a number of different usecases:

  1. The application context expects to provide the application view of the state. i.e. you should be able to ask the application what the active window is, the current selection for the application, etc.
  2. Some information is bounded by a container.
    1. Parts that track the activePart mean the activePart for the window that contains them.
    2. Same with current selection.
    3. A handler in a workbench window want's the part service to search for and show parts within that workbench window.
  3. Sometimes lookups expect to get a local value.
    1. In certain cases, especially for editors, they expect the activeEditor to be themselves. More specifically, they expect to execute in a context where the part is themselves.
    2. Something like the properties view isn't interested in itself, only other parts (although it listens for the active part and simply ignores itself).

We haven't quite closed on a best practice or set of best practices. bug 295007 comment 25

Lookup Strategies

The default lookup strategy for EclipseContext is:

  1. try for a local value (or value computation)
  2. try a local ILookupStrategy
  3. delegate to the parent context

If the local value is a IContextFunction we evaluate the function and return the result.

No lookup function

This reduces to a map lookup that walks up the parent chain until it finds an answer. You can always see what's above you, and a container can customize the data for the hierarchy below it.

This doesn't make use of the concept of active child at all, which opens the question: How can the application answer questions like the current selection or active part or active window correctly.

Something like a Prototype lookup function

IEclipseContext childContext = (IEclipseContext) context
		.getLocal(IContextConstants.ACTIVE_CHILD);
if (childContext != null) {
	return childContext.get(FUNCTION_VAR);
}
return context.get(VALUE_VAR);

This should walk down the active child chain, asking each child context to evaluate the function. When it can no longer find a child context, it asks for the value. For some reason, it doesn't work the way I expect.

An iterative lookup function

IEclipseContext leafContext = context;
IEclipseContext child = (IEclipseContext) leafContext
		.getLocal(IContextConstants.ACTIVE_CHILD);
while (child != null) {
	leafContext = child;
	child = (IEclipseContext) leafContext.getLocal(IContextConstants.ACTIVE_CHILD);
}
return leafContext.get(VALUE_VAR);

Simply walk down the active context chain until you reach a leaf context, and then ask for the value. This works as expected, and means you will always find the value as specified by you or your active child.

A Sum lookup function

IEclipseContext childContext = (IEclipseContext) context
		.getLocal(IContextConstants.ACTIVE_CHILD);
if (childContext != null && arguments.length == 0) {
	return childContext.get(IServiceConstants.ACTIVE_CONTEXTS);
}
Set<String> rc = null;
if (arguments.length == 0) {
	rc = new HashSet<String>();
} else {
	rc = (Set<String>) arguments[0];
}
Set<String> locals = (Set<String>) context
		.getLocal(ContextContextService.LOCAL_CONTEXTS);
if (locals != null) {
	rc.addAll(locals);
}
IEclipseContext parent = (IEclipseContext) context
		.get(IContextConstants.PARENT);
if (parent != null) {
	parent.get(IServiceConstants.ACTIVE_CONTEXTS,
			new Object[] { rc });
}
return rc;

This is an example of a lookup function that will return a set containing the sum of local values, in this case LOCAL_CONTEXTS. It has the 2 attributes needed for the command/keybinding system:

  1. A view sets an active context id (in this case, legacy contexts). When the view asks its IEclipseContext for the activeContexts, it gets back the correct set including the ID it activated.
  2. The application level activeContexts is continually changing based in the current active child chain. This is great for correct keybinding lookups.


Root based lookups

Services like the Part Service depend on setting a container root to be used. ex: EPartService.PART_SERVICE_ROOT. Currently the E4Application creates an application level IContextFunction that has a complex lookup. We're using this as a way to deal with the container based usecase.

MContext perceivedRoot = (MContext) context.get(MWindow.class
		.getName());
if (perceivedRoot == null) {
	perceivedRoot = (MContext) context.get(MApplication.class
			.getName());
	if (perceivedRoot == null) {
		return null;
	}
}
 
IEclipseContext current = perceivedRoot.getContext();
if (current == null) {
	return null;
}
IEclipseContext next = (IEclipseContext) current
		.getLocal(IContextConstants.ACTIVE_CHILD);
while (next != null) {
	current = next;
	next = (IEclipseContext) current
			.getLocal(IContextConstants.ACTIVE_CHILD);
}
 
Object object = current.get(MPerspective.class.getName());
if (object == null) {
	// we need to consider detached windows
	MUIElement window = (MUIElement) current.get(MWindow.class
			.getName());
	if (window == null)
		return null;
	MElementContainer<?> parent = window.getParent();
	while (parent != null && !(parent instanceof MApplication)) {
		window = parent;
		parent = parent.getParent();
	}
	return window;
}
return object;

Back to the top