vaadin / framework

Vaadin 6, 7, 8 is a Java framework for modern Java web applications.
http://vaadin.com/
Other
1.78k stars 730 forks source link

OSGi DS services injection not working is Vaadin 8.1.0.beta2 OSGi portlet #9589

Closed alexweirig closed 7 years ago

alexweirig commented 7 years ago

Hello,

I'm currently struggeling with a problem in Vaadin 8.1.0.beta2 in regards to Liferay OSGi portlets.

I have this very basic portlet:

@Theme(ValoTheme.THEME_NAME)
@VaadinLiferayPortletConfiguration(name = "Vaadin.Tutorial.1", displayName = "Vaadin Tutorial App", category = "Technolink")
@Component(service = UI.class, immediate = true)
public class PersonEntryPortlet extends UI {
    private static final long serialVersionUID = 1L;

    private DummyService service;

    @Reference
    private void setService(DummyService service) {
        System.out.println("in setService ... UI = " + this);
        this.service = service;
    }

    @Override
    protected void init(VaadinRequest request) {
        System.out.println("in init ... UI = " + this);

        VerticalLayout layout = new VerticalLayout();

        Label label = new Label(service != null ? service.getMessage() : "Hello from Vaadin");
        layout.addComponents(label);
        setContent(layout);
    }

}

When I execute the portlet, my service reference is always null because I see the following output: in setService ... UI = lu.tlk.person_entry.portlet.PersonEntryPortlet@329f306c in init ... UI = lu.tlk.person_entry.portlet.PersonEntryPortlet@1284b29f

It thus looks that between the moment OSGi injects my service reference and the moment the portlet's init method is execute a new instance of the class has been created. This of course kills the service reference.

This makes it hard to use OSGi portlets in Liferay with OSGi services. I don't think it is a good idea to declare all service references as static.

This seems to happen in both beta1 and beta2.

The service class (inside the same project as the portlet) is:

@Component(immediate = true, service = DummyService.class)
public class DummyService {

    public String getMessage() {
        return "Hello from Service";
    }
}

I have deployed the following bundles to my Liferay runtime:

vaadin-client-compiled-8.1.0.beta1.jar
vaadin-liferay-integration-8.1.0.beta1.jar
vaadin-server-8.1.0.beta1.jar
vaadin-shared-8.1.0.beta1.jar
vaadin-themes-8.1.0.beta1.jar
vaadin-push-8.1.0.beta1.jar

atmosphere-runtime-2.4.11.vaadin1.jar
gentyref-1.2.0.vaadin1.jar
jsoup-1.8.3.jar
vaadin-slf4j-jdk14-1.6.1.jar
validation-api-1.0.0.GA.jar

All are "active" in OSGi.

alexweirig commented 7 years ago

Hello,

did you have a chance to look at this issue?

Any ideas how one can work around this problem?

Many thanks in advance,

Alex

rlhLegoSoft commented 7 years ago

I have the same problem, so it´s impossible to use Liferay 7 without @Reference. Any work to solve this problem? I´m working with Liferay people to do any Liferay work around and not use @Reference. I let you know but I believe it is a Vaadin problem since for Vaadin 7.7.6 compatibility pack, it works ok.

alexweirig commented 7 years ago

@rlhLegoSoft good to know I'm not the only one facing this problem ...

Mirjan from Vaadin has provided me a workaround ...

Bundle bundle = FrameworkUtil.getBundle(DemoUI.class);
        BundleContext context = bundle.getBundleContext();
        ServiceReference<DashboardService> reference = context.getServiceReference(DashboardService.class);
        if (reference != null) {
            return context.getService(reference);
        }

Even though this is a valid solution to get things working I wouldn't want to have to use this code in production compared to a simple @Reference.

You're right that this has been working with Sampa Sohlman's initial OSGi compatibility pack. My best guess is: Sampsa was relying on the PROTOTYPE feature of DS to get a new instance of the UI for each use while somehow in the current OSGi code, the Vaadin framework creates a new instance of the UI and this causes the @Reference to get lost.

rlhLegoSoft commented 7 years ago

Dear Alex: Thanks for your e-mail!!! It help me a lot, because we are starting a big Liferay project that will take us at least 1 year of development. We decide to go for Vaadin 8.1 because by the time we finish the development Vaadin 7.7.6 compatibility pack will be obsolete.

This was a stopper bug for us, so thanks again!

