PageRenderTime 46ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

/container/src/main/java/com/atlassian/plugin/remotable/container/Container.java

https://bitbucket.org/atlassian/remotable-plugins
Java | 369 lines | 333 code | 31 blank | 5 comment | 18 complexity | 358b81d74073eae8586f688310574d5f MD5 | raw file
Possible License(s): Apache-2.0
  1. package com.atlassian.plugin.remotable.container;
  2. import com.atlassian.activeobjects.spi.DataSourceProvider;
  3. import com.atlassian.event.api.EventPublisher;
  4. import com.atlassian.plugin.DefaultModuleDescriptorFactory;
  5. import com.atlassian.plugin.PluginAccessor;
  6. import com.atlassian.plugin.PluginController;
  7. import com.atlassian.plugin.event.PluginEventManager;
  8. import com.atlassian.plugin.event.impl.DefaultPluginEventManager;
  9. import com.atlassian.plugin.factories.PluginFactory;
  10. import com.atlassian.plugin.hostcontainer.DefaultHostContainer;
  11. import com.atlassian.plugin.loaders.*;
  12. import com.atlassian.plugin.loaders.classloading.Scanner;
  13. import com.atlassian.plugin.manager.DefaultPluginManager;
  14. import com.atlassian.plugin.manager.store.MemoryPluginPersistentStateStore;
  15. import com.atlassian.plugin.module.ClassPrefixModuleFactory;
  16. import com.atlassian.plugin.module.ModuleFactory;
  17. import com.atlassian.plugin.module.PrefixDelegatingModuleFactory;
  18. import com.atlassian.plugin.osgi.container.OsgiContainerManager;
  19. import com.atlassian.plugin.osgi.container.OsgiPersistentCache;
  20. import com.atlassian.plugin.osgi.container.felix.FelixOsgiContainerManager;
  21. import com.atlassian.plugin.osgi.container.impl.DefaultOsgiPersistentCache;
  22. import com.atlassian.plugin.osgi.container.impl.DefaultPackageScannerConfiguration;
  23. import com.atlassian.plugin.osgi.factory.OsgiBundleFactory;
  24. import com.atlassian.plugin.osgi.factory.OsgiPluginFactory;
  25. import com.atlassian.plugin.osgi.hostcomponents.ComponentRegistrar;
  26. import com.atlassian.plugin.osgi.hostcomponents.ContextClassLoaderStrategy;
  27. import com.atlassian.plugin.osgi.hostcomponents.HostComponentProvider;
  28. import com.atlassian.plugin.osgi.module.BeanPrefixModuleFactory;
  29. import com.atlassian.plugin.remotable.api.service.*;
  30. import com.atlassian.plugin.remotable.api.service.http.HostHttpClient;
  31. import com.atlassian.plugin.remotable.api.service.http.HostXmlRpcClient;
  32. import com.atlassian.plugin.remotable.api.service.http.bigpipe.BigPipeManager;
  33. import com.atlassian.plugin.remotable.api.service.license.RemotablePluginLicenseRetriever;
  34. import com.atlassian.plugin.remotable.container.ao.ContainerDataSourceProvider;
  35. import com.atlassian.plugin.remotable.container.internal.EnvironmentFactory;
  36. import com.atlassian.plugin.remotable.container.service.ContainerEmailSender;
  37. import com.atlassian.plugin.remotable.container.service.ContainerHttpResourceMounterServiceFactory;
  38. import com.atlassian.plugin.remotable.container.service.OAuthSignedRequestHandlerServiceFactory;
  39. import com.atlassian.plugin.remotable.container.service.event.ContainerEventPublisher;
  40. import com.atlassian.plugin.remotable.container.service.license.ContainerRemotablePluginLicenseRetriever;
  41. import com.atlassian.plugin.remotable.container.service.plugins.NoOpWebResourceManager;
  42. import com.atlassian.plugin.remotable.container.service.sal.*;
  43. import com.atlassian.plugin.remotable.container.util.ZipWriter;
  44. import com.atlassian.plugin.remotable.descriptor.DescriptorAccessor;
  45. import com.atlassian.plugin.remotable.descriptor.PolyglotDescriptorAccessor;
  46. import com.atlassian.plugin.remotable.host.common.descriptor.DescriptorPermissionsReader;
  47. import com.atlassian.plugin.remotable.host.common.service.RenderContextServiceFactory;
  48. import com.atlassian.plugin.remotable.host.common.service.RequestContextServiceFactory;
  49. import com.atlassian.plugin.remotable.host.common.service.http.HostHttpClientConsumerServiceFactory;
  50. import com.atlassian.plugin.remotable.host.common.service.http.HostHttpClientServiceFactory;
  51. import com.atlassian.plugin.remotable.host.common.service.http.HostXmlRpcClientServiceFactory;
  52. import com.atlassian.plugin.remotable.host.common.service.http.bigpipe.BigPipeServiceFactory;
  53. import com.atlassian.plugin.remotable.host.common.util.BundleLocator;
  54. import com.atlassian.plugin.remotable.host.common.util.BundleUtil;
  55. import com.atlassian.plugin.remotable.spi.host.HostProperties;
  56. import com.atlassian.plugin.remotable.spi.permission.PermissionsReader;
  57. import com.atlassian.plugin.webresource.WebResourceManager;
  58. import com.atlassian.sal.api.ApplicationProperties;
  59. import com.atlassian.sal.api.message.I18nResolver;
  60. import com.atlassian.sal.api.message.LocaleResolver;
  61. import com.atlassian.sal.api.pluginsettings.PluginSettingsFactory;
  62. import com.atlassian.sal.api.transaction.TransactionTemplate;
  63. import com.atlassian.sal.api.user.UserManager;
  64. import com.atlassian.sal.core.transaction.NoOpTransactionTemplate;
  65. import com.google.common.collect.ImmutableSet;
  66. import com.google.common.collect.Iterables;
  67. import org.osgi.framework.Bundle;
  68. import org.slf4j.Logger;
  69. import org.slf4j.LoggerFactory;
  70. import java.io.File;
  71. import java.io.FileNotFoundException;
  72. import java.io.IOException;
  73. import java.net.Socket;
  74. import java.net.URI;
  75. import java.net.UnknownHostException;
  76. import java.util.Arrays;
  77. import java.util.List;
  78. import java.util.Map;
  79. import java.util.Set;
  80. import static com.atlassian.plugin.remotable.container.util.AppRegister.registerApp;
  81. import static com.google.common.base.Preconditions.checkNotNull;
  82. import static com.google.common.collect.Lists.newArrayList;
  83. import static com.google.common.collect.Maps.newHashMap;
  84. import static com.google.common.collect.Sets.newHashSet;
  85. import static java.lang.Boolean.FALSE;
  86. import static java.util.Arrays.asList;
  87. import static java.util.Collections.singleton;
  88. public final class Container
  89. {
  90. private static final Logger log = LoggerFactory.getLogger(Container.class);
  91. public static final Set<URI> AUTOREGISTER_HOSTS = ImmutableSet.of(
  92. URI.create("http://localhost:1990/confluence"),
  93. URI.create("http://localhost:2990/jira"),
  94. URI.create("http://localhost:5990/refapp"));
  95. private final ContainerConfiguration configuration;
  96. private final HttpServer httpServer;
  97. private final DefaultPluginManager pluginManager;
  98. private DescriptorAccessor descriptorAccessor;
  99. private AppReloader appReloader;
  100. public Container(ContainerConfiguration configuration, HttpServer server) throws FileNotFoundException
  101. {
  102. this.configuration = checkNotNull(configuration);
  103. this.httpServer = checkNotNull(server);
  104. // todo: this should use the plugin api, but it doesn't allow setting of plugin loaders right now
  105. final DefaultPackageScannerConfiguration scannerConfig = new DefaultPackageScannerConfiguration(ContainerApplication.INSTANCE.getVersion());
  106. OsgiPersistentCache osgiCache = new DefaultOsgiPersistentCache(configuration.getCacheDirectory("osgi"));
  107. Map<Class<?>, Object> hostComponents = newHashMap();
  108. PluginEventManager pluginEventManager = new DefaultPluginEventManager();
  109. final OsgiContainerManager osgiContainerManager = new FelixOsgiContainerManager(
  110. osgiCache,
  111. scannerConfig,
  112. new ContainerHostComponentProvider(hostComponents),
  113. pluginEventManager);
  114. OsgiBundleFactory bundleFactory = new OsgiBundleFactory(osgiContainerManager, pluginEventManager);
  115. OsgiPluginFactory osgiPluginDeployer = new OsgiPluginFactory(
  116. PluginAccessor.Descriptor.FILENAME,
  117. ImmutableSet.of(ContainerApplication.INSTANCE),
  118. osgiCache,
  119. osgiContainerManager,
  120. pluginEventManager);
  121. final Scanner scanner;
  122. if (Iterables.isEmpty(configuration.getApplicationsPaths()))
  123. {
  124. File appDir = ContainerUtils.mkdirs("apps");
  125. scanner = new DirectoryScanner(appDir);
  126. }
  127. else
  128. {
  129. List<File> files = newArrayList();
  130. for (String app : configuration.getApplicationsPaths())
  131. {
  132. File appFile = new File(app);
  133. try
  134. {
  135. appFile = appFile.getCanonicalFile();
  136. }
  137. catch (IOException e)
  138. {
  139. throw new RuntimeException("Unable to determine canonical path", e);
  140. }
  141. if (!appFile.exists())
  142. {
  143. throw new FileNotFoundException("App '" + app + "' not found");
  144. }
  145. if (appFile.isDirectory())
  146. {
  147. System.setProperty("plugin.resource.directories", appFile.getAbsolutePath());
  148. descriptorAccessor = new PolyglotDescriptorAccessor(appFile);
  149. File appAsZip = zipAppDirectory(descriptorAccessor, appFile);
  150. files.add(appAsZip);
  151. }
  152. else
  153. {
  154. files.add(appFile);
  155. }
  156. }
  157. scanner = new FileListScanner(files);
  158. }
  159. final PluginLoader bundledPluginLoader = new BundledPluginLoader(
  160. this.getClass().getResource("/bundled-plugins-container.zip"),
  161. configuration.getCacheDirectory("bundled"),
  162. Arrays.<PluginFactory>asList(osgiPluginDeployer, bundleFactory),
  163. pluginEventManager);
  164. final PluginLoader appPluginLoader = new ScanningPluginLoader(scanner,
  165. Arrays.<PluginFactory>asList(osgiPluginDeployer, bundleFactory), pluginEventManager);
  166. final DefaultHostContainer hostContainer = new DefaultHostContainer();
  167. pluginManager = new DefaultPluginManager(
  168. new MemoryPluginPersistentStateStore(),
  169. asList(bundledPluginLoader, appPluginLoader),
  170. new DefaultModuleDescriptorFactory(hostContainer),
  171. pluginEventManager
  172. );
  173. ContainerDataSourceProvider dataSourceProvider = new ContainerDataSourceProvider(
  174. new ContainerApplicationProperties(null).getHomeDirectory());
  175. hostComponents.put(DataSourceProvider.class, dataSourceProvider);
  176. final JdbcPluginSettingsFactory pluginSettingsFactory = new JdbcPluginSettingsFactory(dataSourceProvider);
  177. hostComponents.put(PluginSettingsFactory.class, pluginSettingsFactory);
  178. final ContainerApplicationPropertiesServiceFactory applicationPropertiesServiceFactory = new ContainerApplicationPropertiesServiceFactory(server);
  179. hostComponents.put(ApplicationProperties.class, applicationPropertiesServiceFactory);
  180. hostComponents.put(EventPublisher.class, new ContainerEventPublisher());
  181. final EnvironmentFactory environmentFactory = new EnvironmentFactory(pluginSettingsFactory, pluginManager);
  182. final OAuthSignedRequestHandlerServiceFactory oAuthSignedRequestHandlerServiceFactory = new OAuthSignedRequestHandlerServiceFactory(environmentFactory, httpServer);
  183. final RequestContextServiceFactory requestContextServiceFactory = new RequestContextServiceFactory(oAuthSignedRequestHandlerServiceFactory);
  184. final WebResourceManager webReourceManager = new NoOpWebResourceManager();
  185. final BigPipeServiceFactory bigPipeServiceFactory = new BigPipeServiceFactory(webReourceManager, requestContextServiceFactory);
  186. final ContainerHttpResourceMounterServiceFactory containerHttpResourceMounterServiceFactory = new ContainerHttpResourceMounterServiceFactory(pluginManager, httpServer, oAuthSignedRequestHandlerServiceFactory, environmentFactory, requestContextServiceFactory, bigPipeServiceFactory);
  187. final HostHttpClientServiceFactory hostHttpClientServiceFactory = new HostHttpClientServiceFactory(requestContextServiceFactory, oAuthSignedRequestHandlerServiceFactory);
  188. final HostXmlRpcClientServiceFactory hostXmlRpcClientHostServiceFactory = new HostXmlRpcClientServiceFactory(hostHttpClientServiceFactory);
  189. final ContainerLocaleResolver localeResolver = new ContainerLocaleResolver();
  190. final ContainerI18nResolver i18nResolver = new ContainerI18nResolver(pluginManager, pluginEventManager, new ResourceBundleResolverImpl());
  191. final RenderContextServiceFactory renderContextServiceFactory = new RenderContextServiceFactory(requestContextServiceFactory, oAuthSignedRequestHandlerServiceFactory, localeResolver, i18nResolver, bigPipeServiceFactory);
  192. hostComponents.put(SignedRequestHandler.class, oAuthSignedRequestHandlerServiceFactory);
  193. hostComponents.put(HttpResourceMounter.class, containerHttpResourceMounterServiceFactory);
  194. hostComponents.put(PluginAccessor.class, pluginManager);
  195. hostComponents.put(PluginController.class, pluginManager);
  196. hostComponents.put(PluginEventManager.class, pluginEventManager);
  197. hostComponents.put(ModuleFactory.class, new PrefixDelegatingModuleFactory(ImmutableSet.of(new ClassPrefixModuleFactory(hostContainer), new BeanPrefixModuleFactory())));
  198. hostComponents.put(RequestContext.class, requestContextServiceFactory);
  199. hostComponents.put(HostHttpClient.class, hostHttpClientServiceFactory);
  200. hostComponents.put(HostXmlRpcClient.class, hostXmlRpcClientHostServiceFactory);
  201. hostComponents.put(EmailSender.class, new HostHttpClientConsumerServiceFactory<EmailSender>(hostHttpClientServiceFactory, ContainerEmailSender.class));
  202. hostComponents.put(RemotablePluginLicenseRetriever.class, new HostHttpClientConsumerServiceFactory<RemotablePluginLicenseRetriever>(hostHttpClientServiceFactory, ContainerRemotablePluginLicenseRetriever.class));
  203. hostComponents.put(LocaleResolver.class, localeResolver);
  204. hostComponents.put(I18nResolver.class, i18nResolver);
  205. hostComponents.put(WebResourceManager.class, webReourceManager);
  206. hostComponents.put(RenderContext.class, renderContextServiceFactory);
  207. hostComponents.put(BigPipeManager.class, bigPipeServiceFactory);
  208. hostComponents.put(TransactionTemplate.class, new NoOpTransactionTemplate());
  209. hostComponents.put(UserManager.class, new ContainerUserManagerServiceFactory(requestContextServiceFactory));
  210. hostComponents.put(PermissionsReader.class, createPermissionsReaderForProduct(osgiContainerManager, "container"));
  211. }
  212. private DescriptorPermissionsReader createPermissionsReaderForProduct(final OsgiContainerManager osgiContainerManager, final String productKey)
  213. {
  214. return new DescriptorPermissionsReader(new HostProperties()
  215. {
  216. @Override
  217. public String getKey()
  218. {
  219. return productKey;
  220. }
  221. }, new BundleLocator()
  222. {
  223. @Override
  224. public Bundle getBundle(String pluginKey)
  225. {
  226. return BundleUtil.findBundleForPlugin(osgiContainerManager.getBundles()[0].getBundleContext(), pluginKey);
  227. }
  228. });
  229. }
  230. private File zipAppDirectory(DescriptorAccessor descriptorAccessor, File appFile)
  231. {
  232. try
  233. {
  234. return ZipWriter.zipAppIntoPluginJar(descriptorAccessor, appFile);
  235. }
  236. catch (IOException e)
  237. {
  238. throw new IllegalArgumentException("Unable to zip up app: " + appFile.getPath(), e);
  239. }
  240. }
  241. public void start() throws Exception
  242. {
  243. pluginManager.init();
  244. httpServer.start();
  245. if (isDevMode())
  246. {
  247. Set<URI> foundHosts = findHostProducts();
  248. if (descriptorAccessor != null)
  249. {
  250. final String appKey = descriptorAccessor.getKey();
  251. appReloader = new AppReloader(descriptorAccessor, httpServer.getLocalMountBaseUrl(appKey), foundHosts);
  252. }
  253. else
  254. {
  255. for (URI host : foundHosts)
  256. {
  257. for (String appKey : httpServer.getContextNames())
  258. {
  259. registerApp(host, appKey, httpServer.getLocalMountBaseUrl(appKey));
  260. }
  261. }
  262. }
  263. }
  264. }
  265. private Set<URI> findHostProducts()
  266. {
  267. String hostBaseUrl = System.getProperty("hostBaseUrl");
  268. if (hostBaseUrl != null)
  269. {
  270. return singleton(URI.create(hostBaseUrl));
  271. }
  272. Set<URI> found = newHashSet();
  273. for (URI host : AUTOREGISTER_HOSTS)
  274. {
  275. Socket socket = null;
  276. try
  277. {
  278. log.debug("Scanning for host at " + host);
  279. socket = new Socket(host.getHost(), host.getPort());
  280. found.add(host);
  281. }
  282. catch (UnknownHostException e)
  283. {
  284. throw new RuntimeException("Not possible", e);
  285. }
  286. catch (IOException e)
  287. {
  288. // ignore, and try another
  289. }
  290. finally
  291. {
  292. try
  293. {
  294. if (socket != null)
  295. {
  296. socket.close();
  297. }
  298. }
  299. catch (IOException e)
  300. {
  301. // ignore
  302. }
  303. }
  304. }
  305. return found;
  306. }
  307. public void stop()
  308. {
  309. pluginManager.shutdown();
  310. if (appReloader != null)
  311. {
  312. appReloader.shutdown();
  313. }
  314. }
  315. public static boolean isDevMode()
  316. {
  317. return Boolean.valueOf(System.getProperty("atlassian.dev.mode", Boolean.toString(FALSE)))
  318. || Boolean.valueOf(System.getProperty("atlassian.ub.container.dev.mode", Boolean.toString(FALSE)));
  319. }
  320. private static class ContainerHostComponentProvider implements HostComponentProvider
  321. {
  322. private final Map<Class<?>, Object> requiredServices;
  323. public ContainerHostComponentProvider(Map<Class<?>, Object> requiredServices)
  324. {
  325. this.requiredServices = requiredServices;
  326. }
  327. public void provide(ComponentRegistrar registrar)
  328. {
  329. for (Map.Entry<Class<?>, Object> entry : requiredServices.entrySet())
  330. {
  331. // register with the plugin ccl strategy to avoid
  332. // the ccl-switching proxy that breaks with ServiceFactory
  333. registrar.register(entry.getKey()).forInstance(entry.getValue()).withContextClassLoaderStrategy(
  334. ContextClassLoaderStrategy.USE_PLUGIN);
  335. }
  336. }
  337. }
  338. }