Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OSGi: Removed static VaadinResourceService access in liferay-integration, osgi-integration #11335

Merged
merged 10 commits into from
Jun 27, 2019

Conversation

swimmesberger
Copy link
Contributor

@swimmesberger swimmesberger commented Nov 27, 2018

With this pull request I removed the static access to the OsgiVaadinResources class which prevents all kind of issues in an OSGi/liferay environment. I did this by making the VaadinResourceService a proper OSGi service which is accessed only in a dynamic way.
I tried to keep the change backward compatible by also moving the OsgiVaadinResources class to the dynamic model of accessing the VaadinResourceService internally. I made the OsgiVaadinResources class deprecated with the note that all users of this class should move to the dynamic model by referencing the VaadinResourceService via OSGi services.

This pull request is currently open for discussion and should be tested by the different stakeholders (I have no liferay instance to test the changes - only plain OSGi containers).

Correlates strongly with the change I have made in #11334 if this pull request gets merged the change in #11334 is obsolete because it changes the way the VaadinResourceTrackerComponent work internally.

Maybe @Maurice-Betzel, @ctliv, @geletejefazo18 or someone else who works with vaadin in an OSGi/liferay environment can give some input about this change.

Fixes #10220


This change is Reviewable

@swimmesberger swimmesberger changed the title OSGi: Removed static VaadinResourceService access in liferay-integration, osgi-integration WIP: OSGi: Removed static VaadinResourceService access in liferay-integration, osgi-integration Dec 6, 2018
…i-service-integration-fix

# Conflicts:
#	shared/src/main/java/com/vaadin/osgi/resources/impl/VaadinResourceTrackerComponent.java
@swimmesberger swimmesberger changed the title WIP: OSGi: Removed static VaadinResourceService access in liferay-integration, osgi-integration OSGi: Removed static VaadinResourceService access in liferay-integration, osgi-integration Dec 7, 2018
@swimmesberger
Copy link
Contributor Author

swimmesberger commented Dec 7, 2018

I have removed the usage of the old osgi "HttpService" and refactored the code to the the new osgi whiteboard pattern (introduced in OSGi R6 - which seems to be the minimum version for vaadin). With that in place the integration experience into an OSGi environment is much smoother.

For the Http Whiteboard implementation I have chosen to add a ServletContextHelper Component (see R6 spec 140.2*) for all vaadin resources. This makes registering resources much easier because the ServletContextHelper takes care of loading the resources from the correct classpath and prepending the vaadin-{version} path.
Every vaadin resource will be registered as a osgi http whiteboard resource (see R6 spec 140.6*) by the VaadinResourceTrackerComponent with the vaadin context (the custom ServletContextHelper (VaadinServletContextFactory)).

In the last commit I have also updated the bnd version from 3.3.0 to 3.5.0, this update is optional but the capabilities generated by 3.5.0 are more concise than 3.3.0.

As before I have tried to no break any backward compatibility.

I have also made some testing in our OSGi application and with this version we had by far the best integration experience.

@sammso
Copy link
Contributor

sammso commented Dec 9, 2018

Hi @swimmesberger , I'm looking this from Liferay perspective.

@sammso
Copy link
Contributor

sammso commented Dec 9, 2018

Hi @swimmesberger , @mstahv and @TatuLund

The last two commits made this much better approach. When I made my first experiments with Liferay OSGi portlets I was looking a similar Declarative Services based approach for resources.

I will still look this code level deeper as I was more consentrating to see if this works with Liferay 7.0/DXP and 7.1 GA2.

I did test this with simple application which can be generetated with Maven archetype.