But we have a second bug, maybe you had it. We installed Vaadin 8.1.beta3 (and left some bundles with Vaadin 7.7.6 compatibility pack for a while). When we shut down and start Liferay 7 we receive this exception:

15:10:13,292 ERROR [fileinstall-/Users/rlh/LocalApplications/liferay-ce-portal-7.0-ga3/osgi/modules][com_vaadin_liferay_integration:97] [com.vaadin.osgi.liferay.VaadinPortletProvider(780)] The activate method has thrown an exception com.vaadin.osgi.resources.OsgiVaadinResources$ResourceBundleInactiveException: Vaadin Shared is not active! at com.vaadin.osgi.resources.OsgiVaadinResources.getService(OsgiVaadinResources.java:66) at com.vaadin.osgi.liferay.VaadinPortletProvider.activate(VaadinPortletProvider.java:49) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)….

The work around is when Liferay 7 finishes the starting process we just “stop” and “start” again the "Vaadin Liferay Integration" bundle and everything works ok. Do you have a similar problem? Or maybe is my Liferay environment?

Thanks,

Ricardo.

alexweirig commented 7 years ago

Dear Ricardo,

you're welcome ... I was just sharing what I learnt.

I not use Vaadin 7 anymore so I don't have this configuration. I think to remember that somehow Vaadin bundles didn't always start immediately (which might make perfect sense) so I didn't care and activated them manually.

