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 4 years ago
parent
commit
583920f327

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



import org.osgi.framework.BundleContext; import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceObjects; import org.osgi.framework.ServiceObjects;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate; import org.osgi.service.component.annotations.Deactivate;
import org.osgi.service.log.LogService; import org.osgi.service.log.LogService;
import org.osgi.util.tracker.ServiceTracker; import org.osgi.util.tracker.ServiceTracker;


import com.vaadin.osgi.resources.OsgiVaadinResources;
import com.vaadin.osgi.resources.VaadinResourceService; import com.vaadin.osgi.resources.VaadinResourceService;
import com.vaadin.ui.UI; import com.vaadin.ui.UI;




private ServiceTracker<UI, ServiceObjects<UI>> serviceTracker; private ServiceTracker<UI, ServiceObjects<UI>> serviceTracker;
private PortletUIServiceTrackerCustomizer portletUIServiceTrackerCustomizer; private PortletUIServiceTrackerCustomizer portletUIServiceTrackerCustomizer;
private VaadinResourceService vaadinService;
private LogService logService; private LogService logService;


@Activate @Activate
void activate(ComponentContext componentContext) throws Exception {
BundleContext bundleContext = componentContext.getBundleContext();
VaadinResourceService service = OsgiVaadinResources.getService();

void activate(BundleContext bundleContext) throws Exception {
portletUIServiceTrackerCustomizer = new PortletUIServiceTrackerCustomizer( portletUIServiceTrackerCustomizer = new PortletUIServiceTrackerCustomizer(
service, logService);
vaadinService, logService);
serviceTracker = new ServiceTracker<UI, ServiceObjects<UI>>( serviceTracker = new ServiceTracker<UI, ServiceObjects<UI>>(
bundleContext, UI.class, portletUIServiceTrackerCustomizer); bundleContext, UI.class, portletUIServiceTrackerCustomizer);
serviceTracker.open(); 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) @Reference(cardinality = ReferenceCardinality.OPTIONAL)
void setLogService(LogService logService) { void setLogService(LogService logService) {
} }


void unsetLogService(LogService logService) { void unsetLogService(LogService logService) {
this.logService = null;
if(this.logService == logService) {
this.logService = null;
}
} }


@Deactivate @Deactivate

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

import java.util.Hashtable; import java.util.Hashtable;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import java.util.Objects;


import javax.servlet.Servlet; import javax.servlet.Servlet;
import javax.servlet.annotation.WebServlet; import javax.servlet.annotation.WebServlet;
import org.osgi.framework.BundleContext; import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference; import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration; 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.Component;
import org.osgi.service.component.annotations.Reference; import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality; import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.http.whiteboard.HttpWhiteboardConstants; import org.osgi.service.http.whiteboard.HttpWhiteboardConstants;
import org.osgi.service.log.LogService; 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.osgi.resources.VaadinResourceService;
import com.vaadin.server.Constants; import com.vaadin.server.Constants;
import com.vaadin.server.VaadinServlet; import com.vaadin.server.VaadinServlet;
*/ */
@Component @Component
public class VaadinServletRegistration { 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 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!"; private static final String URL_PATTERNS_NOT_SET_MESSAGE_FORMAT = "The property '%s' must be set when the 'urlPatterns' attribute is not set!";


private static final String VAADIN_RESOURCES_PARAM = HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_INIT_PARAM_PREFIX private static final String VAADIN_RESOURCES_PARAM = HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_INIT_PARAM_PREFIX
+ Constants.PARAMETER_VAADIN_RESOURCES; + Constants.PARAMETER_VAADIN_RESOURCES;


private final Map<ServiceReference<VaadinServlet>, ServletRegistration> registeredServlets = Collections
.synchronizedMap(new LinkedHashMap<>());
private VaadinResourceService vaadinService;
private LogService logService; 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) @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"); log(LogService.LOG_INFO, "VaadinServlet Registration");


Hashtable<String, Object> properties = getProperties(reference); Hashtable<String, Object> properties = getProperties(reference);
return; return;
} }


