You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

VaadinResourceTrackerComponent.java 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. /*
  2. * Copyright 2000-2018 Vaadin Ltd.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5. * use this file except in compliance with the License. You may obtain a copy of
  6. * the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. * License for the specific language governing permissions and limitations under
  14. * the License.
  15. */
  16. package com.vaadin.osgi.resources.impl;
  17. import java.io.IOException;
  18. import java.net.URL;
  19. import java.util.ArrayList;
  20. import java.util.Collections;
  21. import java.util.LinkedHashMap;
  22. import java.util.List;
  23. import java.util.Map;
  24. import javax.servlet.http.HttpServletRequest;
  25. import javax.servlet.http.HttpServletResponse;
  26. import org.osgi.framework.Bundle;
  27. import org.osgi.framework.BundleContext;
  28. import org.osgi.framework.Constants;
  29. import org.osgi.framework.ServiceReference;
  30. import org.osgi.framework.ServiceRegistration;
  31. import org.osgi.service.component.annotations.Activate;
  32. import org.osgi.service.component.annotations.Component;
  33. import org.osgi.service.component.annotations.Deactivate;
  34. import org.osgi.service.component.annotations.Reference;
  35. import org.osgi.service.component.annotations.ReferenceCardinality;
  36. import org.osgi.service.component.annotations.ReferencePolicy;
  37. import org.osgi.service.http.HttpContext;
  38. import org.osgi.service.http.HttpService;
  39. import org.osgi.service.http.NamespaceException;
  40. import com.vaadin.osgi.resources.OsgiVaadinContributor;
  41. import com.vaadin.osgi.resources.OsgiVaadinResource;
  42. import com.vaadin.osgi.resources.OsgiVaadinResources;
  43. import com.vaadin.osgi.resources.OsgiVaadinResources.ResourceBundleInactiveException;
  44. import com.vaadin.osgi.resources.OsgiVaadinTheme;
  45. import com.vaadin.osgi.resources.OsgiVaadinWidgetset;
  46. import com.vaadin.osgi.resources.VaadinResourceService;
  47. /**
  48. * Tracks {@link OsgiVaadinWidgetset} and {@link OsgiVaadinTheme} registration
  49. * and uses {@link HttpService} to register them.
  50. *
  51. * @author Vaadin Ltd.
  52. *
  53. * @since 8.1
  54. */
  55. @Component(immediate = true)
  56. public class VaadinResourceTrackerComponent {
  57. private final Map<Long, Delegate> resourceToRegistration = Collections
  58. .synchronizedMap(new LinkedHashMap<>());
  59. private final Map<Long, List<ServiceRegistration<? extends OsgiVaadinResource>>> contributorToRegistrations = Collections
  60. .synchronizedMap(new LinkedHashMap<>());
  61. private HttpService httpService;
  62. @Reference(cardinality = ReferenceCardinality.MULTIPLE, service = OsgiVaadinTheme.class, policy = ReferencePolicy.DYNAMIC)
  63. void bindTheme(ServiceReference<OsgiVaadinTheme> themeRef)
  64. throws ResourceBundleInactiveException {
  65. Bundle bundle = themeRef.getBundle();
  66. BundleContext context = bundle.getBundleContext();
  67. OsgiVaadinTheme theme = context.getService(themeRef);
  68. if (theme == null) {
  69. return;
  70. }
  71. VaadinResourceService resourceService = OsgiVaadinResources
  72. .getService();
  73. Long serviceId = (Long) themeRef.getProperty(Constants.SERVICE_ID);
  74. try {
  75. registerTheme(resourceService, bundle, serviceId, theme);
  76. } finally {
  77. context.ungetService(themeRef);
  78. }
  79. }
  80. void unbindTheme(ServiceReference<OsgiVaadinTheme> themeRef) {
  81. Long serviceId = (Long) themeRef.getProperty(Constants.SERVICE_ID);
  82. unregisterResource(serviceId);
  83. }
  84. @Reference(cardinality = ReferenceCardinality.MULTIPLE, service = OsgiVaadinWidgetset.class, policy = ReferencePolicy.DYNAMIC)
  85. void bindWidgetset(ServiceReference<OsgiVaadinWidgetset> widgetsetRef)
  86. throws ResourceBundleInactiveException {
  87. Bundle bundle = widgetsetRef.getBundle();
  88. BundleContext context = bundle.getBundleContext();
  89. OsgiVaadinWidgetset widgetset = context.getService(widgetsetRef);
  90. if (widgetset == null) {
  91. return;
  92. }
  93. VaadinResourceService service = OsgiVaadinResources.getService();
  94. Long serviceId = (Long) widgetsetRef.getProperty(Constants.SERVICE_ID);
  95. try {
  96. registerWidget(service, bundle, serviceId, widgetset);
  97. } finally {
  98. context.ungetService(widgetsetRef);
  99. }
  100. }
  101. void unbindWidgetset(ServiceReference<OsgiVaadinWidgetset> widgetsetRef) {
  102. Long serviceId = (Long) widgetsetRef.getProperty(Constants.SERVICE_ID);
  103. unregisterResource(serviceId);
  104. }
  105. @Reference(cardinality = ReferenceCardinality.MULTIPLE, service = OsgiVaadinResource.class, policy = ReferencePolicy.DYNAMIC)
  106. void bindResource(ServiceReference<OsgiVaadinResource> resourceRef)
  107. throws ResourceBundleInactiveException {
  108. Bundle bundle = resourceRef.getBundle();
  109. BundleContext context = bundle.getBundleContext();
  110. OsgiVaadinResource resource = context.getService(resourceRef);
  111. if (resource == null) {
  112. return;
  113. }
  114. VaadinResourceService service = OsgiVaadinResources.getService();
  115. Long serviceId = (Long) resourceRef.getProperty(Constants.SERVICE_ID);
  116. try {
  117. registerResource(service, bundle, serviceId, resource);
  118. } finally {
  119. context.ungetService(resourceRef);
  120. }
  121. }
  122. void unbindResource(ServiceReference<OsgiVaadinResource> resourceRef) {
  123. Long serviceId = (Long) resourceRef.getProperty(Constants.SERVICE_ID);
  124. unregisterResource(serviceId);
  125. }
  126. @Reference(cardinality = ReferenceCardinality.MULTIPLE, service = OsgiVaadinContributor.class, policy = ReferencePolicy.DYNAMIC)
  127. void bindContributor(ServiceReference<OsgiVaadinContributor> contributorRef)
  128. throws ResourceBundleInactiveException {
  129. Bundle bundle = contributorRef.getBundle();
  130. BundleContext context = bundle.getBundleContext();
  131. OsgiVaadinContributor contributor = context.getService(contributorRef);
  132. if (contributor == null) {
  133. return;
  134. }
  135. Long serviceId = (Long) contributorRef
  136. .getProperty(Constants.SERVICE_ID);
  137. List<OsgiVaadinResource> contributions = contributor.getContributions();
  138. List<ServiceRegistration<? extends OsgiVaadinResource>> registrations = new ArrayList<>(
  139. contributions.size());
  140. for (final OsgiVaadinResource r : contributions) {
  141. ServiceRegistration<? extends OsgiVaadinResource> reg;
  142. if (r instanceof OsgiVaadinTheme) {
  143. reg = context.registerService(OsgiVaadinTheme.class,
  144. (OsgiVaadinTheme) r, null);
  145. } else if (r instanceof OsgiVaadinWidgetset) {
  146. reg = context.registerService(OsgiVaadinWidgetset.class,
  147. (OsgiVaadinWidgetset) r, null);
  148. } else {
  149. reg = context.registerService(OsgiVaadinResource.class, r,
  150. null);
  151. }
  152. registrations.add(reg);
  153. }
  154. contributorToRegistrations.put(serviceId, registrations);
  155. }
  156. void unbindContributor(
  157. ServiceReference<OsgiVaadinContributor> contributorRef) {
  158. Long serviceId = (Long) contributorRef
  159. .getProperty(Constants.SERVICE_ID);
  160. List<ServiceRegistration<? extends OsgiVaadinResource>> registrations = contributorToRegistrations
  161. .get(serviceId);
  162. if (registrations != null) {
  163. for (ServiceRegistration<? extends OsgiVaadinResource> reg : registrations) {
  164. reg.unregister();
  165. }
  166. }
  167. }
  168. @Reference
  169. void setHttpService(HttpService service) {
  170. this.httpService = service;
  171. }
  172. void unsetHttpService(HttpService service) {
  173. this.httpService = null;
  174. }
  175. /**
  176. *
  177. * @throws NamespaceException
  178. * @since
  179. */
  180. @Activate
  181. protected void activate() throws NamespaceException {
  182. for(Delegate registration : resourceToRegistration.values()) {
  183. registration.init(httpService);
  184. httpService.registerResources(registration.alias, registration.path, registration);
  185. }
  186. }
  187. /**
  188. * @since
  189. */
  190. @Deactivate
  191. protected void deactivate() {
  192. for(final Delegate registration : resourceToRegistration.values()) {
  193. unregisterResource(registration);
  194. }
  195. for(List<ServiceRegistration<? extends OsgiVaadinResource>> registrations : contributorToRegistrations.values()) {
  196. for (ServiceRegistration<? extends OsgiVaadinResource> reg : registrations) {
  197. reg.unregister();
  198. }
  199. }
  200. resourceToRegistration.clear();
  201. contributorToRegistrations.clear();
  202. httpService = null;
  203. }
  204. private void registerTheme(VaadinResourceService resourceService,
  205. Bundle bundle, Long serviceId, OsgiVaadinTheme theme) {
  206. String pathPrefix = resourceService.getResourcePathPrefix();
  207. String alias = PathFormatHelper.getThemeAlias(theme.getName(),
  208. pathPrefix);
  209. String path = PathFormatHelper.getThemePath(theme.getName());
  210. registerResource(alias, path, bundle, serviceId);
  211. }
  212. private void registerWidget(VaadinResourceService resourceService,
  213. Bundle bundle, Long serviceId, OsgiVaadinWidgetset widgetset) {
  214. String pathPrefix = resourceService.getResourcePathPrefix();
  215. String alias = PathFormatHelper.getWidgetsetAlias(widgetset.getName(),
  216. pathPrefix);
  217. String path = PathFormatHelper.getWidgetsetPath(widgetset.getName());
  218. registerResource(alias, path, bundle, serviceId);
  219. }
  220. private void registerResource(VaadinResourceService resourceService,
  221. Bundle bundle, Long serviceId, OsgiVaadinResource resource) {
  222. String pathPrefix = resourceService.getResourcePathPrefix();
  223. String alias = PathFormatHelper.getRootResourceAlias(resource.getName(),
  224. pathPrefix);
  225. String path = PathFormatHelper.getRootResourcePath(resource.getName());
  226. registerResource(alias, path, bundle, serviceId);
  227. }
  228. private void registerResource(String alias, String path, Bundle bundle,
  229. Long serviceId) {
  230. resourceToRegistration.put(serviceId, new Delegate(alias, path, bundle));
  231. }
  232. private void unregisterResource(Long serviceId) {
  233. Delegate registration = resourceToRegistration.remove(serviceId);
  234. unregisterResource(registration);
  235. }
  236. private void unregisterResource(Delegate registration) {
  237. if (registration != null && httpService != null) {
  238. httpService.unregister(registration.alias);
  239. }
  240. }
  241. static final class Delegate implements HttpContext {
  242. private final String alias;
  243. private final String path;
  244. private final Bundle bundle;
  245. private volatile HttpContext context;
  246. public Delegate(String alias, String path, Bundle bundle) {
  247. this.alias = alias;
  248. this.path = path;
  249. this.bundle = bundle;
  250. }
  251. public void init(HttpService service) {
  252. context = service.createDefaultHttpContext();
  253. }
  254. @Override
  255. public boolean handleSecurity(HttpServletRequest request,
  256. HttpServletResponse response) throws IOException {
  257. return context.handleSecurity(request, response);
  258. }
  259. @Override
  260. public URL getResource(String name) {
  261. return bundle.getResource(name);
  262. }
  263. @Override
  264. public String getMimeType(String name) {
  265. return context.getMimeType(name);
  266. }
  267. }
  268. }