diff options
author | S.W <wimmesberger@gmail.com> | 2019-06-27 09:58:37 +0200 |
---|---|---|
committer | Zhe Sun <31067185+ZheSun88@users.noreply.github.com> | 2019-06-27 10:58:36 +0300 |
commit | 583920f327c338a020d4e09e420548f44127cb7f (patch) | |
tree | 4319908dd2887bd780fb89a64d79c7690721c252 | |
parent | 4c4d0375c1efdf5d943ee2112bdd2160e0045af7 (diff) | |
download | vaadin-framework-583920f327c338a020d4e09e420548f44127cb7f.tar.gz vaadin-framework-583920f327c338a020d4e09e420548f44127cb7f.zip |
OSGi: Removed static VaadinResourceService access in liferay-integration, osgi-integration (#11335)
* Made VaadinResourceService a OSGi component, removed static access of OsgiVaadinResources
9 files changed, 418 insertions, 230 deletions
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 cb5f6cfa1b..0bdab7b480 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 @@ -17,7 +17,6 @@ package com.vaadin.osgi.liferay; 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; @@ -26,7 +25,6 @@ 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; import com.vaadin.osgi.resources.VaadinResourceService; import com.vaadin.ui.UI; @@ -45,19 +43,28 @@ public class VaadinPortletProvider { private ServiceTracker<UI, ServiceObjects<UI>> serviceTracker; private PortletUIServiceTrackerCustomizer portletUIServiceTrackerCustomizer; + private VaadinResourceService vaadinService; private LogService logService; @Activate - void activate(ComponentContext componentContext) throws Exception { - BundleContext bundleContext = componentContext.getBundleContext(); - VaadinResourceService service = OsgiVaadinResources.getService(); - + void activate(BundleContext bundleContext) throws Exception { portletUIServiceTrackerCustomizer = new PortletUIServiceTrackerCustomizer( - service, logService); + vaadinService, logService); serviceTracker = new ServiceTracker<UI, ServiceObjects<UI>>( bundleContext, UI.class, portletUIServiceTrackerCustomizer); serviceTracker.open(); } + + @Reference + void setVaadinResourceService(VaadinResourceService vaadinService) { + this.vaadinService = vaadinService; + } + + void unsetVaadinResourceService(VaadinResourceService vaadinService) { + if(this.vaadinService == vaadinService) { + this.vaadinService = null; + } + } @Reference(cardinality = ReferenceCardinality.OPTIONAL) void setLogService(LogService logService) { @@ -65,7 +72,9 @@ public class VaadinPortletProvider { } void unsetLogService(LogService logService) { - this.logService = null; + if(this.logService == logService) { + this.logService = null; + } } @Deactivate diff --git a/osgi-integration/src/main/java/com/vaadin/osgi/servlet/VaadinServletRegistration.java b/osgi-integration/src/main/java/com/vaadin/osgi/servlet/VaadinServletRegistration.java index d331edf7bb..013ec65f05 100644 --- a/osgi-integration/src/main/java/com/vaadin/osgi/servlet/VaadinServletRegistration.java +++ b/osgi-integration/src/main/java/com/vaadin/osgi/servlet/VaadinServletRegistration.java @@ -19,6 +19,7 @@ import java.util.Collections; import java.util.Hashtable; import java.util.LinkedHashMap; import java.util.Map; +import java.util.Objects; import javax.servlet.Servlet; import javax.servlet.annotation.WebServlet; @@ -26,6 +27,7 @@ import javax.servlet.annotation.WebServlet; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; import org.osgi.framework.ServiceRegistration; +import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Reference; import org.osgi.service.component.annotations.ReferenceCardinality; @@ -33,8 +35,6 @@ import org.osgi.service.component.annotations.ReferencePolicy; import org.osgi.service.http.whiteboard.HttpWhiteboardConstants; import org.osgi.service.log.LogService; -import com.vaadin.osgi.resources.OsgiVaadinResources; -import com.vaadin.osgi.resources.OsgiVaadinResources.ResourceBundleInactiveException; import com.vaadin.osgi.resources.VaadinResourceService; import com.vaadin.server.Constants; import com.vaadin.server.VaadinServlet; @@ -50,9 +50,6 @@ import com.vaadin.server.VaadinServlet; */ @Component public class VaadinServletRegistration { - private final Map<ServiceReference<VaadinServlet>, ServiceRegistration<Servlet>> registeredServlets = Collections - .synchronizedMap(new LinkedHashMap<>()); - private static final String MISSING_ANNOTATION_MESSAGE_FORMAT = "The property '%s' must be set in a '%s' without the '%s' annotation!"; private static final String URL_PATTERNS_NOT_SET_MESSAGE_FORMAT = "The property '%s' must be set when the 'urlPatterns' attribute is not set!"; @@ -61,11 +58,22 @@ public class VaadinServletRegistration { private static final String VAADIN_RESOURCES_PARAM = HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_INIT_PARAM_PREFIX + Constants.PARAMETER_VAADIN_RESOURCES; + private final Map<ServiceReference<VaadinServlet>, ServletRegistration> registeredServlets = Collections + .synchronizedMap(new LinkedHashMap<>()); + private VaadinResourceService vaadinService; private LogService logService; + @Activate + void activate(BundleContext bundleContext) throws Exception { + // see if we have registrations already which are not initialized + for(ServletRegistration registration : registeredServlets.values()) { + registration.register(vaadinService); + } + } + @Reference(cardinality = ReferenceCardinality.MULTIPLE, service = VaadinServlet.class, policy = ReferencePolicy.DYNAMIC) - void bindVaadinServlet(VaadinServlet servlet, ServiceReference<VaadinServlet> reference) - throws ResourceBundleInactiveException { + void bindVaadinServlet(VaadinServlet servlet, + ServiceReference<VaadinServlet> reference) { log(LogService.LOG_INFO, "VaadinServlet Registration"); Hashtable<String, Object> properties = getProperties(reference); @@ -77,20 +85,17 @@ public class VaadinServletRegistration { return; } - properties.put(VAADIN_RESOURCES_PARAM, getResourcePath()); if (annotation != null) { properties.put( HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_ASYNC_SUPPORTED, Boolean.toString(annotation.asyncSupported())); } - // We register the Http Whiteboard servlet using the context of - // the bundle which registered the Vaadin Servlet, not our own - BundleContext bundleContext = reference.getBundle().getBundleContext(); - ServiceRegistration<Servlet> servletRegistration = bundleContext - .registerService(Servlet.class, servlet, properties); - - registeredServlets.put(reference, servletRegistration); + ServletRegistration registration = new ServletRegistration(servlet, + reference, properties); + registeredServlets.put(reference, registration); + // try to register with the vaadin service - the service could be null at this point but we handle that in the register method + registration.register(this.vaadinService); } private boolean validateSettings(WebServlet annotation, @@ -112,11 +117,6 @@ public class VaadinServletRegistration { return true; } - private String getResourcePath() throws ResourceBundleInactiveException { - VaadinResourceService service = OsgiVaadinResources.getService(); - return String.format("/%s", service.getResourcePathPrefix()); - } - private void log(int level, String message) { if (logService != null) { logService.log(level, message); @@ -124,17 +124,21 @@ public class VaadinServletRegistration { } void unbindVaadinServlet(ServiceReference<VaadinServlet> reference) { - ServiceRegistration<?> servletRegistration = registeredServlets + ServletRegistration servletRegistration = registeredServlets .remove(reference); if (servletRegistration != null) { - try { - servletRegistration.unregister(); - } catch (IllegalStateException ise) { - // This service may have already been unregistered - // automatically by the OSGi framework if the - // application bundle is being stopped. This is - // obviously not a problem for us. - } + servletRegistration.unregister(); + } + } + + @Reference + void setVaadinResourceService(VaadinResourceService vaadinService) { + this.vaadinService = vaadinService; + } + + void unsetVaadinResourceService(VaadinResourceService vaadinService) { + if (this.vaadinService == vaadinService) { + this.vaadinService = null; } } @@ -144,7 +148,9 @@ public class VaadinServletRegistration { } void unsetLogService(LogService logService) { - this.logService = null; + if (this.logService == logService) { + this.logService = null; + } } private Hashtable<String, Object> getProperties( @@ -155,4 +161,53 @@ public class VaadinServletRegistration { } return properties; } + + private static class ServletRegistration { + private final VaadinServlet servlet; + private final ServiceReference<VaadinServlet> servletRef; + private final Hashtable<String, Object> properties; + + private volatile ServiceRegistration<Servlet> registration; + + public ServletRegistration(VaadinServlet servlet, + ServiceReference<VaadinServlet> servletRef, + Hashtable<String, Object> properties) { + this.servlet = Objects.requireNonNull(servlet); + this.servletRef = Objects.requireNonNull(servletRef); + this.properties = properties; + } + + public void register(VaadinResourceService vaadinService) { + // we are already registered + if (this.registration != null) + return; + // only register if the vaadin service is not null + if(vaadinService == null) + return; + + final String resourcePath = String.format("/%s", vaadinService.getResourcePathPrefix()); + this.properties.put(VAADIN_RESOURCES_PARAM, resourcePath); + // We register the Http Whiteboard servlet using the context of + // the bundle which registered the Vaadin Servlet, not our own + BundleContext bundleContext = this.servletRef.getBundle() + .getBundleContext(); + this.registration = bundleContext.registerService(Servlet.class, + servlet, properties); + } + + public void unregister() { + //we are already deregistered + if (this.registration == null) + return; + try { + this.registration.unregister(); + } catch (IllegalStateException ise) { + // This service may have already been unregistered + // automatically by the OSGi framework if the + // application bundle is being stopped. This is + // obviously not a problem for us. + } + this.registration = null; + } + } } @@ -43,7 +43,7 @@ <osgi.version>6.0.0</osgi.version> <osgi.annotation.version>6.0.1</osgi.annotation.version> - <bnd.version>3.3.0</bnd.version> + <bnd.version>3.5.0</bnd.version> <!-- Dependency unpack directory --> <dependency.unpack.directory>${project.build.directory}/dependency-unpack</dependency.unpack.directory> diff --git a/server/src/main/java/com/vaadin/server/osgi/BootstrapContribution.java b/server/src/main/java/com/vaadin/server/osgi/BootstrapContribution.java index 17e2e711e6..62b6d55967 100644 --- a/server/src/main/java/com/vaadin/server/osgi/BootstrapContribution.java +++ b/server/src/main/java/com/vaadin/server/osgi/BootstrapContribution.java @@ -39,8 +39,8 @@ public class BootstrapContribution implements OsgiVaadinContributor { public List<OsgiVaadinResource> getContributions() { final List<OsgiVaadinResource> contributions = new ArrayList<>( RESOURCES.length); - for (final String theme : RESOURCES) { - contributions.add(OsgiVaadinResource.create(theme)); + for (final String resource : RESOURCES) { + contributions.add(OsgiVaadinResource.create(resource)); } return contributions; } diff --git a/shared/src/main/java/com/vaadin/osgi/resources/OsgiVaadinResources.java b/shared/src/main/java/com/vaadin/osgi/resources/OsgiVaadinResources.java index 6f2842d47e..675c33db3f 100644 --- a/shared/src/main/java/com/vaadin/osgi/resources/OsgiVaadinResources.java +++ b/shared/src/main/java/com/vaadin/osgi/resources/OsgiVaadinResources.java @@ -17,9 +17,8 @@ package com.vaadin.osgi.resources; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; -import org.osgi.framework.Version; - -import com.vaadin.osgi.resources.impl.VaadinResourceServiceImpl; +import org.osgi.framework.ServiceReference; +import org.osgi.util.tracker.ServiceTracker; /** * {@link BundleActivator} used to provide access to the @@ -29,6 +28,8 @@ import com.vaadin.osgi.resources.impl.VaadinResourceServiceImpl; * @author Vaadin Ltd. * * @since 8.1 + * @deprecated use OSGi DS services to bind a instance of + * {@link VaadinResourceService} */ public class OsgiVaadinResources implements BundleActivator { @@ -48,8 +49,8 @@ public class OsgiVaadinResources implements BundleActivator { private static OsgiVaadinResources instance; - private VaadinResourceServiceImpl service; - private Version version; + private ServiceTracker<VaadinResourceService, VaadinResourceService> vaadinResourceTracker; + private VaadinResourceService service; /** * Returns the {@link VaadinResourceService} instance. Always returns @@ -71,16 +72,38 @@ public class OsgiVaadinResources implements BundleActivator { @Override public void start(BundleContext context) throws Exception { - version = context.getBundle().getVersion(); - service = new VaadinResourceServiceImpl(); - service.setBundleVersion(version.toString()); + vaadinResourceTracker = new ServiceTracker<VaadinResourceService, VaadinResourceService>( + context, VaadinResourceService.class, null) { + @Override + public VaadinResourceService addingService( + ServiceReference<VaadinResourceService> reference) { + VaadinResourceService vaadinService = super.addingService( + reference); + service = vaadinService; + return vaadinService; + } + + @Override + public void removedService( + ServiceReference<VaadinResourceService> reference, + VaadinResourceService service) { + super.removedService(reference, service); + if (OsgiVaadinResources.this.service == service) { + OsgiVaadinResources.this.service = null; + } + } + }; + vaadinResourceTracker.open(); instance = this; } @Override public void stop(BundleContext context) throws Exception { + if (vaadinResourceTracker != null) { + vaadinResourceTracker.close(); + } + vaadinResourceTracker = null; instance = null; service = null; - version = null; } } diff --git a/shared/src/main/java/com/vaadin/osgi/resources/VaadinResourceService.java b/shared/src/main/java/com/vaadin/osgi/resources/VaadinResourceService.java index ee4ff294e0..1568edf563 100644 --- a/shared/src/main/java/com/vaadin/osgi/resources/VaadinResourceService.java +++ b/shared/src/main/java/com/vaadin/osgi/resources/VaadinResourceService.java @@ -27,7 +27,6 @@ import org.osgi.service.http.NamespaceException; * @since 8.1 */ public interface VaadinResourceService { - /** * Register the theme with the given name under the * {@link VaadinResourceService} versioned namespace. The theme folder is @@ -38,6 +37,7 @@ public interface VaadinResourceService { * "/vaadin-x.x.x/VAADIN/themes/themeName" where x.x.x is the version of the * Vaadin Shared bundle * + * @deprecated use OSGi DS services and register a {@link OsgiVaadinTheme} * @param themeName * the name of the theme * @param httpService @@ -45,6 +45,7 @@ public interface VaadinResourceService { * @throws NamespaceException * if there is a clash during the theme registration */ + @Deprecated void publishTheme(String themeName, HttpService httpService) throws NamespaceException; @@ -56,6 +57,8 @@ public interface VaadinResourceService { * The resource will become accessible under the url "/vaadin-x.x.x/VAADIN/" * where x.x.x is the version of the Vaadin Shared bundle * + * @deprecated use OSGi DS services and register a + * {@link OsgiVaadinResource} * @param resourceName * the name of the resource * @param httpService @@ -63,6 +66,7 @@ public interface VaadinResourceService { * @throws NamespaceException * if there is a clash during the theme registration */ + @Deprecated void publishResource(String resourceName, HttpService httpService) throws NamespaceException; @@ -75,6 +79,8 @@ public interface VaadinResourceService { * "/vaadin-x.x.x/VAADIN/widgetsets" where x.x.x is the version of the * Vaadin Shared bundle * + * @deprecated use OSGi DS services and register a + * {@link OsgiVaadinWidgetset} * @param widgetsetName * the name of the resource * @param httpService @@ -82,6 +88,7 @@ public interface VaadinResourceService { * @throws NamespaceException * if there is a clash during the theme registration */ + @Deprecated void publishWidgetset(String widgetsetName, HttpService httpService) throws NamespaceException; @@ -94,4 +101,10 @@ public interface VaadinResourceService { */ String getResourcePathPrefix(); + /** + * Returns the http servlet context name of Vaadin + * + * @return the context name + */ + String getContextName(); } diff --git a/shared/src/main/java/com/vaadin/osgi/resources/impl/VaadinResourceServiceImpl.java b/shared/src/main/java/com/vaadin/osgi/resources/impl/VaadinResourceServiceImpl.java index 6ada30f7b3..6bda191681 100644 --- a/shared/src/main/java/com/vaadin/osgi/resources/impl/VaadinResourceServiceImpl.java +++ b/shared/src/main/java/com/vaadin/osgi/resources/impl/VaadinResourceServiceImpl.java @@ -15,8 +15,19 @@ */ package com.vaadin.osgi.resources.impl; +import java.util.Dictionary; +import java.util.Hashtable; + +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceRegistration; +import org.osgi.framework.Version; +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.http.HttpService; import org.osgi.service.http.NamespaceException; +import org.osgi.service.http.context.ServletContextHelper; +import org.osgi.service.http.whiteboard.HttpWhiteboardConstants; import com.vaadin.osgi.resources.VaadinResourceService; @@ -28,26 +39,36 @@ import com.vaadin.osgi.resources.VaadinResourceService; * * @since 8.1 */ +@Component public class VaadinResourceServiceImpl implements VaadinResourceService { private static final String NAMESPACE_PREFIX = "vaadin-%s"; - - private String bundleVersion; + // it's best practice to select a own context "namespace" + private static final String CONTEXT_NAME = "com.vaadin"; private String pathPrefix; + private ServiceRegistration<ServletContextHelper> servletContextReg; - /** - * Sets the version of the bundle managing this service. - * - * <p> - * This needs to be called before any other method after the service is - * created. - * - * @param bundleVersion - * the version of the bundle managing this service - */ - public void setBundleVersion(String bundleVersion) { - this.bundleVersion = bundleVersion; - pathPrefix = String.format(NAMESPACE_PREFIX, bundleVersion); + @Activate + public void start(BundleContext context) throws Exception { + Version version = context.getBundle().getVersion(); + this.setBundleVersion(version.toString()); + + // register the vaadin servlet context helper + Dictionary<String, String> contextProps = new Hashtable<>(); + contextProps.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_NAME, + this.getContextName()); + contextProps.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_PATH, + "/" + this.getResourcePathPrefix()); + servletContextReg = context.registerService(ServletContextHelper.class, + new VaadinServletContextFactory(), contextProps); + } + + @Deactivate + public void stop() { + if (servletContextReg != null) { + servletContextReg.unregister(); + servletContextReg = null; + } } @Override @@ -79,6 +100,25 @@ public class VaadinResourceServiceImpl implements VaadinResourceService { @Override public String getResourcePathPrefix() { - return String.format(NAMESPACE_PREFIX, bundleVersion); + return this.pathPrefix; + } + + @Override + public String getContextName() { + return CONTEXT_NAME; + } + + /** + * Sets the version of the bundle managing this service. + * + * <p> + * This needs to be called before any other method after the service is + * created. + * + * @param bundleVersion + * the version of the bundle managing this service + */ + private void setBundleVersion(String bundleVersion) { + this.pathPrefix = String.format(NAMESPACE_PREFIX, bundleVersion); } } diff --git a/shared/src/main/java/com/vaadin/osgi/resources/impl/VaadinResourceTrackerComponent.java b/shared/src/main/java/com/vaadin/osgi/resources/impl/VaadinResourceTrackerComponent.java index 031b1d1432..26b2a15d4f 100644 --- a/shared/src/main/java/com/vaadin/osgi/resources/impl/VaadinResourceTrackerComponent.java +++ b/shared/src/main/java/com/vaadin/osgi/resources/impl/VaadinResourceTrackerComponent.java @@ -15,16 +15,14 @@ */ package com.vaadin.osgi.resources.impl; -import java.io.IOException; -import java.net.URL; import java.util.ArrayList; import java.util.Collections; +import java.util.Dictionary; +import java.util.Hashtable; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import java.util.Objects; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; @@ -37,14 +35,11 @@ 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.component.annotations.ReferencePolicy; -import org.osgi.service.http.HttpContext; import org.osgi.service.http.HttpService; -import org.osgi.service.http.NamespaceException; +import org.osgi.service.http.whiteboard.HttpWhiteboardConstants; import com.vaadin.osgi.resources.OsgiVaadinContributor; import com.vaadin.osgi.resources.OsgiVaadinResource; -import com.vaadin.osgi.resources.OsgiVaadinResources; -import com.vaadin.osgi.resources.OsgiVaadinResources.ResourceBundleInactiveException; import com.vaadin.osgi.resources.OsgiVaadinTheme; import com.vaadin.osgi.resources.OsgiVaadinWidgetset; import com.vaadin.osgi.resources.VaadinResourceService; @@ -59,93 +54,44 @@ import com.vaadin.osgi.resources.VaadinResourceService; */ @Component(immediate = true) public class VaadinResourceTrackerComponent { - private final Map<Long, Delegate> resourceToRegistration = Collections + private final Map<Long, Delegate<?>> resourceToRegistration = Collections .synchronizedMap(new LinkedHashMap<>()); private final Map<Long, List<ServiceRegistration<? extends OsgiVaadinResource>>> contributorToRegistrations = Collections .synchronizedMap(new LinkedHashMap<>()); - private HttpService httpService; - - @Reference(cardinality = ReferenceCardinality.MULTIPLE, service = OsgiVaadinTheme.class, policy = ReferencePolicy.DYNAMIC) - void bindTheme(ServiceReference<OsgiVaadinTheme> themeRef) - throws ResourceBundleInactiveException, NamespaceException { - - Bundle bundle = themeRef.getBundle(); - BundleContext context = bundle.getBundleContext(); - OsgiVaadinTheme theme = context.getService(themeRef); - if (theme == null) { - return; - } + private BundleContext vaadinSharedContext; + private VaadinResourceService vaadinService; - VaadinResourceService resourceService = OsgiVaadinResources - .getService(); - Long serviceId = (Long) themeRef.getProperty(Constants.SERVICE_ID); - try { - registerTheme(resourceService, bundle, serviceId, theme); - } finally { - context.ungetService(themeRef); - } + @Reference(cardinality = ReferenceCardinality.MULTIPLE, service = OsgiVaadinTheme.class, policy = ReferencePolicy.DYNAMIC) + void bindTheme(ServiceReference<OsgiVaadinTheme> themeRef) { + registerResource(themeRef); } void unbindTheme(ServiceReference<OsgiVaadinTheme> themeRef) { - Long serviceId = (Long) themeRef.getProperty(Constants.SERVICE_ID); - unregisterResource(serviceId); + unregisterResource(themeRef); } @Reference(cardinality = ReferenceCardinality.MULTIPLE, service = OsgiVaadinWidgetset.class, policy = ReferencePolicy.DYNAMIC) - void bindWidgetset(ServiceReference<OsgiVaadinWidgetset> widgetsetRef) - throws ResourceBundleInactiveException, NamespaceException { - Bundle bundle = widgetsetRef.getBundle(); - BundleContext context = bundle.getBundleContext(); - - OsgiVaadinWidgetset widgetset = context.getService(widgetsetRef); - if (widgetset == null) { - return; - } - - VaadinResourceService service = OsgiVaadinResources.getService(); - Long serviceId = (Long) widgetsetRef.getProperty(Constants.SERVICE_ID); - try { - registerWidget(service, bundle, serviceId, widgetset); - } finally { - context.ungetService(widgetsetRef); - } - + void bindWidgetset(ServiceReference<OsgiVaadinWidgetset> widgetsetRef) { + registerResource(widgetsetRef); } void unbindWidgetset(ServiceReference<OsgiVaadinWidgetset> widgetsetRef) { - Long serviceId = (Long) widgetsetRef.getProperty(Constants.SERVICE_ID); - unregisterResource(serviceId); + unregisterResource(widgetsetRef); } @Reference(cardinality = ReferenceCardinality.MULTIPLE, service = OsgiVaadinResource.class, policy = ReferencePolicy.DYNAMIC) - void bindResource(ServiceReference<OsgiVaadinResource> resourceRef) - throws ResourceBundleInactiveException, NamespaceException { - Bundle bundle = resourceRef.getBundle(); - BundleContext context = bundle.getBundleContext(); - - OsgiVaadinResource resource = context.getService(resourceRef); - if (resource == null) { - return; - } - - VaadinResourceService service = OsgiVaadinResources.getService(); - Long serviceId = (Long) resourceRef.getProperty(Constants.SERVICE_ID); - try { - registerResource(service, bundle, serviceId, resource); - } finally { - context.ungetService(resourceRef); - } + void bindResource(ServiceReference<OsgiVaadinResource> resourceRef) { + registerResource(resourceRef); } void unbindResource(ServiceReference<OsgiVaadinResource> resourceRef) { - Long serviceId = (Long) resourceRef.getProperty(Constants.SERVICE_ID); - unregisterResource(serviceId); + unregisterResource(resourceRef); } @Reference(cardinality = ReferenceCardinality.MULTIPLE, service = OsgiVaadinContributor.class, policy = ReferencePolicy.DYNAMIC) - void bindContributor(ServiceReference<OsgiVaadinContributor> contributorRef) - throws ResourceBundleInactiveException { + void bindContributor( + ServiceReference<OsgiVaadinContributor> contributorRef) { Bundle bundle = contributorRef.getBundle(); BundleContext context = bundle.getBundleContext(); @@ -189,23 +135,25 @@ public class VaadinResourceTrackerComponent { } @Reference - void setHttpService(HttpService service) { - this.httpService = service; + void bindVaadinResourceService(VaadinResourceService vaadinService) { + this.vaadinService = vaadinService; } - void unsetHttpService(HttpService service) { - this.httpService = null; + void unbindVaadinResourceService(VaadinResourceService vaadinService) { + if (this.vaadinService == vaadinService) { + this.vaadinService = null; + } } /** * - * @throws NamespaceException * @since 8.6.0 */ @Activate - protected void activate() throws NamespaceException { - for (Delegate registration : resourceToRegistration.values()) { - registerResource(registration); + protected void activate(BundleContext context) { + vaadinSharedContext = context; + for (Delegate<?> registration : resourceToRegistration.values()) { + registration.register(vaadinSharedContext, vaadinService); } } @@ -214,7 +162,7 @@ public class VaadinResourceTrackerComponent { */ @Deactivate protected void deactivate() { - for (final Delegate registration : resourceToRegistration.values()) { + for (final Delegate<?> registration : resourceToRegistration.values()) { unregisterResource(registration); } for (List<ServiceRegistration<? extends OsgiVaadinResource>> registrations : contributorToRegistrations @@ -225,107 +173,146 @@ public class VaadinResourceTrackerComponent { } resourceToRegistration.clear(); contributorToRegistrations.clear(); - httpService = null; - } - - private void registerTheme(VaadinResourceService resourceService, - Bundle bundle, Long serviceId, OsgiVaadinTheme theme) - throws NamespaceException { - String pathPrefix = resourceService.getResourcePathPrefix(); - - String alias = PathFormatHelper.getThemeAlias(theme.getName(), - pathPrefix); - String path = PathFormatHelper.getThemePath(theme.getName()); - - registerResource(alias, path, bundle, serviceId); - } - - private void registerWidget(VaadinResourceService resourceService, - Bundle bundle, Long serviceId, OsgiVaadinWidgetset widgetset) - throws NamespaceException { - String pathPrefix = resourceService.getResourcePathPrefix(); - - String alias = PathFormatHelper.getWidgetsetAlias(widgetset.getName(), - pathPrefix); - String path = PathFormatHelper.getWidgetsetPath(widgetset.getName()); - - registerResource(alias, path, bundle, serviceId); + vaadinSharedContext = null; + vaadinService = null; } - private void registerResource(VaadinResourceService resourceService, - Bundle bundle, Long serviceId, OsgiVaadinResource resource) - throws NamespaceException { - String pathPrefix = resourceService.getResourcePathPrefix(); - - String alias = PathFormatHelper.getRootResourceAlias(resource.getName(), - pathPrefix); - String path = PathFormatHelper.getRootResourcePath(resource.getName()); - - registerResource(alias, path, bundle, serviceId); - } - - private void registerResource(String alias, String path, Bundle bundle, - Long serviceId) throws NamespaceException { - Delegate registration = new Delegate(alias, path, bundle); + private <T extends OsgiVaadinResource> void registerResource( + ServiceReference<T> resourceRef) { + String pattern = (String) resourceRef.getProperty( + HttpWhiteboardConstants.HTTP_WHITEBOARD_RESOURCE_PATTERN); + // if this resource contains a http whiteboard property we are done here + // because we are registering the same service with whiteboard + // properties we have to filter them here + if (pattern != null) + return; + BundleContext context = resourceRef.getBundle().getBundleContext(); + Long serviceId = (Long) resourceRef.getProperty(Constants.SERVICE_ID); + Delegate<T> registration = new Delegate<>(resourceRef, context); resourceToRegistration.put(serviceId, registration); - registerResource(registration); + registration.register(vaadinSharedContext, vaadinService); } - private void registerResource(Delegate registration) - throws NamespaceException { - if (this.httpService != null && !registration.isInitialized()) { - registration.init(httpService); - httpService.registerResources(registration.alias, registration.path, - registration); - } + private void unregisterResource( + ServiceReference<? extends OsgiVaadinResource> resourceRef) { + Long serviceId = (Long) resourceRef.getProperty(Constants.SERVICE_ID); + unregisterResource(serviceId); } private void unregisterResource(Long serviceId) { - Delegate registration = resourceToRegistration.remove(serviceId); + if (serviceId == null) + return; + Delegate<?> registration = resourceToRegistration.remove(serviceId); unregisterResource(registration); } - private void unregisterResource(Delegate registration) { - if (registration != null && httpService != null) { - httpService.unregister(registration.alias); + private void unregisterResource(Delegate<?> registration) { + if (registration != null) { + registration.unregister(); } } - static final class Delegate implements HttpContext { - private final String alias; - private final String path; - private final Bundle bundle; - - private volatile HttpContext context; - - public Delegate(String alias, String path, Bundle bundle) { - this.alias = alias; - this.path = path; - this.bundle = bundle; - } - - public void init(HttpService service) { - context = service.createDefaultHttpContext(); - } - - public boolean isInitialized() { - return context != null; + static final class Delegate<T extends OsgiVaadinResource> { + private final ServiceReference<T> resourceRef; + // the bundle context who contributed the resource - we reuse that so we + // can register the http whiteboard resource in the name of the + // contributing bundle + private final BundleContext bundleContext; + + private volatile BundleContext vaadinSharedContext; + private volatile VaadinResourceService vaadinService; + private volatile ServiceRegistration<? super T> resourceRegistration; + + public Delegate(ServiceReference<T> resourceRef, + BundleContext bundleContext) { + this.resourceRef = Objects.requireNonNull(resourceRef); + this.bundleContext = Objects.requireNonNull(bundleContext); } - @Override - public boolean handleSecurity(HttpServletRequest request, - HttpServletResponse response) throws IOException { - return context.handleSecurity(request, response); + public void register(BundleContext vaadinSharedContext, + VaadinResourceService vaadinService) { + if (vaadinService != null) { + this.vaadinService = vaadinService; + } + if (vaadinSharedContext != null) { + this.vaadinSharedContext = vaadinSharedContext; + } + // if all dependencies are satisfied we can finally register the + // http resource + if (this.vaadinService != null + && this.vaadinSharedContext != null) { + this.registerImpl(); + } } - @Override - public URL getResource(String name) { - return bundle.getResource(name); + public void unregister() { + if (resourceRegistration != null) { + resourceRegistration.unregister(); + } + if (vaadinSharedContext != null) { + // unget the service reference + vaadinSharedContext.ungetService(resourceRef); + } + vaadinService = null; + vaadinSharedContext = null; + resourceRegistration = null; } - @Override - public String getMimeType(String name) { - return context.getMimeType(name); + @SuppressWarnings("unchecked") + private void registerImpl() { + // we have already registered if resourceRegistration is set + if (resourceRegistration != null) + return; + + T resource = vaadinSharedContext.getService(this.resourceRef); + // we don't need a path prefix because we register at the vaadin + // context which handles the prefixing + String pathPrefix = ""; + Class<? super T> interfaceType; + String alias; + String path; + if (resource instanceof OsgiVaadinWidgetset) { + alias = PathFormatHelper.getWidgetsetAlias(resource.getName(), + pathPrefix); + // OsgiVaadinWidgetset provides folders so we have to add a + // wildcard + alias = alias + "/*"; + path = PathFormatHelper.getWidgetsetPath(resource.getName()); + // save cast because OsgiVaadinWidgetset is a super class of T + interfaceType = (Class<? super T>) OsgiVaadinWidgetset.class; + } else if (resource instanceof OsgiVaadinTheme) { + alias = PathFormatHelper.getThemeAlias(resource.getName(), + pathPrefix); + // OsgiVaadinTheme provides folders so we have to add a wildcard + alias = alias + "/*"; + path = PathFormatHelper.getThemePath(resource.getName()); + // save cast because OsgiVaadinTheme is a super class of T + interfaceType = (Class<? super T>) OsgiVaadinTheme.class; + } else { + alias = PathFormatHelper + .getRootResourceAlias(resource.getName(), pathPrefix); + path = PathFormatHelper.getRootResourcePath(resource.getName()); + interfaceType = OsgiVaadinResource.class; + } + // remove the empty prefixed slash + alias = alias.substring(1); + + final String contextFilter = "(" + + HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_NAME + "=" + + vaadinService.getContextName() + ")"; + // register a OSGi http resource based on the whiteboard pattern + final Dictionary<String, String> properties = new Hashtable<>(); + properties.put( + HttpWhiteboardConstants.HTTP_WHITEBOARD_RESOURCE_PATTERN, + alias); + properties.put( + HttpWhiteboardConstants.HTTP_WHITEBOARD_RESOURCE_PREFIX, + path); + properties.put( + HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_SELECT, + contextFilter); + resourceRegistration = bundleContext.registerService(interfaceType, + resource, properties); } } } diff --git a/shared/src/main/java/com/vaadin/osgi/resources/impl/VaadinServletContextFactory.java b/shared/src/main/java/com/vaadin/osgi/resources/impl/VaadinServletContextFactory.java new file mode 100644 index 0000000000..035f6fca47 --- /dev/null +++ b/shared/src/main/java/com/vaadin/osgi/resources/impl/VaadinServletContextFactory.java @@ -0,0 +1,61 @@ +/* + * Copyright 2000-2018 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.osgi.resources.impl; + +import java.net.URL; + +import org.osgi.framework.Bundle; +import org.osgi.framework.ServiceFactory; +import org.osgi.framework.ServiceRegistration; +import org.osgi.service.http.context.ServletContextHelper; + +public class VaadinServletContextFactory + implements ServiceFactory<ServletContextHelper> { + @Override + public ServletContextHelper getService(final Bundle bundle, + final ServiceRegistration<ServletContextHelper> registration) { + return new VaadinServletContext(bundle); + } + + @Override + public void ungetService(final Bundle bundle, + final ServiceRegistration<ServletContextHelper> registration, + final ServletContextHelper service) { + // nothing to do + } + + private static class VaadinServletContext extends ServletContextHelper { + private final Bundle bundle; + + public VaadinServletContext(Bundle bundle) { + super(bundle); + this.bundle = bundle; + } + + // we want to load the resources from the classpath + @Override + public URL getResource(String name) { + if ((name != null) && (bundle != null)) { + if (name.startsWith("/")) { + name = name.substring(1); + } + + return this.bundle.getResource(name); + } + return null; + } + } +} |