properties.put(VAADIN_RESOURCES_PARAM, getResourcePath());
if (annotation != null) { if (annotation != null) {
properties.put( properties.put(
HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_ASYNC_SUPPORTED, HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_ASYNC_SUPPORTED,
Boolean.toString(annotation.asyncSupported())); 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, private boolean validateSettings(WebServlet annotation,
return true; return true;
} }


private String getResourcePath() throws ResourceBundleInactiveException {
VaadinResourceService service = OsgiVaadinResources.getService();
return String.format("/%s", service.getResourcePathPrefix());
}

private void log(int level, String message) { private void log(int level, String message) {
if (logService != null) { if (logService != null) {
logService.log(level, message); logService.log(level, message);
} }


void unbindVaadinServlet(ServiceReference<VaadinServlet> reference) { void unbindVaadinServlet(ServiceReference<VaadinServlet> reference) {
ServiceRegistration<?> servletRegistration = registeredServlets
ServletRegistration servletRegistration = registeredServlets
.remove(reference); .remove(reference);
if (servletRegistration != null) { 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;
} }
} }


} }


void unsetLogService(LogService logService) { void unsetLogService(LogService logService) {
this.logService = null;
if (this.logService == logService) {
this.logService = null;
}
} }


private Hashtable<String, Object> getProperties( private Hashtable<String, Object> getProperties(
} }
return properties; 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

<osgi.version>6.0.0</osgi.version> <osgi.version>6.0.0</osgi.version>
<osgi.annotation.version>6.0.1</osgi.annotation.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 -->
<dependency.unpack.directory>${project.build.directory}/dependency-unpack</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

public List<OsgiVaadinResource> getContributions() { public List<OsgiVaadinResource> getContributions() {
final List<OsgiVaadinResource> contributions = new ArrayList<>( final List<OsgiVaadinResource> contributions = new ArrayList<>(
RESOURCES.length); RESOURCES.length);
for (final String theme : RESOURCES) {
contributions.add(OsgiVaadinResource.create(theme));
for (final String resource : RESOURCES) {
contributions.add(OsgiVaadinResource.create(resource));
} }
return contributions; return contributions;
} }

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



import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext; 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 * {@link BundleActivator} used to provide access to the
* @author Vaadin Ltd. * @author Vaadin Ltd.
* *
* @since 8.1 * @since 8.1
* @deprecated use OSGi DS services to bind a instance of
* {@link VaadinResourceService}
*/ */
public class OsgiVaadinResources implements BundleActivator { public class OsgiVaadinResources implements BundleActivator {




private static OsgiVaadinResources instance; 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 * Returns the {@link VaadinResourceService} instance. Always returns


@Override @Override
public void start(BundleContext context) throws Exception { 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; instance = this;
} }


@Override @Override
public void stop(BundleContext context) throws Exception { public void stop(BundleContext context) throws Exception {
if (vaadinResourceTracker != null) {
vaadinResourceTracker.close();
}
vaadinResourceTracker = null;
instance = null; instance = null;
service = null; service = null;
version = null;
} }
} }

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

