Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » Eclipse 4 » Trying to get E4 services(I guess I'm not understanding injection)
Trying to get E4 services [message #1016293] Tue, 05 March 2013 16:22 Go to next message
Jo Jaquinta is currently offline Jo Jaquinta
Messages: 40
Registered: January 2013
Location: Boston
Member

So there is an E4 service I want to use in a class. Everything I read says that I get it by using injection. For example:
@Inject IStylingEngine mStyler;

However, this code only seems to work in classes that are directly invoked by the E4 layer. I.e. if I have a class that is a Class URI for a Part, then mStyler is correctly set. However, if that class uses other UI controls, and further down, one of those controls uses this code to get at the service, it is never set.
Following some other posts, I tying using E4Workbench.getServiceContext.get(XXX) or even creating an IEclipseContext from my bundle. But these always return null when I ask it for the service.
So is there any way I can get a service from an arbitrary point of code? It's going to make things awfully ugly if I have to resolve it at the point my code touches the framework and then pass it down the constructor stacks.


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Jo Grant, Senior Software Engineer
Admin and Config Console Architect
OpenPages, IBM
Re: Trying to get E4 services [message #1016302 is a reply to message #1016293] Tue, 05 March 2013 17:50 Go to previous messageGo to next message
Thomas Schindl is currently offline Thomas Schindl
Messages: 5294
Registered: July 2009
Senior Member
You need to create instance of your subclasses using
ContextInjectionFactory.make()

Tom

Am 05.03.13 22:22, schrieb Jo Jaquinta:
> So there is an E4 service I want to use in a class. Everything I read
> says that I get it by using injection. For example:
> @Inject IStylingEngine mStyler;
> However, this code only seems to work in classes that are directly
> invoked by the E4 layer. I.e. if I have a class that is a Class URI for
> a Part, then mStyler is correctly set. However, if that class uses other
> UI controls, and further down, one of those controls uses this code to
> get at the service, it is never set.
> Following some other posts, I tying using
> E4Workbench.getServiceContext.get(XXX) or even creating an
> IEclipseContext from my bundle. But these always return null when I ask
> it for the service.
> So is there any way I can get a service from an arbitrary point of code?
> It's going to make things awfully ugly if I have to resolve it at the
> point my code touches the framework and then pass it down the
> constructor stacks.
Re: Trying to get E4 services [message #1016479 is a reply to message #1016302] Wed, 06 March 2013 10:41 Go to previous messageGo to next message
Jo Jaquinta is currently offline Jo Jaquinta
Messages: 40
Registered: January 2013
Location: Boston
Member

Hey Tom,
Thanks for the response. That will come in useful. Someday. But since you need an IEclipseContext before you can call ContextInjectionFactory.make(), I'm still stuck as described. I don't know how to get the default IEclipseContext to pass in.
I've tried the following:

class Test
{
    @Inject
    public IStylingEngine mStyler;
}


invoked by:

        try
        {
            IEclipseContext context1 = E4Workbench.getServiceContext();
            Test t1 = ContextInjectionFactory.make(Test.class, context1);
            if (t1.mStyler != null)
                System.out.println("Case 1 works!");
            else
                System.out.println("Case 1 fails");
        }
        catch (Exception e)
        {
            e.printStackTrace();
            System.out.println("case 1 fails");
        }
        try
        {
            IEclipseContext context2 = EclipseContextFactory.getServiceContext(Activator.getContext());
            Test t2 = ContextInjectionFactory.make(Test.class, context2);
            if (t2.mStyler != null)
                System.out.println("Case 2 works!");
            else
                System.out.println("Case 2 fails");
        }
        catch (Exception e)
        {
            e.printStackTrace();
            System.out.println("case 2 fails");
        }
        try
        {
            Test t3 = ContextInjectionFactory.make(Test.class, null);
            if (t3.mStyler != null)
                System.out.println("Case 3 works!");
            else
                System.out.println("Case 3 fails");
        }
        catch (Exception e)
        {
            e.printStackTrace();
            System.out.println("case 3 fails");
        }

All of these report failure.


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Jo Grant, Senior Software Engineer
Admin and Config Console Architect
OpenPages, IBM
Re: Trying to get E4 services [message #1016497 is a reply to message #1016479] Wed, 06 March 2013 11:54 Go to previous messageGo to next message
Sopot Cela is currently offline Sopot Cela
Messages: 597
Registered: December 2010
Senior Member

What does the invoker look like? There is no default IEclipseContext. There are a lot IECs (the context hierarchy) and an active one. The idea is that when you do CIF.make(C,IEC); all the @Inject's in C are looked up in the IEC context and it's parents. So this invoker guy is part of your application or some out of container JUnit test or something else?
Re: Trying to get E4 services [message #1016516 is a reply to message #1016497] Wed, 06 March 2013 13:07 Go to previous messageGo to next message
Jo Jaquinta is currently offline Jo Jaquinta
Messages: 40
Registered: January 2013
Location: Boston
Member

The problem is that this depth of code can be arrived at through a variety of means.
I have need of different services throughout my code, but for this, specific, example I have a Composite that creates a whole bunch of UI and wants to style it. (I am converting it from org.eclipse.ui.forms to being e4 CSS driven.)
Sometimes this Composite is constructed in a MPart, but other times I use it directly in a Dialog. (The dialog is launched by clicking on a button with is nested several layers down in a MPart.)
I understand that for a lot of things you want a context very local to the model element in question. But my understanding is that services are generally connected at the very top context, and are, pretty much, universal throughout. If they are, essentially, global, I'd like to be able to access them globally.

[For now I have an ugly hack. I have a startup handler, which gets passed an IEclipseContext. It passes this value to my style control code. Later, when the style control code is requested by the Composite to apply a style, it gets the IStylingEngine from the IEclipseContext it was initialized with. It works. But I'm pretty sure this is not "best practice".]


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Jo Grant, Senior Software Engineer
Admin and Config Console Architect
OpenPages, IBM
Re: Trying to get E4 services [message #1016648 is a reply to message #1016479] Thu, 07 March 2013 04:14 Go to previous messageGo to next message
Thomas Schindl is currently offline Thomas Schindl
Messages: 5294
Registered: July 2009
Senior Member
The service context is to high in the hierarchy. The main Context layout is:

ServiceContext (E4Workbench.getServiceContext())
+ WorkbenchContext (connected to the MApplication-Instance)

The reason for this is that ServiceContext is bound to the OSGi-Instance
so it is a singleton, whereas there can be multiple WorkbenchContexts in
multi-user envs.

Tom

Am 06.03.13 16:41, schrieb Jo Jaquinta:
> Hey Tom,
> Thanks for the response. That will come in useful. Someday. But since
> you need an IEclipseContext before you can call
> ContextInjectionFactory.make(), I'm still stuck as described. I don't
> know how to get the default IEclipseContext to pass in. I've tried the
> following:
>
> class Test
> {
> @Inject
> public IStylingEngine mStyler;
> }
>
> invoked by:
>
> try
> {
> IEclipseContext context1 = E4Workbench.getServiceContext();
> Test t1 = ContextInjectionFactory.make(Test.class, context1);
> if (t1.mStyler != null)
> System.out.println("Case 1 works!");
> else
> System.out.println("Case 1 fails");
> }
> catch (Exception e)
> {
> e.printStackTrace();
> System.out.println("case 1 fails");
> }
> try
> {
> IEclipseContext context2 =
> EclipseContextFactory.getServiceContext(Activator.getContext());
> Test t2 = ContextInjectionFactory.make(Test.class, context2);
> if (t2.mStyler != null)
> System.out.println("Case 2 works!");
> else
> System.out.println("Case 2 fails");
> }
> catch (Exception e)
> {
> e.printStackTrace();
> System.out.println("case 2 fails");
> }
> try
> {
> Test t3 = ContextInjectionFactory.make(Test.class, null);
> if (t3.mStyler != null)
> System.out.println("Case 3 works!");
> else
> System.out.println("Case 3 fails");
> }
> catch (Exception e)
> {
> e.printStackTrace();
> System.out.println("case 3 fails");
> }
> All of these report failure.
Re: Trying to get E4 services [message #1016651 is a reply to message #1016516] Thu, 07 March 2013 04:15 Go to previous messageGo to next message
Thomas Schindl is currently offline Thomas Schindl
Messages: 5294
Registered: July 2009
Senior Member
Best pratice is that *ALL* instances are created through CIF.make() why
can't you create the Dialog, .... also through the DI-Container. I don't
see a reason you can't do this.

Tom

Am 06.03.13 19:07, schrieb Jo Jaquinta:
> The problem is that this depth of code can be arrived at through a
> variety of means.
> I have need of different services throughout my code, but for this,
> specific, example I have a Composite that creates a whole bunch of UI
> and wants to style it. (I am converting it from org.eclipse.ui.forms to
> being e4 CSS driven.)
> Sometimes this Composite is constructed in a MPart, but other times I
> use it directly in a Dialog. (The dialog is launched by clicking on a
> button with is nested several layers down in a MPart.)
> I understand that for a lot of things you want a context very local to
> the model element in question. But my understanding is that services are
> generally connected at the very top context, and are, pretty much,
> universal throughout. If they are, essentially, global, I'd like to be
> able to access them globally.
>
> [For now I have an ugly hack. I have a startup handler, which gets
> passed an IEclipseContext. It passes this value to my style control
> code. Later, when the style control code is requested by the Composite
> to apply a style, it gets the IStylingEngine from the IEclipseContext it
> was initialized with. It works. But I'm pretty sure this is not "best
> practice".]
Re: Trying to get E4 services [message #1016655 is a reply to message #1016651] Thu, 07 March 2013 04:27 Go to previous messageGo to next message
Sopot Cela is currently offline Sopot Cela
Messages: 597
Registered: December 2010
Senior Member

@Tom, I think his issue is that he doesn't want to drag down the IEC which has to be supplied to CIF#make.

If you don't want to extend this context hierarchy downards then I think, theoretically, you can access a top level context and traverse its children until you find a suitable context. But still I think that letting the DI container ( creating what you need with CIF#make) do the instantiations is a better idea, despite the depth.

I'm not sure I fully understand your issue but I hope this helps. Also here's a simplified diagram about the context hierarchy in this slideshow http://www.slideshare.net/smcela/eclipse-4-context-functions

Re: Trying to get E4 services [message #1016659 is a reply to message #1016655] Thu, 07 March 2013 04:41 Go to previous messageGo to next message
Thomas Schindl is currently offline Thomas Schindl
Messages: 5294
Registered: July 2009
Senior Member
There is not navigation from Parent to Child IIRC.


But I see problem and I thought about that often myself as well because
I wanted my POJO code free of any Framework stuff as well - e.g. to make
use of them in a Guice-DI or Spring-DI context.

a) define an interface

interface DiCreator {
public <O> O creatInstance(Class<O> clazz);
public DiCreator createChild();
public void setValue(String name, Object o);
public void setValue(Class<O> clazz, O o);
}

b) Contribute this as the context function using DS

=> You can use DI but your code does not depend on IEC

Tom

Am 07.03.13 10:27, schrieb Sopot Cela:
> @Tom, I think his issue is that he doesn't want to drag down the IEC
> which has to be supplied to CIF#make.
> If you don't want to extend this context hierarchy downards then I
> think, theoretically, you can access a top level context and traverse
> its children until you find a suitable context. But still I think that
> letting the DI container ( creating what you need with CIF#make) do the
> instantiations is a better idea, despite the depth.
>
> I'm not sure I fully understand your issue but I hope this helps. Also
> here's a simplified diagram about the context hierarchy in this
> slideshow http://www.slideshare.net/smcela/eclipse-4-context-functions
>
>
Re: Trying to get E4 services [message #1016749 is a reply to message #1016651] Thu, 07 March 2013 09:52 Go to previous messageGo to next message
Jo Jaquinta is currently offline Jo Jaquinta
Messages: 40
Registered: January 2013
Location: Boston
Member

Quote:
Best pratice is that *ALL* instances are created through CIF.make() why
can't you create the Dialog, .... also through the DI-Container. I don't
see a reason you can't do this.

Well, to do this, it would end up being something like this.
My part would have to create it's main Composite extended panel via make. That panel would have to create the launcher sub-panel via make. The launcher, catching the button click, would have to create the Dialog via make. Then the Dialog, when creating it's Composite extended panel, would have to create it via make(). THEN that panel could access the style object to add CSS styling.
I appreciate in the purest sense that this is the "correct" way to do things. But in a pragmatic sense, that's an awful lot of trouble to go through just to apply some CSS styling and use a service that is going to be, pretty much, global anyway. When you add in the fact that in most cases all of the non-model SWT level code is being ported over from a non-e4 environment, it's a rather large burden of work and changes necessary in order to make use of one part of e4.


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Jo Grant, Senior Software Engineer
Admin and Config Console Architect
OpenPages, IBM
Re: Trying to get E4 services [message #1016756 is a reply to message #1016749] Thu, 07 March 2013 10:20 Go to previous messageGo to next message
Thomas Schindl is currently offline Thomas Schindl
Messages: 5294
Registered: July 2009
Senior Member
You asked for the correct solution ;-)

Like I already outlined what you expect to be a singleton is from the
frameworks point of view not a singleton (I gave you the Vaadin/RAP
usecase already).

Please note that we are publishing the IWorkbench in 4.3 as an
OSGi-Service so you can get access to the instance query the OSGi-Registry.

You are free to creating singletons to shorten call paths if you think
they are the better solution but the framework can't and won't hopefully
provide it.

Tom

Am 07.03.13 15:52, schrieb Jo Jaquinta:
> Quote:
>> Best pratice is that *ALL* instances are created through CIF.make() why
>> can't you create the Dialog, .... also through the DI-Container. I don't
>> see a reason you can't do this.
>
> Well, to do this, it would end up being something like this.
> My part would have to create it's main Composite extended panel via
> make. That panel would have to create the launcher sub-panel via make.
> The launcher, catching the button click, would have to create the Dialog
> via make. Then the Dialog, when creating it's Composite extended panel,
> would have to create it via make(). THEN that panel could access the
> style object to add CSS styling.
> I appreciate in the purest sense that this is the "correct" way to do
> things. But in a pragmatic sense, that's an awful lot of trouble to go
> through just to apply some CSS styling and use a service that is going
> to be, pretty much, global anyway. When you add in the fact that in most
> cases all of the non-model SWT level code is being ported over from a
> non-e4 environment, it's a rather large burden of work and changes
> necessary in order to make use of one part of e4.
>
Re: Trying to get E4 services [message #1016757 is a reply to message #1016756] Thu, 07 March 2013 10:33 Go to previous message
Jo Jaquinta is currently offline Jo Jaquinta
Messages: 40
Registered: January 2013
Location: Boston
Member

I understand you have to balance taking a pure approach against things that will be a barrier to adoption.

Thomas Schindl wrote on Thu, 07 March 2013 10:20
Please note that we are publishing the IWorkbench in 4.3 as an
OSGi-Service so you can get access to the instance query the OSGi-Registry.

We're targeting 4.3 for our release, so this is fine. I'll keep my hack for now and move over to this when it is available.
In the meantime, I'll see about making sure all new code we write use make().

Thanks for your help!

Jo


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Jo Grant, Senior Software Engineer
Admin and Config Console Architect
OpenPages, IBM
Previous Topic:Difficulties with tutorial examples
Next Topic:Launching from PDE with -console
Goto Forum:
  


Current Time: Fri Aug 29 06:11:31 EDT 2014

Powered by FUDForum. Page generated in 0.02780 seconds