Browse Source

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

* Made VaadinResourceService a OSGi component, removed static access of OsgiVaadinResources
tags/8.9.0.alpha1
S.W 1 year ago
parent
commit
583920f327

+ 17
- 8
liferay-integration/src/main/java/com/vaadin/osgi/liferay/VaadinPortletProvider.java View File

@@ -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

+ 85
- 30
osgi-integration/src/main/java/com/vaadin/osgi/servlet/VaadinServletRegistration.java View File

@@ -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;
}
}
}

+ 1
- 1
pom.xml View File

@@ -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>

+ 2
- 2
server/src/main/java/com/vaadin/server/osgi/BootstrapContribution.java View File

@@ -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;
}

+ 32
- 9
shared/src/main/java/com/vaadin/osgi/resources/OsgiVaadinResources.java View File

@@ -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;
}
}

+ 14
- 1
shared/src/main/java/com/vaadin/osgi/resources/VaadinResourceService.java View File

@@ -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();
}

+ 56
- 16
shared/src/main/java/com/vaadin/osgi/resources/impl/VaadinResourceServiceImpl.java View File

@@ -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);
}
}

+ 150
- 163
shared/src/main/java/com/vaadin/osgi/resources/impl/VaadinResourceTrackerComponent.java View File

@@ -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);
}
}
}

+ 61
- 0
shared/src/main/java/com/vaadin/osgi/resources/impl/VaadinServletContextFactory.java View File

@@ -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;
}
}
}

Loading…
Cancel
Save