Improvements for OSGi support in Vaadin

Hi,

I’ve spent the last weeks trying to run Vaadin in an OSGi environment. The current support for OSGi seems to be broken or only working in very specific settings (https://vaadin.com/forum/#!/thread/16934575).
Therefore, I developed my own integration that is currently working with Vaadin 8.2.1(https://github.com/Sandared/vaadin8integration).
During the development of this integration I also had a look at the current OSGi integration regarding Themes/Widgetsets/Resources which could also be enhanced. A first draft of this enhancement could be seen here: https://github.com/Sandared/vaadin8integration/blob/master/de.modularco.vaadin.integration.impl/src/de/modularco/vaadin/integration/impl/OSGiResourceExtender.xtend

What are those enhancements good for?

  • No more need in core Vaadin to explicitly call VaadinResourceServiceImpl nor any dependencies to OSGi in the core Vaadin bundles. If you want Vaadin to be OSGi compatible all you will have to do is to add an additional bundle to your runtime.
  • UIs will be Declarative Services that can have their own references to other OSGi components/services. The lifecycle of UIs is managed so that all dependencies are resolved before init() is called.
  • New themes/widgetsets/resources can be made available by adding just one line to the manifest (currently a call to a static method of VaadinResourceServiceImpl is required and this only works if the bundles are started in the right order

Is this an enhancement that you would like to see in the framework? Or do you have any plans on your own regarding enhancing OSGi support in Vaadin that I’m not aware of?

If this is an enhancement you’d like to see I would prepare a pull request for this and rewrite my solution in Java (currently written in Xtend).
I’ve also created an issue in GitHub so that I can reference it if the enhancements are accepted. (https://github.com/vaadin/framework/issues/10616)

Kind regards,
Thomas

Hi Thomas,

Your solution helped me a lot to understand Vaadin OSGi for resources, themes and widgetset. So I decided to use it in a Liferay DXP (i.e… Equinox enviornment), everything worked ok but I had a problem: bunle initialization.

When I shit down LiferayDXP and start again a OSGi runtime does not contain HttpService! exception is thrown. This is because the HTTPService is not up. So I had to start de bundle manually and averything is ok again.

Any Idea what I´m doing wrong?

Thanks,

Hi Ricardo,

do you have more information on the exception that is thrown? Or any Log information that might help to understand your problem? Right now it sounds as if the http service is doing something wrong that somehow leads to an exception during
its initialization, which again would lead to it not being started properly.

Kind regards,
Thomas

Hi,

Here is the log information when I start Liferay DXP:

13:52:31,992 ERROR [Framework Event Dispatcher: Equinox Container: 701c952f-fe5c-0018-1f50-d9146102d4cb]
[lskit-osgi-vaadin-components:97]
FrameworkEvent ERROR
java.lang.IllegalStateException: OSGi runtime does not contain HttpService!
at com.legosoft.vaadin.widgetset.OSGiVaadinTracker.addingBundle(OSGiVaadinTracker.java:54)
at com.legosoft.vaadin.widgetset.OSGiVaadinTracker.addingBundle(OSGiVaadinTracker.java:1)
at org.osgi.util.tracker.BundleTracker$Tracked.customizerAdding(BundleTracker.java:469)
at org.osgi.util.tracker.BundleTracker$Tracked.customizerAdding(BundleTracker.java:1)
at org.osgi.util.tracker.AbstractTracked.trackAdding(AbstractTracked.java:256)
at org.osgi.util.tracker.AbstractTracked.track(AbstractTracked.java:229)
at org.osgi.util.tracker.BundleTracker$Tracked.bundleChanged(BundleTracker.java:444)
at org.eclipse.osgi.internal.framework.BundleContextImpl.dispatchEvent(BundleContextImpl.java:905)…

As I understand this is because the HttpService is not instanciated yet. This is part of my code for the Activator:

	@Override
public Bundle addingBundle(Bundle bundle, BundleEvent event) {			
	String resourcePath = bundle.getHeaders().get(header);
	
	if (resourcePath != null) {		
		VaadinResourceService service = null;	
		try {
			service = OsgiVaadinResources.getService();
		} catch (ResourceBundleInactiveException e) {
			e.printStackTrace();
			return bundle;
		}
		ServiceReference httpRef = context.getServiceReference(HttpService.class.getName());
	
		if (httpRef == null)
			throw new IllegalStateException("OSGi runtime does not contain HttpService!");
	    // ^ Here is where the exception is thrown.
		.....
		
		
		Ricardo

I think I got a solucion (I´m still testing it):

First: I stored the resources (widgetset, themes, images and JS libraries) defined in the MANIFEST file at the bundle activation time (NOT published the resources) following our code.
Second: I create a ServiceTracker for the HttpService class. When the services is added I publish the resources with the HttpService instance.

This solution works if I start and stop a bundle manually and also works is I shutdown and start Liferary DXP.

note: With this solution I don´t need the VAADIN path since it comes from the HttpsService so no Vaadin version dependency is needed.

Any comment is welcome.

Hi Ricardo,

sorry for the late response, but I see you got a working solution anyway :wink:

Meanwhile I always try to implement such things as Declarative Services, as they take away the OSGi complexity. So a possible solution I could imagine would be:

@Component
public class VaadinTracker{
	@Reference
	HttpService http;
	
	private VaadinResourceTracker resTracker;
	...
	
	@Activate
	private void activate(BundleContext context){
		resTracker = new VaadinResourceTracker(context, "OSGiVaadin-Resource", http);
		resTracker.open();
		...
	}
	
	@Deactivate
	private void deactivate(){
		resTracker.close();
		resTracker = null;
		...
	}
}

This way you don’t have to deal with the HttpService service yourself but let OSGi do the hard work.

BTW: If you too want Vaadin to support OSGi out of the box in the future (Vaadin 10) then you could add yourself to this issue https://github.com/vaadin/flow/issues/455 :wink:

Kind regards,
Thomas

Hi Thomas,

Your solution is simpler than declaring a ServiceTracker. Have yout test it?

Our experience of the @Reference annotation in Liferay DXP has not been always a good one. Specially when are not mandatory and many service need to be tracked List. Sometimes it nevers initialized the service (because bundle order initialization). This happened when we implemented a Vaadin component for a BPM (jBPM version 6.4) user tasks. But again, it is a simpler and cleaner solution than mine. Thanks for your help.
Of course that we are very interested using Vaadin 10 in an OSGi environment. For our customers this is the right path to follow. Thanks for the invitation.

Ricardo

Hi Ricardo,

I’m glad that I could help. I didn’t test specifically this piece of code, but I used this pattern more often recently, as it provides me with a simple solution to couple non-OSGi code to the lifecycle of OSGi components. You still have to take care of concurrency issues yourself, but those are not so difficult.

I’m not sure what SCR implementation Liferay DXP uses, but if it relies on Equinox then I think the newest version uses the Apache Felix SCR. I never had troubles with this one if I planned my component dependencies accordingly. Anyway, for this case it is just a static/mandatory reference to the HttpService, so this should not cause any trouble in Liferay DXP either.

Kind regards,
Thomas

Liferay DXP relies in Equinox.

Thanks for your comments