diff options
author | Mirjan Merruko <mirjan@vaadin.com> | 2017-04-06 15:21:29 +0300 |
---|---|---|
committer | Henri Sara <henri.sara@gmail.com> | 2017-04-25 15:01:06 +0300 |
commit | 5308eb76f463ededa059f8d82653b29ee813a92a (patch) | |
tree | f5f2d007b3878e4c5cb30024dd15373ccefe9d01 | |
parent | de7a16aee8544ea20be2f5ac9c9ed3d85b35a8a4 (diff) | |
download | vaadin-framework-5308eb76f463ededa059f8d82653b29ee813a92a.tar.gz vaadin-framework-5308eb76f463ededa059f8d82653b29ee813a92a.zip |
Convenience API for registering themes and widgetsets
6 files changed, 396 insertions, 35 deletions
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 8a0592fb58..c74e830b45 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 @@ -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) diff --git a/shared/src/main/java/com/vaadin/osgi/resources/OSGiVaadinTheme.java b/shared/src/main/java/com/vaadin/osgi/resources/OSGiVaadinTheme.java new file mode 100644 index 0000000000..9507dfe6f4 --- /dev/null +++ b/shared/src/main/java/com/vaadin/osgi/resources/OSGiVaadinTheme.java @@ -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(); +} diff --git a/shared/src/main/java/com/vaadin/osgi/resources/OSGiVaadinWidgetset.java b/shared/src/main/java/com/vaadin/osgi/resources/OSGiVaadinWidgetset.java new file mode 100644 index 0000000000..45bf0c4f6a --- /dev/null +++ b/shared/src/main/java/com/vaadin/osgi/resources/OSGiVaadinWidgetset.java @@ -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(); +} diff --git a/shared/src/main/java/com/vaadin/osgi/resources/impl/PathFormatHelper.java b/shared/src/main/java/com/vaadin/osgi/resources/impl/PathFormatHelper.java new file mode 100644 index 0000000000..e4f1fcaa10 --- /dev/null +++ b/shared/src/main/java/com/vaadin/osgi/resources/impl/PathFormatHelper.java @@ -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); + } +} 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 d33a56abfa..6bf6f9fa52 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 @@ -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 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 new file mode 100644 index 0000000000..0cf6aaeb18 --- /dev/null +++ b/shared/src/main/java/com/vaadin/osgi/resources/impl/VaadinResourceTrackerComponent.java @@ -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); + } + + } +} |