PageRenderTime 47ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

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

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