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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  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, NamespaceException {
  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, NamespaceException {
  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, NamespaceException {
  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. .remove(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 8.6.0
  179. */
  180. @Activate
  181. protected void activate() throws NamespaceException {
  182. for (Delegate registration : resourceToRegistration.values()) {
  183. registerResource(registration);
  184. }
  185. }
  186. /**
  187. * @since 8.6.0
  188. */
  189. @Deactivate
  190. protected void deactivate() {
  191. for (final Delegate registration : resourceToRegistration.values()) {
  192. unregisterResource(registration);
  193. }
  194. for (List<ServiceRegistration<? extends OsgiVaadinResource>> registrations : contributorToRegistrations
  195. .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. throws NamespaceException {
  207. String pathPrefix = resourceService.getResourcePathPrefix();
  208. String alias = PathFormatHelper.getThemeAlias(theme.getName(),
  209. pathPrefix);
  210. String path = PathFormatHelper.getThemePath(theme.getName());
  211. registerResource(alias, path, bundle, serviceId);
  212. }
  213. private void registerWidget(VaadinResourceService resourceService,
  214. Bundle bundle, Long serviceId, OsgiVaadinWidgetset widgetset)
  215. throws NamespaceException {
  216. String pathPrefix = resourceService.getResourcePathPrefix();
  217. String alias = PathFormatHelper.getWidgetsetAlias(widgetset.getName(),
  218. pathPrefix);
  219. String path = PathFormatHelper.getWidgetsetPath(widgetset.getName());
  220. registerResource(alias, path, bundle, serviceId);
  221. }
  222. private void registerResource(VaadinResourceService resourceService,
  223. Bundle bundle, Long serviceId, OsgiVaadinResource resource)
  224. throws NamespaceException {
  225. String pathPrefix = resourceService.getResourcePathPrefix();
  226. String alias = PathFormatHelper.getRootResourceAlias(resource.getName(),
  227. pathPrefix);
  228. String path = PathFormatHelper.getRootResourcePath(resource.getName());
  229. registerResource(alias, path, bundle, serviceId);
  230. }
  231. private void registerResource(String alias, String path, Bundle bundle,
  232. Long serviceId) throws NamespaceException {
  233. Delegate registration = new Delegate(alias, path, bundle);
  234. resourceToRegistration.put(serviceId, registration);
  235. registerResource(registration);
  236. }
  237. private void registerResource(Delegate registration)
  238. throws NamespaceException {
  239. if (this.httpService != null && !registration.isInitialized()) {
  240. registration.init(httpService);
  241. httpService.registerResources(registration.alias, registration.path,
  242. registration);
  243. }
  244. }
  245. private void unregisterResource(Long serviceId) {
  246. Delegate registration = resourceToRegistration.remove(serviceId);
  247. unregisterResource(registration);
  248. }
  249. private void unregisterResource(Delegate registration) {
  250. if (registration != null && httpService != null) {
  251. httpService.unregister(registration.alias);
  252. }
  253. }
  254. static final class Delegate implements HttpContext {
  255. private final String alias;
  256. private final String path;
  257. private final Bundle bundle;
  258. private volatile HttpContext context;
  259. public Delegate(String alias, String path, Bundle bundle) {
  260. this.alias = alias;
  261. this.path = path;
  262. this.bundle = bundle;
  263. }
  264. public void init(HttpService service) {
  265. context = service.createDefaultHttpContext();
  266. }
  267. public boolean isInitialized() {
  268. return context != null;
  269. }
  270. @Override
  271. public boolean handleSecurity(HttpServletRequest request,
  272. HttpServletResponse response) throws IOException {
  273. return context.handleSecurity(request, response);
  274. }
  275. @Override
  276. public URL getResource(String name) {
  277. return bundle.getResource(name);
  278. }
  279. @Override
  280. public String getMimeType(String name) {
  281. return context.getMimeType(name);
  282. }
  283. }
  284. }