com.vaadin:vaadin-archetype-liferay-portlet (This archetype generates a Liferay portlet plugin project that relies on the Vaadin bundles being installed on the portal server.

The this is built with maven and result is copied to <liferay home>/osgi/modules folder. The Vaadin framework is installed by copying following files also to same folder:

gentyref-1.2.0.vaadin1.jar
jsoup-1.11.2.jar
vaadin-client-compiled-8.7-SNAPSHOT.jar
vaadin-liferay-integration-8.7-SNAPSHOT.jar
vaadin-osgi-integration-8.7-SNAPSHOT.jar
vaadin-server-8.7-SNAPSHOT.jar
vaadin-shared-8.7-SNAPSHOT.jar
vaadin-themes-8.7-SNAPSHOT.jar

This application works with build from this pull request (JDK8) and with Liferay 7.0 / DXP 7.0 fixpack50, but it does not work with 7.1 GA2. There is another issue on #11156 which is blocking that, but it is easy to fix and after I did apply the fix then it was working also with 7.1. Also note here that latest version 8.6.2 with 7.1, but this version did not have that either.

Summary, I will still look little bit the code and implementation at another day until I give my final pass :) . Thanks @swimmesberger this really good improvement.

@sammso
Copy link
Contributor

sammso commented Dec 9, 2018

Liferay 7.1 simple fix is here #11360

@swimmesberger , your version do not have the following issue with Liferay 7.1 with above fix included.

2018-12-09 22:42:19.968 ERROR [Start Level: Equinox Container: a75544cf-12c3-4aa3-979b-fcdd7bdf5058][com_vaadin_liferay_integration:97] bundle com.vaadin.liferay.integration:8.7.0.201812092232 (947)[com.vaadin.osgi.liferay.VaadinPortletProvider(3887)] : 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:53)
        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:497)
        at org.apache.felix.scr.impl.inject.methods.BaseMethod.invokeMethod(BaseMethod.java:228)
        at org.apache.felix.scr.impl.inject.methods.BaseMethod.access$500(BaseMethod.java:41)
        at org.apache.felix.scr.impl.inject.methods.BaseMethod$Resolved.invoke(BaseMethod.java:664)
        at org.apache.felix.scr.impl.inject.methods.BaseMethod.invoke(BaseMethod.java:510)
        at org.apache.felix.scr.impl.inject.methods.ActivateMethod.invoke(ActivateMethod.java:317)
        at org.apache.felix.scr.impl.inject.methods.ActivateMethod.invoke(ActivateMethod.java:307)
        at org.apache.felix.scr.impl.manager.SingleComponentManager.createImplementationObject(SingleComponentManager.java:341)
        at org.apache.felix.scr.impl.manager.SingleComponentManager.createComponent(SingleComponentManager.java:114)
        at org.apache.felix.scr.impl.manager.SingleComponentManager.getService(SingleComponentManager.java:983)
        at org.apache.felix.scr.impl.manager.SingleComponentManager.getServiceInternal(SingleComponentManager.java:956)
        at org.apache.felix.scr.impl.manager.AbstractComponentManager.activateInternal(AbstractComponentManager.java:765)
        at org.apache.felix.scr.impl.manager.AbstractComponentManager.enableInternal(AbstractComponentManager.java:666)
        at org.apache.felix.scr.impl.manager.AbstractComponentManager.enable(AbstractComponentManager.java:432)
        at org.apache.felix.scr.impl.manager.ConfigurableComponentHolder.enableComponents(ConfigurableComponentHolder.java:665)
        at org.apache.felix.scr.impl.BundleComponentActivator.initialEnable(BundleComponentActivator.java:339)
        at org.apache.felix.scr.impl.Activator.loadComponents(Activator.java:381)
        at org.apache.felix.scr.impl.Activator.access$200(Activator.java:49)
        at org.apache.felix.scr.impl.Activator$ScrExtension.start(Activator.java:263)
        at org.apache.felix.scr.impl.AbstractExtender.createExtension(AbstractExtender.java:196)
        at org.apache.felix.scr.impl.AbstractExtender.modifiedBundle(AbstractExtender.java:169)
        at org.apache.felix.scr.impl.AbstractExtender.modifiedBundle(AbstractExtender.java:49)
        at org.osgi.util.tracker.BundleTracker$Tracked.customizerModified(BundleTracker.java:488)
        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:450)
        at org.eclipse.osgi.internal.framework.BundleContextImpl.dispatchEvent(BundleContextImpl.java:908)
        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:230)
        at org.eclipse.osgi.internal.framework.EquinoxEventPublisher.publishBundleEvent(EquinoxEventPublisher.java:137)
        at org.eclipse.osgi.internal.framework.EquinoxEventPublisher.publishBundleEvent(EquinoxEventPublisher.java:129)
        at org.eclipse.osgi.internal.framework.EquinoxContainerAdaptor.publishModuleEvent(EquinoxContainerAdaptor.java:191)
        at org.eclipse.osgi.container.Module.publishEvent(Module.java:476)
        at org.eclipse.osgi.container.Module.start(Module.java:467)
        at org.eclipse.osgi.container.ModuleContainer$ContainerStartLevel.incStartLevel(ModuleContainer.java:1682)
        at org.eclipse.osgi.container.ModuleContainer$ContainerStartLevel.incStartLevel(ModuleContainer.java:1662)
        at org.eclipse.osgi.container.ModuleContainer$ContainerStartLevel.doContainerStartLevel(ModuleContainer.java:1624)
        at org.eclipse.osgi.container.ModuleContainer$ContainerStartLevel.dispatchEvent(ModuleContainer.java:1555)
        at org.eclipse.osgi.container.ModuleContainer$ContainerStartLevel.dispatchEvent(ModuleContainer.java:1)
        at org.eclipse.osgi.framework.eventmgr.EventManager.dispatchEvent(EventManager.java:230)
        at org.eclipse.osgi.framework.eventmgr.EventManager$EventThread.run(EventManager.java:340)
