PageRenderTime 33ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 0ms

/refapp-core/src/main/java/com/atlassian/plugin/refimpl/plugins/RefappHostComponentProvider.java

https://bitbucket.org/atlassian/atlassian-refapp
Java | 148 lines | 116 code | 14 blank | 18 comment | 2 complexity | 4b332d4eb0e1037cb44c95525786838c MD5 | raw file
  1. package com.atlassian.plugin.refimpl.plugins;
  2. import com.atlassian.annotations.VisibleForTesting;
  3. import com.atlassian.beehive.ClusterLockService;
  4. import com.atlassian.event.api.EventPublisher;
  5. import com.atlassian.healthcheck.spi.HealthCheckWhitelist;
  6. import com.atlassian.plugin.ModuleDescriptorFactory;
  7. import com.atlassian.plugin.PluginController;
  8. import com.atlassian.plugin.SplitStartupPluginSystemLifecycle;
  9. import com.atlassian.plugin.metadata.PluginMetadataManager;
  10. import com.atlassian.plugin.module.ModuleFactory;
  11. import com.atlassian.plugin.osgi.external.ListableModuleDescriptorFactory;
  12. import com.atlassian.plugin.osgi.hostcomponents.ComponentRegistrar;
  13. import com.atlassian.plugin.osgi.hostcomponents.HostComponentProvider;
  14. import com.atlassian.plugin.schema.descriptor.DescribedModuleDescriptorFactory;
  15. import com.atlassian.plugin.servlet.ServletContextFactory;
  16. import com.atlassian.plugin.servlet.ServletModuleManager;
  17. import com.atlassian.plugin.webresource.PluginResourceLocator;
  18. import com.atlassian.plugin.webresource.ResourceBatchingConfiguration;
  19. import com.atlassian.plugin.webresource.WebResourceIntegration;
  20. import com.atlassian.plugin.webresource.WebResourceManager;
  21. import com.atlassian.plugin.webresource.WebResourceUrlProvider;
  22. import com.atlassian.plugin.webresource.prebake.PrebakeWebResourceAssemblerFactory;
  23. import com.atlassian.plugins.landlord.spi.LandlordRequests;
  24. import com.atlassian.refapp.api.ConnectionProvider;
  25. import com.atlassian.scheduler.SchedulerHistoryService;
  26. import com.atlassian.scheduler.SchedulerService;
  27. import com.atlassian.tenancy.api.TenantAccessor;
  28. import com.atlassian.tenancy.api.TenantContext;
  29. import com.atlassian.vcache.VCacheFactory;
  30. import com.atlassian.webresource.api.assembler.PageBuilderService;
  31. import com.atlassian.webresource.api.assembler.WebResourceAssemblerFactory;
  32. import org.springframework.beans.BeansException;
  33. import org.springframework.context.ApplicationContext;
  34. import org.springframework.context.ApplicationContextAware;
  35. import javax.annotation.Nonnull;
  36. import javax.annotation.ParametersAreNonnullByDefault;
  37. import java.util.LinkedHashMap;
  38. import java.util.List;
  39. import java.util.Map;
  40. import static java.util.Arrays.asList;
  41. import static java.util.Collections.unmodifiableList;
  42. import static java.util.Objects.requireNonNull;
  43. import static org.apache.commons.lang3.StringUtils.uncapitalize;
  44. /**
  45. * The set of services that Refapp exports to OSGi, for use by plugins.
  46. *
  47. * @since 5.4 was a map in ContainerManager; this is more type-safe and removes a lot of boilerplate
  48. */
  49. @ParametersAreNonnullByDefault
  50. public class RefappHostComponentProvider implements ApplicationContextAware, HostComponentProvider {
  51. /*
  52. These components will be made available to plugins via OSGi. To export a new type:
  53. (1) add its interface (not class) below
  54. (2) make sure the injected Spring ApplicationContext contains a (single?) bean of that type
  55. */
  56. @SuppressWarnings("deprecation") // not this class' fault if Refapp uses deprecated types
  57. private static final Class<?>[] SERVICE_TYPES_TO_EXPORT = {
  58. ClusterLockService.class,
  59. ConnectionProvider.class,
  60. DescribedModuleDescriptorFactory.class,
  61. EventPublisher.class,
  62. HealthCheckWhitelist.class,
  63. LandlordRequests.class,
  64. ListableModuleDescriptorFactory.class,
  65. ModuleDescriptorFactory.class,
  66. ModuleFactory.class,
  67. PageBuilderService.class,
  68. PluginController.class,
  69. PluginMetadataManager.class,
  70. PluginResourceLocator.class,
  71. PrebakeWebResourceAssemblerFactory.class,
  72. ResourceBatchingConfiguration.class,
  73. SchedulerHistoryService.class,
  74. SchedulerService.class,
  75. ServletContextFactory.class,
  76. ServletModuleManager.class,
  77. SplitStartupPluginSystemLifecycle.class,
  78. TenantAccessor.class,
  79. TenantContext.class,
  80. VCacheFactory.class,
  81. WebResourceAssemblerFactory.class,
  82. WebResourceIntegration.class,
  83. WebResourceManager.class,
  84. WebResourceUrlProvider.class
  85. };
  86. /**
  87. * Factory method for this class.
  88. *
  89. * @return a new instance
  90. */
  91. @Nonnull
  92. public static RefappHostComponentProvider getInstance() {
  93. return new RefappHostComponentProvider(asList(SERVICE_TYPES_TO_EXPORT));
  94. }
  95. private final List<Class<?>> serviceTypes;
  96. private ApplicationContext applicationContext;
  97. @VisibleForTesting
  98. RefappHostComponentProvider(final List<Class<?>> serviceTypes) {
  99. this.serviceTypes = unmodifiableList(serviceTypes);
  100. }
  101. @Override
  102. public void setApplicationContext(final ApplicationContext applicationContext) throws BeansException {
  103. this.applicationContext = requireNonNull(applicationContext);
  104. }
  105. @Override
  106. public void provide(final ComponentRegistrar registrar) {
  107. final Map<Class<?>, Object> instancesByType = new LinkedHashMap<>();
  108. //noinspection CollectionAddedToSelf yes, this is weird, but that's what ContainerManager did
  109. instancesByType.put(Map.class, instancesByType);
  110. serviceTypes.forEach(serviceType -> {
  111. final Object instance = registerService(registrar, serviceType);
  112. instancesByType.put(serviceType, instance);
  113. });
  114. // Presumably some plugin needs to iterate over a map of all the exported services, including the Map itself...
  115. registrar.register(Map.class).forInstance(instancesByType).withName(getBeanName(Map.class));
  116. }
  117. private Object registerService(final ComponentRegistrar registrar, final Class<?> serviceType) {
  118. checkIsInterface(serviceType);
  119. final Object instance = applicationContext.getBean(serviceType);
  120. final String name = getBeanName(serviceType);
  121. registrar.register(serviceType).forInstance(instance).withName(name);
  122. return instance;
  123. }
  124. private void checkIsInterface(final Class<?> serviceType) {
  125. // Remember that annotations are also interfaces
  126. if (serviceType.isAnnotation() || !serviceType.isInterface()) {
  127. throw new IllegalArgumentException(
  128. "Only interfaces can be exported to OSGi, not " + serviceType.getName());
  129. }
  130. }
  131. private static String getBeanName(final Class<?> serviceType) {
  132. return uncapitalize(serviceType.getSimpleName());
  133. }
  134. }