From 08ff3b8fdbc7f9b40000cd266449ec08c6e9e366 Mon Sep 17 00:00:00 2001 From: Mirjan Merruko Date: Tue, 29 Aug 2017 12:16:14 +0300 Subject: [PATCH] Enable Declarative Services in OSGi portlet UI (#9879) If the UI scope is not prototype, show a warning that declarative services are not available in the UI. Fixes #9589 --- documentation/portal/portal-osgi.asciidoc | 16 ++++++-- .../vaadin/osgi/liferay/OsgiUIProvider.java | 38 ++++++++++++++++++- .../PortletUIServiceTrackerCustomizer.java | 10 ++++- .../osgi/liferay/VaadinPortletProvider.java | 20 ++++++++-- 4 files changed, 75 insertions(+), 9 deletions(-) diff --git a/documentation/portal/portal-osgi.asciidoc b/documentation/portal/portal-osgi.asciidoc index 0f31698f7e..3381989d56 100644 --- a/documentation/portal/portal-osgi.asciidoc +++ b/documentation/portal/portal-osgi.asciidoc @@ -8,7 +8,7 @@ layout: page = OSGi Portlets on Liferay 7 Lifeary 7 supports modular portlet development using OSGi, and enables e.g. -using multiple different Vaadin versions in different portlets on a page. +using multiple different Vaadin versions in different portlets on a page. For general OSGi considerations with Vaadin Framework such as packaging and bundle manifests, and how to publish static resources such as themes and @@ -31,7 +31,7 @@ and configure it to use the correct static resources. ---- @Theme(MyTheme.THEME_NAME) @VaadinLiferayPortletConfiguration(name = "Vaadin.Tutorial.1", displayName = "Vaadin Tutorial App") -@Component(service = UI.class) +@Component(service = UI.class, scope = ServiceScope.PROTOTYPE) public class MyUI extends UI { ... } @@ -43,6 +43,15 @@ property files that plain JSR-362 portlets require. Alternatively, the property [literal]#com.vaadin.osgi.liferay.portlet-ui=true# can be used when publishing a UI as an OSGi service to publish the UI as a portlet. +The scope of the service should be set to [literal]#ServiceScope.PROTOTYPE#, as new instances +of the UI will be needed. When this scope set, declarative services annotations can +be used to get references to other services within a UI instance. + +This is not an absolute requirement if you are not using other declarative services +annotations in your UI besides the [interfacename]#@Component#. If the scope is not +set to prototype a warning will be logged and the constructor of the UI will be used +when new instances are needed. + [source, java] ---- @Theme(MyTheme.THEME_NAME) @@ -51,7 +60,8 @@ can be used when publishing a UI as an OSGi service to publish the UI as a portl "javax.portlet.name=my.vaadin.app.app.1.0.0", "javax.portlet.display-name=Tutorial Portlet", "javax.portlet.security-role-ref=power-user,user", - "com.vaadin.osgi.liferay.portlet-ui=true"}) + "com.vaadin.osgi.liferay.portlet-ui=true"}, + scope = ServiceScope.PROTOTYPE) public class MyUI extends UI { ... } diff --git a/liferay-integration/src/main/java/com/vaadin/osgi/liferay/OsgiUIProvider.java b/liferay-integration/src/main/java/com/vaadin/osgi/liferay/OsgiUIProvider.java index 072dcbdc02..bdf50aa0d1 100644 --- a/liferay-integration/src/main/java/com/vaadin/osgi/liferay/OsgiUIProvider.java +++ b/liferay-integration/src/main/java/com/vaadin/osgi/liferay/OsgiUIProvider.java @@ -15,9 +15,15 @@ */ package com.vaadin.osgi.liferay; +import java.util.Optional; + +import org.osgi.framework.Constants; import org.osgi.framework.ServiceObjects; +import org.osgi.framework.ServiceReference; +import org.osgi.service.log.LogService; import com.vaadin.server.UIClassSelectionEvent; +import com.vaadin.server.UICreateEvent; import com.vaadin.server.UIProvider; import com.vaadin.ui.UI; @@ -34,12 +40,26 @@ import com.vaadin.ui.UI; @SuppressWarnings("serial") public class OsgiUIProvider extends UIProvider { private Class uiClass; + private ServiceObjects serviceObjects; + private boolean prototype; + private Optional logService; @SuppressWarnings("unchecked") - public OsgiUIProvider(ServiceObjects serviceObjects) { + public OsgiUIProvider(ServiceObjects serviceObjects, + Optional logService) { super(); + this.serviceObjects = serviceObjects; + this.logService = logService; + UI ui = serviceObjects.getService(); + + ServiceReference reference = serviceObjects.getServiceReference(); + Object property = reference.getProperty(Constants.SERVICE_SCOPE); + + prototype = Constants.SCOPE_PROTOTYPE.equals(property); + uiClass = (Class) ui.getClass(); + serviceObjects.ungetService(ui); } @@ -48,6 +68,22 @@ public class OsgiUIProvider extends UIProvider { return uiClass; } + @Override + public UI createInstance(UICreateEvent event) { + if (prototype) { + UI ui = serviceObjects.getService(); + ui.addDetachListener(e -> { + serviceObjects.ungetService(ui); + }); + return ui; + } + logService.ifPresent(log -> { + log.log(LogService.LOG_WARNING, + "UI services should have a prototype scope! Creating UI instance using the default constructor!"); + }); + return super.createInstance(event); + } + public String getDefaultPortletName() { return uiClass.getName(); } diff --git a/liferay-integration/src/main/java/com/vaadin/osgi/liferay/PortletUIServiceTrackerCustomizer.java b/liferay-integration/src/main/java/com/vaadin/osgi/liferay/PortletUIServiceTrackerCustomizer.java index 077730d2a8..607d5e33a0 100644 --- a/liferay-integration/src/main/java/com/vaadin/osgi/liferay/PortletUIServiceTrackerCustomizer.java +++ b/liferay-integration/src/main/java/com/vaadin/osgi/liferay/PortletUIServiceTrackerCustomizer.java @@ -19,6 +19,7 @@ import java.util.Dictionary; import java.util.HashMap; import java.util.Hashtable; import java.util.Map; +import java.util.Optional; import javax.portlet.Portlet; @@ -27,6 +28,7 @@ import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceObjects; import org.osgi.framework.ServiceReference; import org.osgi.framework.ServiceRegistration; +import org.osgi.service.log.LogService; import org.osgi.util.tracker.ServiceTrackerCustomizer; import com.vaadin.osgi.resources.VaadinResourceService; @@ -60,9 +62,12 @@ class PortletUIServiceTrackerCustomizer private Map, ServiceRegistration> portletRegistrations = new HashMap, ServiceRegistration>(); private VaadinResourceService service; + private Optional logService; - PortletUIServiceTrackerCustomizer(VaadinResourceService service) { + PortletUIServiceTrackerCustomizer(VaadinResourceService service, + LogService logService) { this.service = service; + this.logService = Optional.ofNullable(logService); } @Override @@ -102,7 +107,8 @@ class PortletUIServiceTrackerCustomizer ServiceObjects serviceObjects = bundleContext .getServiceObjects(reference); - OsgiUIProvider uiProvider = new OsgiUIProvider(serviceObjects); + OsgiUIProvider uiProvider = new OsgiUIProvider(serviceObjects, + logService); Dictionary properties = null; if (configuration != null) { diff --git a/liferay-integration/src/main/java/com/vaadin/osgi/liferay/VaadinPortletProvider.java b/liferay-integration/src/main/java/com/vaadin/osgi/liferay/VaadinPortletProvider.java index 78d0bff383..b95f0b591e 100644 --- a/liferay-integration/src/main/java/com/vaadin/osgi/liferay/VaadinPortletProvider.java +++ b/liferay-integration/src/main/java/com/vaadin/osgi/liferay/VaadinPortletProvider.java @@ -15,12 +15,17 @@ */ package com.vaadin.osgi.liferay; +import java.util.Optional; + import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceObjects; import org.osgi.service.component.ComponentContext; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.log.LogService; import org.osgi.util.tracker.ServiceTracker; import com.vaadin.osgi.resources.OsgiVaadinResources; @@ -37,11 +42,12 @@ import com.vaadin.ui.UI; * * @since 8.1 */ -@Component(immediate = true) +@Component public class VaadinPortletProvider { private ServiceTracker> serviceTracker; private PortletUIServiceTrackerCustomizer portletUIServiceTrackerCustomizer; + private LogService logService; @Activate void activate(ComponentContext componentContext) throws Exception { @@ -49,12 +55,21 @@ public class VaadinPortletProvider { VaadinResourceService service = OsgiVaadinResources.getService(); portletUIServiceTrackerCustomizer = new PortletUIServiceTrackerCustomizer( - service); + service, logService); serviceTracker = new ServiceTracker>( bundleContext, UI.class, portletUIServiceTrackerCustomizer); serviceTracker.open(); } + @Reference(cardinality = ReferenceCardinality.OPTIONAL) + void setLogService(LogService logService) { + this.logService = logService; + } + + void unsetLogService(LogService logService) { + this.logService = null; + } + @Deactivate void deactivate() { if (serviceTracker != null) { @@ -62,6 +77,5 @@ public class VaadinPortletProvider { portletUIServiceTrackerCustomizer.cleanPortletRegistrations(); portletUIServiceTrackerCustomizer = null; } - } } -- 2.39.5