Browse Source

Convenience API for registering themes and widgetsets

tags/8.1.0.alpha7
Mirjan Merruko 7 years ago
parent
commit
5308eb76f4

+ 24
- 3
osgi-integration/src/main/java/com/vaadin/osgi/servlet/VaadinServletRegistration.java View File

@@ -15,13 +15,17 @@
*/
package com.vaadin.osgi.servlet;

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

import javax.servlet.Servlet;
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.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
@@ -46,6 +50,9 @@ import com.vaadin.server.VaadinServlet;
*/
@Component(immediate = true)
public class VaadinServletRegistration {
private Map<Long, ServiceRegistration<?>> 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!";

@@ -78,10 +85,19 @@ public class VaadinServletRegistration {
Boolean.toString(annotation.asyncSupported()));
}

bundleContext.registerService(Servlet.class, servlet, properties);
ServiceRegistration<Servlet> servletRegistration = bundleContext
.registerService(Servlet.class, servlet, properties);
Long serviceId = getServiceId(reference);
registeredServlets.put(serviceId, servletRegistration);

bundleContext.ungetService(reference);
}

private Long getServiceId(ServiceReference<VaadinServlet> reference) {
return (Long) reference
.getProperty(org.osgi.framework.Constants.SERVICE_ID);
}

private boolean validateSettings(WebServlet annotation,
Hashtable<String, Object> properties) {
if (!properties.containsKey(SERVLET_PATTERN)) {
@@ -112,8 +128,13 @@ public class VaadinServletRegistration {
}
}

void unbindVaadinServlet(VaadinServlet servlet) {

void unbindVaadinServlet(ServiceReference<VaadinServlet> servletRef) {
Long serviceId = getServiceId(servletRef);
ServiceRegistration<?> servletRegistration = registeredServlets
.remove(serviceId);
if (servletRegistration != null) {
servletRegistration.unregister();
}
}

@Reference(cardinality = ReferenceCardinality.OPTIONAL)

+ 30
- 0
shared/src/main/java/com/vaadin/osgi/resources/OSGiVaadinTheme.java View File

@@ -0,0 +1,30 @@
/*
* Copyright 2000-2016 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;

/**
* Used to declare a Vaadin Theme for use in OSGi. The theme is expected to be
* in the same OSGi bundle as the class implementing this interface, under the
* path "/VAADIN/themes/{themeName}" where {themeName} is what is returned by
* {@link OSGiVaadinTheme#getName()}.
*
* @author Vaadin Ltd.
*
* @since 8.1
*/
public interface OSGiVaadinTheme {
public String getName();
}

+ 30
- 0
shared/src/main/java/com/vaadin/osgi/resources/OSGiVaadinWidgetset.java View File

@@ -0,0 +1,30 @@
/*
* Copyright 2000-2016 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;

/**
* Used to declare a Vaadin Widgetset for use in OSGi. The widgetset is expected
* to be in the same OSGi bundle as the class implementing this interface, under
* the path "/VAADIN/widgetsets/{widgetsetName}" where {widgetsetName} is what
* is returned by {@link OSGiVaadinWidgetset#getName()}.
*
* @author Vaadin Ltd.
*
* @since 8.1
*/
public interface OSGiVaadinWidgetset {
public String getName();
}

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

@@ -0,0 +1,118 @@
/*
* Copyright 2000-2016 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;

/**
* Helper for formatting the Alias, and Theme and Widgetset names.
*
* @author Vaadin Ltd.
*
* @since 8.1
*/
public final class PathFormatHelper {
private static final String VAADIN_ROOT_ALIAS_FORMAT = "/%s/VAADIN/%s";
private static final String VAADIN_ROOT_FORMAT = "/VAADIN/%s";

private static final String VAADIN_THEME_ALIAS_FORMAT = "/%s/VAADIN/themes/%s";
private static final String VAADIN_WIDGETSET_ALIAS_FORMAT = "/%s/VAADIN/widgetsets/%s";

private static final String VAADIN_THEME_PATH_FORMAT = "/VAADIN/themes/%s";
private static final String VAADIN_WIDGETSET_PATH_FORMAT = "/VAADIN/widgetsets/%s";

private PathFormatHelper() {

}

/**
* Returns the alias for the theme given a the theme name and a path prefix.
*
* @param themeName
* the theme name
* @param pathPrefix
* the prefix for the /VAADIN/ folder
* @return the alias
*/
public static String getThemeAlias(String themeName, String pathPrefix) {
return String.format(VAADIN_THEME_ALIAS_FORMAT, pathPrefix, themeName);
}

/**
* Returns the expected/default path of the theme folder in the source
* bundle.
*
* @param themeName
* the name of the theme
* @return the path of the theme folder in the source bundle
*/
public static String getThemePath(String themeName) {
return String.format(VAADIN_THEME_PATH_FORMAT, themeName);
}

/**
* Returns the alias for a widgetset given a the widgetset name and a path
* prefix.
*
* @param widgetsetName
* the name of the widgetset
* @param pathPrefix
* the prefix for the /VAADIN/ folder
* @return the alias
*/
public static String getWidgetsetAlias(String widgetsetName,
String pathPrefix) {
return String.format(VAADIN_WIDGETSET_ALIAS_FORMAT, pathPrefix,
widgetsetName);
}

/**
* Returns the expected/default path of the widgetset folder in the source
* bundle.
*
* @param widgetsetName
* the name of the widgetset
* @return the path of the widgetset folder in the source bundle
*/
public static String getWidgetsetPath(String widgetsetName) {
return String.format(VAADIN_WIDGETSET_PATH_FORMAT, widgetsetName);
}

/**
* Returns the alias for a resource that will placed under the /VAADIN/
* folder.
*
* @param resourceName
* the name of the resource
* @param pathPrefix
* the prefix for the /VAADIN/ folder
* @return the alias
*/
public static String getRootResourceAlias(String resourceName,
String pathPrefix) {
return String.format(VAADIN_ROOT_ALIAS_FORMAT, pathPrefix,
resourceName);
}

/**
* Returns the expected/default path of the resource in the source bundle.
*
* @param resourceName
* the name of the resource
* @return the path of the resource in the source bundle
*/
public static String getRootResourcePath(String resourceName) {
return String.format(VAADIN_ROOT_FORMAT, resourceName);
}
}

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

@@ -23,71 +23,58 @@ import com.vaadin.osgi.resources.VaadinResourceService;
/**
* Implementation of {@link VaadinResourceService}. Uses bundle version as a
* prefix for the /VAADIN/ folder.
*
*
* @author Vaadin Ltd.
*
*
* @since 8.1
*/
public class VaadinResourceServiceImpl implements VaadinResourceService {
private static final String NAMESPACE_PREFIX = "vaadin-%s";

private static final String VAADIN_ROOT_ALIAS_FORMAT = "/%s/VAADIN/%s";
private static final String VAADIN_ROOT_FORMAT = "/VAADIN/%s";

private static final String VAADIN_THEME_ALIAS_FORMAT = "/%s/VAADIN/themes/%s";
private static final String VAADIN_WIDGETSET_ALIAS_FORMAT = "/%s/VAADIN/widgetsets/%s";

private static final String VAADIN_THEME_PATH_FORMAT = "/VAADIN/themes/%s";
private static final String VAADIN_WIDGETSET_PATH_FORMAT = "/VAADIN/widgetsets/%s";

private String bundleVersion;

private String pathPrefix;

/**
* 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);
}

@Override
public void publishTheme(String themeName, HttpService httpService)
throws NamespaceException {
doPublish(themeName, VAADIN_THEME_ALIAS_FORMAT,
VAADIN_THEME_PATH_FORMAT, httpService);
}

private void doPublish(String resourceName, String aliasFormat,
String pathFormat, HttpService httpService)
throws NamespaceException {
String bundleVersionPrefix = String.format(NAMESPACE_PREFIX,
bundleVersion);

String resourcePath = String.format(pathFormat, resourceName);
String resourceAlias = String.format(aliasFormat, bundleVersionPrefix,
resourceName);

httpService.registerResources(resourceAlias, resourcePath, null);
String themeAlias = PathFormatHelper.getThemeAlias(themeName,
pathPrefix);
String themePath = PathFormatHelper.getThemePath(themeName);
httpService.registerResources(themeAlias, themePath, null);
}

@Override
public void publishResource(String resource, HttpService httpService)
throws NamespaceException {
doPublish(resource, VAADIN_ROOT_ALIAS_FORMAT, VAADIN_ROOT_FORMAT,
httpService);
String alias = PathFormatHelper.getRootResourceAlias(resource,
pathPrefix);
String path = PathFormatHelper.getRootResourcePath(resource);
httpService.registerResources(alias, path, null);
}

@Override
public void publishWidgetset(String widgetset, HttpService httpService)
throws NamespaceException {
doPublish(widgetset, VAADIN_WIDGETSET_ALIAS_FORMAT,
VAADIN_WIDGETSET_PATH_FORMAT, httpService);
String widgetsetAlias = PathFormatHelper.getWidgetsetAlias(widgetset,
pathPrefix);
String widgetsetPath = PathFormatHelper.getWidgetsetPath(widgetset);
httpService.registerResources(widgetsetAlias, widgetsetPath, null);
}

@Override

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

@@ -0,0 +1,175 @@
/*
* Copyright 2000-2016 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.io.IOException;
import java.net.URL;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceReference;
import org.osgi.service.component.annotations.Component;
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 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;

/**
* Tracks {@link OSGiVaadinWidgetset} and {@link OSGiVaadinTheme} registration
* and uses {@link HttpService} to register them.
*
* @author Vaadin Ltd.
*
* @since 8.1
*/
@Component(immediate = true)
public class VaadinResourceTrackerComponent {
private HttpService httpService;

private Map<Long, String> themeToAlias = Collections
.synchronizedMap(new LinkedHashMap<>());
private Map<Long, String> widgetsetToAlias = Collections
.synchronizedMap(new LinkedHashMap<>());

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

VaadinResourceService resourceService = OSGiVaadinResources
.getService();

try {
String pathPrefix = resourceService.getResourcePathPrefix();
Long serviceId = (Long) themeRef.getProperty(Constants.SERVICE_ID);

String alias = PathFormatHelper.getThemeAlias(theme.getName(),
pathPrefix);
String path = PathFormatHelper.getThemePath(theme.getName());

httpService.registerResources(alias, path,
new Delegate(httpService, bundle));

themeToAlias.put(serviceId, alias);
} finally {
context.ungetService(themeRef);
}
}

void unbindTheme(ServiceReference<OSGiVaadinTheme> themeRef) {
Long serviceId = (Long) themeRef.getProperty(Constants.SERVICE_ID);
String themeAlias = themeToAlias.remove(serviceId);
if (themeAlias != null && httpService != null) {
httpService.unregister(themeAlias);
}
}

@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();
try {
String pathPrefix = service.getResourcePathPrefix();

Long serviceId = (Long) widgetsetRef
.getProperty(Constants.SERVICE_ID);

String alias = PathFormatHelper
.getWidgetsetAlias(widgetset.getName(), pathPrefix);
String path = PathFormatHelper
.getWidgetsetPath(widgetset.getName());

httpService.registerResources(alias, path,
new Delegate(httpService, bundle));
widgetsetToAlias.put(serviceId, alias);
} finally {
context.ungetService(widgetsetRef);
}

}

void unbindWidgetset(ServiceReference<OSGiVaadinWidgetset> widgetsetRef) {
Long serviceId = (Long) widgetsetRef.getProperty(Constants.SERVICE_ID);
String widgetsetAlias = widgetsetToAlias.remove(serviceId);
if (widgetsetAlias != null && httpService != null) {
httpService.unregister(widgetsetAlias);
}
}

@Reference
void setHttpService(HttpService service) {
this.httpService = service;
}

void unsetHttpService(HttpService service) {
this.httpService = null;
}

static final class Delegate implements HttpContext {
private HttpContext context;
private Bundle bundle;

public Delegate(HttpService service, Bundle bundle) {
this.context = service.createDefaultHttpContext();
this.bundle = bundle;
}

@Override
public boolean handleSecurity(HttpServletRequest request,
HttpServletResponse response) throws IOException {
return context.handleSecurity(request, response);
}

@Override
public URL getResource(String name) {
return bundle.getResource(name);
}

@Override
public String getMimeType(String name) {
return context.getMimeType(name);
}

}
}

Loading…
Cancel
Save