2018-12-09 22:42:20.617 INFO  [main][ModuleFrameworkImpl:1716] Started dynamic bundles
2018-12-09 22:42:20.619 INFO  [main][ModuleFrameworkImpl:413] Navigate to Control Panel > Configuration > Gogo Shell and enter "lb" to see all bundles

It is not possible to add example portlet on the page due this.

Workaround with gogo shell as this seems to be issue of the starting order of the bundles.

g! lb -s | grep vaadin
  944|Active     |   10|com.sohlman.vaadintest.com.sohlman.vaadintest.test (1.0.0.201812091251)|1.0.0.201812091251
  945|Active     |   10|com.vaadin.external.gentyref (1.2.0.vaadin1)|1.2.0.vaadin1
  947|Active     |   10|com.vaadin.client-compiled (8.6.2)|8.6.2
  948|Active     |   10|com.vaadin.liferay.integration (8.6.2)|8.6.2
  949|Active     |   10|com.vaadin.osgi.integration (8.6.2)|8.6.2
  950|Active     |   10|com.vaadin.server (8.6.2)|8.6.2
  951|Active     |   10|com.vaadin.shared (8.6.2)|8.6.2
  952|Active     |   10|com.vaadin.themes (8.6.2)|8.6.2
true
g! stop 944
g! stop 948
g! start 948
g! start 944

@swimmesberger
Copy link
Contributor Author

swimmesberger commented Dec 13, 2018