* @since 8.1 * @since 8.1
*/ */
public interface VaadinResourceService { public interface VaadinResourceService {

/** /**
* Register the theme with the given name under the * Register the theme with the given name under the
* {@link VaadinResourceService} versioned namespace. The theme folder is * {@link VaadinResourceService} versioned namespace. The theme folder is
* "/vaadin-x.x.x/VAADIN/themes/themeName" where x.x.x is the version of the * "/vaadin-x.x.x/VAADIN/themes/themeName" where x.x.x is the version of the
* Vaadin Shared bundle * Vaadin Shared bundle
* *
* @deprecated use OSGi DS services and register a {@link OsgiVaadinTheme}
* @param themeName * @param themeName
* the name of the theme * the name of the theme
* @param httpService * @param httpService
* @throws NamespaceException * @throws NamespaceException
* if there is a clash during the theme registration * if there is a clash during the theme registration
*/ */
@Deprecated
void publishTheme(String themeName, HttpService httpService) void publishTheme(String themeName, HttpService httpService)
throws NamespaceException; throws NamespaceException;


* The resource will become accessible under the url "/vaadin-x.x.x/VAADIN/" * 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 * where x.x.x is the version of the Vaadin Shared bundle
* *
* @deprecated use OSGi DS services and register a
* {@link OsgiVaadinResource}
* @param resourceName * @param resourceName
* the name of the resource * the name of the resource
* @param httpService * @param httpService
* @throws NamespaceException * @throws NamespaceException
* if there is a clash during the theme registration * if there is a clash during the theme registration
*/ */
@Deprecated
void publishResource(String resourceName, HttpService httpService) void publishResource(String resourceName, HttpService httpService)
throws NamespaceException; throws NamespaceException;


* "/vaadin-x.x.x/VAADIN/widgetsets" where x.x.x is the version of the * "/vaadin-x.x.x/VAADIN/widgetsets" where x.x.x is the version of the
* Vaadin Shared bundle * Vaadin Shared bundle
* *
* @deprecated use OSGi DS services and register a
* {@link OsgiVaadinWidgetset}
* @param widgetsetName * @param widgetsetName
* the name of the resource * the name of the resource
* @param httpService * @param httpService
* @throws NamespaceException * @throws NamespaceException
* if there is a clash during the theme registration * if there is a clash during the theme registration
*/ */
@Deprecated
void publishWidgetset(String widgetsetName, HttpService httpService) void publishWidgetset(String widgetsetName, HttpService httpService)
throws NamespaceException; throws NamespaceException;


*/ */
String getResourcePathPrefix(); 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

*/ */
package com.vaadin.osgi.resources.impl; 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.HttpService;
import org.osgi.service.http.NamespaceException; 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; import com.vaadin.osgi.resources.VaadinResourceService;


* *
* @since 8.1 * @since 8.1
*/ */
@Component
public class VaadinResourceServiceImpl implements VaadinResourceService { public class VaadinResourceServiceImpl implements VaadinResourceService {
private static final String NAMESPACE_PREFIX = "vaadin-%s"; 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 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 @Override


@Override @Override
public String getResourcePathPrefix() { 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

*/ */
package com.vaadin.osgi.resources.impl; package com.vaadin.osgi.resources.impl;


import java.io.IOException;
import java.net.URL;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Dictionary;
import java.util.Hashtable;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; 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.Bundle;
import org.osgi.framework.BundleContext; import org.osgi.framework.BundleContext;
import org.osgi.service.component.annotations.Reference; import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality; import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.component.annotations.ReferencePolicy; import org.osgi.service.component.annotations.ReferencePolicy;
import org.osgi.service.http.HttpContext;
import org.osgi.service.http.HttpService; 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.OsgiVaadinContributor;
import com.vaadin.osgi.resources.OsgiVaadinResource; 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.OsgiVaadinTheme;
import com.vaadin.osgi.resources.OsgiVaadinWidgetset; import com.vaadin.osgi.resources.OsgiVaadinWidgetset;
import com.vaadin.osgi.resources.VaadinResourceService; import com.vaadin.osgi.resources.VaadinResourceService;
*/ */
@Component(immediate = true) @Component(immediate = true)
public class VaadinResourceTrackerComponent { public class VaadinResourceTrackerComponent {
private final Map<Long, Delegate> resourceToRegistration = Collections
private final Map<Long, Delegate<?>> resourceToRegistration = Collections
.synchronizedMap(new LinkedHashMap<>()); .synchronizedMap(new LinkedHashMap<>());
private final Map<Long, List<ServiceRegistration<? extends OsgiVaadinResource>>> contributorToRegistrations = Collections private final Map<Long, List<ServiceRegistration<? extends OsgiVaadinResource>>> contributorToRegistrations = Collections
.synchronizedMap(new LinkedHashMap<>()); .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) { 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) @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) { 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) @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) { 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) @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(); Bundle bundle = contributorRef.getBundle();
BundleContext context = bundle.getBundleContext(); BundleContext context = bundle.getBundleContext();


} }


@Reference @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 * @since 8.6.0
*/ */
@Activate @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);
} }
} }


*/ */
@Deactivate @Deactivate
protected void deactivate() { protected void deactivate() {
for (final Delegate registration : resourceToRegistration.values()) {
for (final Delegate<?> registration : resourceToRegistration.values()) {
unregisterResource(registration); unregisterResource(registration);
} }
for (List<ServiceRegistration<? extends OsgiVaadinResource>> registrations : contributorToRegistrations for (List<ServiceRegistration<? extends OsgiVaadinResource>> registrations : contributorToRegistrations
} }
resourceToRegistration.clear(); resourceToRegistration.clear();
contributorToRegistrations.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); 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) { private void unregisterResource(Long serviceId) {
Delegate registration = resourceToRegistration.remove(serviceId);
if (serviceId == null)
return;
Delegate<?> registration = resourceToRegistration.remove(serviceId);
unregisterResource(registration); 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

/*
* 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