One drawback of the workaround is however (if I'm not mistaken) that you lose the dynamic service injection of DS. I'm not sure yet how you could make the context lookup dynamic ... i.e. get informed when a new service is becoming available (except doing some polling)?

I still hope we figure out why @Reference is not working and how we can fix it.

Alex

alexweirig commented 7 years ago

Hi Ricardo,

I've updated my environment to 8.1.0 and I'm now also hitting the message for Vaadin Shared: com.vaadin.osgi.resources.OsgiVaadinResources$ResourceBundleInactiveException: Vaadin Shared is not active! at com.vaadin.osgi.resources.OsgiVaadinResources.getService(OsgiVaadinResources.java:66) at com.vaadin.osgi.liferay.VaadinPortletProvider.activate(VaadinPortletProvider.java:49) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.apache.felix.scr.impl.inject.BaseMethod.invokeMethod(BaseMethod.java:224) at org.apache.felix.scr.impl.inject.BaseMethod.access$500(BaseMethod.java:39) at org.apache.felix.scr.impl.inject.BaseMethod$Resolved.invoke(BaseMethod.java:617) at org.apache.felix.scr.impl.inject.BaseMethod.invoke(BaseMethod.java:501) at org.apache.felix.scr.impl.inject.ActivateMethod.invoke(ActivateMethod.java:302) at org.apache.felix.scr.impl.inject.ActivateMethod.invoke(ActivateMethod.java:294) at org.apache.felix.scr.impl.manager.SingleComponentManager.createImplementationObject(SingleComponentManager.java:297) at org.apache.felix.scr.impl.manager.SingleComponentManager.createComponent(SingleComponentManager.java:108) at org.apache.felix.scr.impl.manager.SingleComponentManager.getService(SingleComponentManager.java:906) at org.apache.felix.scr.impl.manager.SingleComponentManager.getServiceInternal(SingleComponentManager.java:879) at org.apache.felix.scr.impl.manager.AbstractComponentManager.activateInternal(AbstractComponentManager.java:748) at org.apache.felix.scr.impl.manager.AbstractComponentManager.enableInternal(AbstractComponentManager.java:674) at org.apache.felix.scr.impl.manager.AbstractComponentManager.enable(AbstractComponentManager.java:429) at org.apache.felix.scr.impl.manager.ConfigurableComponentHolder.enableComponents(ConfigurableComponentHolder.java:657) at org.apache.felix.scr.impl.BundleComponentActivator.initialEnable(BundleComponentActivator.java:341) at org.apache.felix.scr.impl.Activator.loadComponents(Activator.java:403) at org.apache.felix.scr.impl.Activator.access$200(Activator.java:54) at org.apache.felix.scr.impl.Activator$ScrExtension.start(Activator.java:278) at org.apache.felix.utils.extender.AbstractExtender.createExtension(AbstractExtender.java:259) at org.apache.felix.utils.extender.AbstractExtender.modifiedBundle(AbstractExtender.java:232) at org.osgi.util.tracker.BundleTracker$Tracked.customizerModified(BundleTracker.java:482) at org.osgi.util.tracker.BundleTracker$Tracked.customizerModified(BundleTracker.java:1) at org.osgi.util.tracker.AbstractTracked.track(AbstractTracked.java:232) at org.osgi.util.tracker.BundleTracker$Tracked.bundleChanged(BundleTracker.java:444) at org.eclipse.osgi.internal.framework.BundleContextImpl.dispatchEvent(BundleContextImpl.java:905) at org.eclipse.osgi.framework.eventmgr.EventManager.dispatchEvent(EventManager.java:230) at org.eclipse.osgi.framework.eventmgr.ListenerQueue.dispatchEventSynchronous(ListenerQueue.java:148) at org.eclipse.osgi.internal.framework.EquinoxEventPublisher.publishBundleEventPrivileged(EquinoxEventPublisher.java:165) at org.eclipse.osgi.internal.framework.EquinoxEventPublisher.publishBundleEvent(EquinoxEventPublisher.java:75) at org.eclipse.osgi.internal.framework.EquinoxEventPublisher.publishBundleEvent(EquinoxEventPublisher.java:67) at org.eclipse.osgi.internal.framework.EquinoxContainerAdaptor.publishModuleEvent(EquinoxContainerAdaptor.java:102) at org.eclipse.osgi.container.Module.publishEvent(Module.java:461) at org.eclipse.osgi.container.Module.start(Module.java:452) at org.eclipse.osgi.internal.framework.EquinoxBundle.start(EquinoxBundle.java:402) at org.apache.felix.fileinstall.internal.DirectoryWatcher.startBundle(DirectoryWatcher.java:1253) at org.apache.felix.fileinstall.internal.DirectoryWatcher.startBundles(DirectoryWatcher.java:1225) at org.apache.felix.fileinstall.internal.DirectoryWatcher.startAllBundles(DirectoryWatcher.java:1213) at org.apache.felix.fileinstall.internal.DirectoryWatcher.doProcess(DirectoryWatcher.java:507) at org.apache.felix.fileinstall.internal.DirectoryWatcher.process(DirectoryWatcher.java:361) at org.apache.felix.fileinstall.internal.DirectoryWatcher.run(DirectoryWatcher.java:312)

So it's not related to your environment.

Alex

mmerruko commented 7 years ago

Hi,

I've made a fix in my fork of the framework for this issue. There are a couple of things I need to check before I make a PR for the framework team, but this should help you if you want to use it in the meantime.

You can checkout the branch https://github.com/mmerruko/framework/tree/Issue_9589 and build the Vaadin Liferay Integration bundle and install it in your liferay OSGi container.

If the UI is declared as a DS component with prototype scope then the a new service instance will be created so the methods annotated with @Reference should have their dependencies ready. If the scope is not prototype a warning is logged and it falls back to the current behavior of using the constructor.

mmerruko commented 7 years ago

In regards to the second issue I've run into it when using "update {bundleId}" from the shell. Something seems to go wrong with the bundle activator or the order of activation of the bundles. Restarting the whole liferay server seemed to fix it for me.

alexweirig commented 7 years ago

Hi Mirjan,

I deployed the jar file and it works ... I get the Portal service injected using the @Reference.

Thank you very much

Alex

alexweirig commented 7 years ago

@mmerruko,

I tested with a custom service and it works as expected.

Alex

rlhLegoSoft commented 7 years ago

Hi Mirjan, Thanks for your help, now @Reference injection is working as expected!!

Other point, sharing what I learnt : Maybe it is not a bug, but for sure it is an issue: it is impossible to use use BeanValidationBinder with OSGi since it looks for a JSR-303 javax.Validation implementation in the class path, in OSGi environment it does not work that way, so it sends an exception. I think you need to take an approach like this one: https://floriansblog.wordpress.com/2015/03/18/osgi-vaadin-and-apache-bean-validation-jsr303/

Any comment on this subject? Ricardo.

hesara commented 7 years ago

For bean validation, there is a separate issue #9389

rlhLegoSoft commented 7 years ago

Thanks, for your reply.

I use Florian approach and it is working.

Ricardo Legorreta

On Jul 27, 2017, at 3:34 AM, Henri Sara notifications@github.com wrote:

For bean validation, there is a separate issue #9389 https://github.com/vaadin/framework/issues/9389 — You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/vaadin/framework/issues/9589#issuecomment-318296578, or mute the thread https://github.com/notifications/unsubscribe-auth/AUARuoYDtQhKlCGKsbyD-HpVyaGmhh0jks5sSEuTgaJpZM4OGNMr.