One thing I have noticed is that (the same behavior applies to the currently released vaadin version) there is the VaadinServlet (https://github.com/vaadin/framework/blob/master/server/src/main/java/com/vaadin/server/VaadinServlet.java) which contains code to handle static resources but in the OSGi world there is no monolithic VaadinServlet. The VaadinServlet only serves requests of the vaadin application itself. All the static resources are served via the http whiteboard pattern (which serves this resources via ResourceServlets) so all the code regarding serving static resources (on the fly compilation, caching header etc...) are not triggered in the OSGi world.

@mkampmey
Copy link

With the changes in this pull request, vaadin portlets are correctly working with Liferay 7.2.

Copy link
Contributor

@ZheSun88 ZheSun88 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed 1 of 5 files at r1, 1 of 2 files at r2, 4 of 6 files at r5, 1 of 1 files at r6, 1 of 1 files at r7, 1 of 1 files at r8.
Reviewable status: :shipit: complete! all files reviewed, all discussions resolved

@ZheSun88 ZheSun88 merged commit 583920f into vaadin:master Jun 27, 2019
@ZheSun88 ZheSun88 added this to the 8.9.0 milestone Jun 27, 2019
@TatuLund
Copy link
Contributor

This PR will be included in 8.9.0.alpha1 release. I would like to urge everybody using OSGi to verify that there is no regressions, and if there are some adverse effects to inform us.

@alexweirig
Copy link

Hi,
do you know if this will allow Vaadin UIs to be published as OSGi services in order to be able to use OSGi DS inside a UI? As far as I remember there was a restriction on VaadinServletRegistration and it required an OsgiUiProvider to work.

@mmerruko published a fix a long time ago and I've been using that fix ever since for my applications and it's working great.

Would be cool if this would finally make it into a release. Currently I'm building my own Vaadin OSGi Integration with every Vaadin release I need to use.

@swimmesberger
Copy link
Contributor Author

swimmesberger commented Jul 1, 2019

In our application we still use the workaround via a UIProvider to use OSGi DS. This pull request allows to properly provide a VaadinServlet as a OSGi Service. For directly providing a (Vaadin) UI as a OSGi DS component (without the UIProvider workaround) we would need a additional pull request that handles this case properly.

The workaround is very simple therefore it's not that big of an issue and also does not require a custom build.

Something along the lines:

WebappServlet.java

@Component(service = Servlet.class, property = { 
    HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN + "=/webapp/*"
        })
public class WebappServlet extends VaadinServlet {
  private ServiceObjects<MyWebappUI> uiFactory;

  @Reference
  public void bindUIFactory(ServiceReference<UI> uiReference) {
      BundleContext context = uiReference.getBundle().getBundleContext();
      this.uiFactory= context.getServiceObjects(uiReference);
  }

  public MyWebappUI createUI() {
      return this.uiFactory.getService();
  }

  @Override
  protected DeploymentConfiguration createDeploymentConfiguration(Properties initParameters) {
    initParameters.setProperty(VaadinServlet.SERVLET_PARAMETER_UI_PROVIDER, MainUIProvider.class.getName());
    return super.createDeploymentConfiguration(initParameters);
  }
}

MainUIProvider.java

public class MainUIProvider extends UIProvider {
  @Override
  public Class<? extends UI> getUIClass(UIClassSelectionEvent event) {
    return MyWebappUI.class;
  }

  @Override
  public UI createInstance(UICreateEvent event) {
    final VaadinServletService servletService = (VaadinServletService) event.getService();
    final WebappServlet webappServlet = (WebappServlet) servletService.getServlet();
    return webappServlet.createUI();
  }
}

MyWebappUI.java

@Component(scope = ServiceScope.PROTOTYPE)
public class MyWebappUI extends UI {
...
}

@alexweirig
Copy link

Hi @swimmesberger

thanks for the update. I'll have a look at the code you provide for the workaround.

Regards

@swimmesberger
Copy link
Contributor Author

@alexweirig note that this was just a "quick and dirty" example I would recommend using ServiceObjects/Prototype Scope instead of component factory for a more modern OSGi based approach. (see the edit of the other comment)

@mkampmey
Copy link

mkampmey commented Jul 1, 2019

@alexweirig Why don't you use the vaadin-liferay-integration module and deploy it to your osgi environment? It has a ui provider and is part of the official vaadin release. No custom code is required anymore.

@alexweirig
Copy link

Hi @mkampmey
I'm actually not talking about Liferay, but about OSGi in a Karaf container. Do you know if that adds support for UI being deployed as OSGi Declarative Services?

@mkampmey
Copy link

mkampmey commented Jul 2, 2019

@alexweirig Well, the liferay-integration module does not have dependencies to liferay APIs, but to the portlet-api and servlet-api that you possibly do not have. It is possible to deploy UIs as declarative services, but I think it won't work in a karaf container.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Vaadin 8.1.5 on OSGi, Shared not active after restart
6 participants