Having discussed yesterday with Alex Blewitt and Lars Vogel on what @Active
is I thought it might make sense to explain it in a short blog post.
Let’s start with the question Alex posted on twitter: “Which is preferable; using @Named(ACTIVE_SHELL)
or @Active shell
”
Answer: they are completely different things!
Before we understand why we need to know more about the IEclipseContext and how it works:
- There’s not a single context but a hierarchy of context
- Child-Contexts have access to informations of themselves and their parent(s)
So if we have code like this:
public class MyBean { private IEclipseContext owner; private String parentValue; private String childValue; @Inject public MyBean(IEclipseContext owner) { this.owner = owner; } @Inject void setParentValue(@Optional @Named("parent_value") String value) { this.parentValue = value; } @Inject void setChildValue(@Optional @Named("child_value") String value) { this.childValue = value; } void print() { System.err.println(owner.toString() + ": parent = " + parentValue + "; child: " + childValue); } }
IEclipseContext rootContext = EclipseContextFactory.getServiceContext(FrameworkUtil.getBundle(getClass()).getBundleContext()); rootContext.set("parent_value","Hello Parent"); MyBean p = ContextInjectionFactory.make(MyBean.class, rootContext); p.print(); // OSGi context for bundle: test.di.active: parent = Hello Parent; child: null IEclipseContext childContext_1 = rootContext.createChild("Child 1"); childContext_1.set("child_value","Hello Child 1"); MyChildBean c1 = ContextInjectionFactory.make(MyBean.class, childContext_1); c1.print(); // Child 1: parent = Hello Parent; child: Hello Child 1
Anyone working with e4 knows about this already so it should be clear.
To understand now @Active
you have to know a much less know thing about the IEclipseContext
hierarchy:
The notion of an activeBranch/activeContext
when working in e4 you do not recognize this but the framework switches the activeContext based on which area of your UI currently has the input focus by calling IEclipseContext#activateBranch
. Lets extend our example a bit:
IEclipseContext childContext_1 = rootContext.createChild("Child 2"); childContext_1.set("child_value","Hello Child 2"); MyChildBean c1 = ContextInjectionFactory.make(MyBean.class, childContext_2); c2.print(); // Child 2: parent = Hello Parent; child: Hello Child 2 childContext_1.activateBranch(); p.print(); // // OSGi context for bundle: test.di.active: parent = Hello Parent; child: null childContext_2.activateBranch(); p.print(); // // OSGi context for bundle: test.di.active: parent = Hello Parent; child: null
Now let’s modify the bean code using @Active
public class MyBean { @Inject void setChildValue(@Optional @Named("child_value") @Active String value) { this.childValue = value; } }
if we now execute the code once more we’ll get the following out put for the last 2 p.print() statements from above:
OSGi context for bundle: test.di.active: parent = Hello Parent; child: Hello Child 1 OSGi context for bundle: test.di.active: parent = Hello Parent; child: Hello Child 2
This means @Active
works in the opposite direction of the IEclipseContext
hierarchy and instances created on a parent context can track values from their active child using it!