Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » e(fx)clipse » Osgi service activated in the JavaFX Application Thread?
Osgi service activated in the JavaFX Application Thread? [message #1771730] Wed, 30 August 2017 00:32 Go to next message
Marcelo Ruiz is currently offline Marcelo RuizFriend
Messages: 44
Registered: April 2017
Member
Hi everyone,

I notice a strange (at least for me) behavior while playing with osgi services in my application.

I have a bundle defining a service:

public interface MyService {
  public void doSomething();
}


and a different bundle with implementation:

@Component
public class MyServiceImpl {

  @Activate
  public void activate() {
    System.err.println("activate() called in " + Thread.currentThread());
  }

  @Deactivate
  public void deactivate() {
    System.err.println("deactivate() called in " + Thread.currentThread());
  }

  public void doSomething() {
    //doing something here
  }
}


and I was curious and also added an activator in the same bundle:

public class Activator implements BundleActivator {

  public void start(BundleContext bundleContext) {
    System.err.println("start() called in " + Thread.currentThread());
  }

  public void stop(BundleContext bundleContext) {
    System.err.println("stop() called in " + Thread.currentThread());
  }
  
}


Then I have a different bundle with a controller that uses the service:

public class MyController {

  @Inject
  @Service
  private MyService service;

  @PostConstruct
  public void postConstruct() {
    service.doSomething();
  }
}


When the controller gets instantiated I receive the following output:

start() called in Thread[JavaFX Application Thread,5,main]
activate() called in Thread[JavaFX Application Thread,5,main]
deactivate() called in Thread[Framework stop,5,main]
stop() called in Thread[Framework stop,5,main]


It got my attention that the service and the activator are called by 2 different threads during their lifecycle events.

Also, assuming this service will start and access a remote database, how can I configure things to avoid the database being accessed by the JavaFX Application Thread?

I understand that after the service are created, I could access them using ThreadSynchronize but that doesn't help the creation problem. The only way I thought of avoiding that is by using an ExecutorService in the service implementation class and forcing everything to run there. It seems overkill... Maybe there is a simpler way (via configuration)?

I would appreciate any thoughts!

Thanks!

[Updated on: Wed, 30 August 2017 17:13]

Report message to a moderator

Re: Osgi service activated in the JavaFX Application Thread? [message #1771739 is a reply to message #1771730] Wed, 30 August 2017 05:04 Go to previous messageGo to next message
Dirk Fauth is currently offline Dirk FauthFriend
Messages: 2539
Registered: July 2012
Senior Member
OSGi DS services are managed by the Service Component Runtime. Those services are managed in the SCR thread, which is in fact a benefit over using Activator.

Your problem might be MyController because you are mixing two DI mechanisms here. @Component is OSGi DS, so the service instance should be managed by the SCR. But you are also using @Inject and @PostConstruct, and these annotations are used by e4 DI. That mixture is never a good idea. If MyController is a e4 managed class remove @Component, if it is intended as OSGi service, replace @Inject with @Reference and @PostConstruct with @Activate.
Re: Osgi service activated in the JavaFX Application Thread? [message #1771796 is a reply to message #1771739] Wed, 30 August 2017 14:59 Go to previous messageGo to next message
Marcelo Ruiz is currently offline Marcelo RuizFriend
Messages: 44
Registered: April 2017
Member
@Dirk
Thanks for taking the time to write back.
I was expecting the services being managed by the Service Component Runtime, that's why I was surprised to see the JavaFX Application Thread involved.
I have a doubt, though. If the two mechanisms are not to be mixed, how an eclipse RCP application can access and use OSGI services?
I thought the benefit of doing things this way was to have a layer of the application not dependent on Eclipse, making it easier to move that layer to a different OSGI container if needed. Within that layer, I was going to use the OSGI annotations for services depending on other services.
Also, according to https://wiki.eclipse.org/Efxclipse/Runtime/Recipes#Injection_of_OSGi-Services it seems that @Inject and @Service are the recommended way to inject OSGI services into an RCP application.
Still confused... :S
Re: Osgi service activated in the JavaFX Application Thread? [message #1771805 is a reply to message #1771796] Wed, 30 August 2017 16:38 Go to previous messageGo to next message
Dirk Fauth is currently offline Dirk FauthFriend
Messages: 2539
Registered: July 2012
Senior Member
Yes you use @Inject and @Service to inject OSGi services in e4 managed resources. But you should not use them in @Component annotated OSGi services. You should clearly separate these layers.
Re: Osgi service activated in the JavaFX Application Thread? [message #1771807 is a reply to message #1771805] Wed, 30 August 2017 17:16 Go to previous messageGo to next message
Marcelo Ruiz is currently offline Marcelo RuizFriend
Messages: 44
Registered: April 2017
Member
@Dirk
Thanks again for your answer... I realized I made a mistake when simplifying my example for this post (code is much larger). My controller is not annotated with @Component in the real code (but it does use the @PostConstruct annotation).
I edited the code in my first post to reflect the changes. Sorry for the confusion. Unfortunately the problem remains...
Re: Osgi service activated in the JavaFX Application Thread? [message #1771808 is a reply to message #1771807] Wed, 30 August 2017 17:27 Go to previous messageGo to next message
Marcelo Ruiz is currently offline Marcelo RuizFriend
Messages: 44
Registered: April 2017
Member
I was wondering if I should force the service to start playing with the project's Start Levels... but I thought one the points of working with an Eclipse RCP application is that it takes care of instantiating the services you need...

[edit] Scratch this... it doesn't seem to work...

[Updated on: Wed, 30 August 2017 17:31]

Report message to a moderator

Re: Osgi service activated in the JavaFX Application Thread? [message #1771836 is a reply to message #1771808] Thu, 31 August 2017 08:24 Go to previous messageGo to next message
Thomas Schindl is currently offline Thomas SchindlFriend
Messages: 6365
Registered: July 2009
Senior Member
The things you show are absolutely expected. Lazy bundle is activated when the first class is loaded and the activation is a synchronous process (hence you see the JavaFX-Thread in the activator). For services I think Dirk's statement is not 100% correct because the SCR-Thread is only responsible to manage the meta-data and resolving of references. OSGi-Services are created in lazy fashion so once more the caller thread is the thread the service is instantiated and created (not sure although if the spec enforces that).

Bottom-line: You should never do long running operation on @Activate (eg connecting to a database) or your BundleActivator#start because you block at least the frameworks initialization/booting and in the worst case your application code (eg. by blocking the JavaFX UI-Thread). Too proof all this I pushed a test repo: https://github.com/BestSolution-at/osgi-activation-debug

	@Override
	public Object start(IApplicationContext context) throws Exception {
		CountDownLatch l = new CountDownLatch(3);
				
		Thread t = new Thread("Activate A") {
			@Override
			public void run() {
				loadService(ServiceA.class);
				l.countDown();
			}
		};
		t.start();
		
		t = new Thread("Activate B") {
			@Override
			public void run() {
				loadService(ServiceB.class);
				l.countDown();
			}
		};
		t.start();
		
		t = new Thread("Activate C") {
			@Override
			public void run() {
				try {
					Class.forName("test.activation.lazyc.MyAPI");
					l.countDown();
				} catch (ClassNotFoundException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		};
		t.start();
		
		l.await();
		
		return IApplication.EXIT_OK;
	}


who yields the following output:
LazCActivator start: Thread[Activate C,5,main]
LazyBActivator start: Thread[Activate B,5,main]
ServiceBImpl instance: Thread[Activate B,5,main]
ServiceBImpl activated: Thread[Activate B,5,main]
test.activation.lazyb.ServiceBImpl@929617f
LazyAActivator start: Thread[Activate A,5,main]
ServiceAImpl instance: Thread[Activate A,5,main]
ServiceAImpl activated: Thread[Activate A,5,main]
test.activation.lazya.ServiceAImpl@6cfb06fc
Re: Osgi service activated in the JavaFX Application Thread? [message #1771842 is a reply to message #1771836] Thu, 31 August 2017 09:22 Go to previous messageGo to next message
Dirk Fauth is currently offline Dirk FauthFriend
Messages: 2539
Registered: July 2012
Senior Member
Quote:
For services I think Dirk's statement is not 100% correct because the SCR-Thread is only responsible to manage the meta-data and resolving of references. OSGi-Services are created in lazy fashion so once more the caller thread is the thread the service is instantiated and created


Seems Tom is correct. I checked with some of my examples, and yes the service instance is created within the thread where the instance is requested. If you for example register an EventHandler via DS, the EventHandler instance is created by the EventHandler thread.

The spec actually says nothing about the SCR thread. At least I haven't found anything.

So to answer the initial question, if you want to ensure that a db connection is established or db started at a certain point of time without blocking anything (BundleActivator will block the application startup, delayed components will block the UI once the service is requested the first time) you need to take care of the threading yourself.

To start at a specific point of time you could implement an EventHandler and send an event once your pre-requisites are met. Or if you do not have such pre-requisites, use an immediate component to start the db connection as soon as the bundle is loaded in @Activate. But in any case you should do this in a background thread to avoid blocking the rest of your application.
Re: Osgi service activated in the JavaFX Application Thread? [message #1771884 is a reply to message #1771842] Thu, 31 August 2017 15:46 Go to previous message
Marcelo Ruiz is currently offline Marcelo RuizFriend
Messages: 44
Registered: April 2017
Member
Thanks both Tom and Dirk for the explanation!
Previous Topic:Isn't it time to create a reference e(fx)clipse project from scratch?
Next Topic:e(fx)clipse 3.0.0 released
Goto Forum:
  


Current Time: Fri Dec 15 14:18:43 GMT 2017

Powered by FUDForum. Page generated in 0.01530 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software