PageRenderTime 55ms CodeModel.GetById 0ms RepoModel.GetById 0ms app.codeStats 0ms

/atlassian-plugins-osgi/src/test/java/it/com/atlassian/plugin/osgi/TestDynamicPluginModule.java

https://bitbucket.org/atlassian/atlassian-plugins
Java | 784 lines | 689 code | 91 blank | 4 comment | 9 complexity | 770b1fafc0517144430c9ebdd6e3ac84 MD5 | raw file
  1. package it.com.atlassian.plugin.osgi;
  2. import com.atlassian.plugin.DefaultModuleDescriptorFactory;
  3. import com.atlassian.plugin.JarPluginArtifact;
  4. import com.atlassian.plugin.ModuleDescriptor;
  5. import com.atlassian.plugin.PluginArtifact;
  6. import com.atlassian.plugin.descriptors.UnrecognisedModuleDescriptor;
  7. import com.atlassian.plugin.event.PluginEventListener;
  8. import com.atlassian.plugin.event.events.PluginModuleDisabledEvent;
  9. import com.atlassian.plugin.event.events.PluginModuleEnabledEvent;
  10. import com.atlassian.plugin.osgi.BasicWaitCondition;
  11. import com.atlassian.plugin.osgi.DummyModuleDescriptorWithKey;
  12. import com.atlassian.plugin.osgi.DummyStateAwareModuleDescriptorWithKey;
  13. import com.atlassian.plugin.osgi.EventTrackingModuleDescriptor;
  14. import com.atlassian.plugin.osgi.PluginInContainerTestBase;
  15. import com.atlassian.plugin.osgi.factory.OsgiPlugin;
  16. import com.atlassian.plugin.test.PluginJarBuilder;
  17. import com.atlassian.plugin.util.WaitUntil;
  18. import io.atlassian.fugue.Pair;
  19. import my.FooModule;
  20. import my.FooModuleDescriptor;
  21. import org.junit.Test;
  22. import org.osgi.framework.Bundle;
  23. import org.osgi.framework.BundleContext;
  24. import org.osgi.framework.ServiceReference;
  25. import org.osgi.framework.ServiceRegistration;
  26. import java.io.File;
  27. import java.io.IOException;
  28. import java.util.Collection;
  29. import java.util.HashSet;
  30. import java.util.List;
  31. import java.util.Set;
  32. import java.util.concurrent.atomic.AtomicInteger;
  33. import static org.hamcrest.MatcherAssert.assertThat;
  34. import static org.hamcrest.Matchers.equalTo;
  35. import static org.junit.Assert.assertEquals;
  36. import static org.junit.Assert.assertFalse;
  37. import static org.junit.Assert.assertNotNull;
  38. import static org.junit.Assert.assertNotSame;
  39. import static org.junit.Assert.assertTrue;
  40. public class TestDynamicPluginModule extends PluginInContainerTestBase {
  41. @Test
  42. public void testDynamicPluginModule() throws Exception {
  43. initPluginManager(registrar -> {});
  44. final File pluginJar = new PluginJarBuilder("pluginType")
  45. .addFormattedResource("atlassian-plugin.xml",
  46. "<atlassian-plugin name='Test' key='test.plugin.module' pluginsVersion='2'>",
  47. " <plugin-info>",
  48. " <version>1.0</version>",
  49. " </plugin-info>",
  50. " <component key='factory' class='foo.MyModuleDescriptorFactory' public='true'>",
  51. " <interface>com.atlassian.plugin.ModuleDescriptorFactory</interface>",
  52. " </component>",
  53. "</atlassian-plugin>")
  54. .addFormattedJava(getMyModuleDescriptorClass().left(), getMyModuleDescriptorClass().right())
  55. .addFormattedJava("foo.MyModuleDescriptorFactory",
  56. "package foo;",
  57. "public class MyModuleDescriptorFactory extends com.atlassian.plugin.DefaultModuleDescriptorFactory {",
  58. " public MyModuleDescriptorFactory() {",
  59. " super(new com.atlassian.plugin.hostcontainer.DefaultHostContainer());",
  60. " addModuleDescriptor('foo', MyModuleDescriptor.class);",
  61. " }",
  62. "}")
  63. .build();
  64. final File pluginJar2 = buildDynamicModuleClientJar();
  65. pluginController.installPlugins(new JarPluginArtifact(pluginJar));
  66. pluginController.installPlugins(new JarPluginArtifact(pluginJar2));
  67. final Collection<ModuleDescriptor<?>> descriptors = pluginAccessor.getPlugin("test.plugin").getModuleDescriptors();
  68. assertEquals(1, descriptors.size());
  69. final ModuleDescriptor<?> descriptor = descriptors.iterator()
  70. .next();
  71. assertEquals("MyModuleDescriptor", descriptor.getClass().getSimpleName());
  72. }
  73. @Test
  74. public void testDynamicPluginModuleUsingModuleTypeDescriptorWithReinstall() throws Exception {
  75. initPluginManager();
  76. final File pluginJar = new PluginJarBuilder("pluginType")
  77. .addFormattedResource("atlassian-plugin.xml",
  78. "<atlassian-plugin name='Test' key='test.plugin.module' pluginsVersion='2'>",
  79. " <plugin-info>",
  80. " <version>1.0</version>",
  81. " </plugin-info>",
  82. " <module-type key='foo' class='foo.MyModuleDescriptor' />",
  83. "</atlassian-plugin>")
  84. .addFormattedJava(getMyModuleDescriptorClass().left(), getMyModuleDescriptorClass().right())
  85. .build();
  86. final File pluginJar2 = buildDynamicModuleClientJar();
  87. pluginController.installPlugins(new JarPluginArtifact(pluginJar));
  88. pluginController.installPlugins(new JarPluginArtifact(pluginJar2));
  89. assertTrue(waitForDynamicModuleEnabled());
  90. // uninstall the module - the test plugin modules should revert back to Unrecognised
  91. pluginController.uninstall(pluginAccessor.getPlugin("test.plugin.module"));
  92. WaitUntil.invoke(new BasicWaitCondition() {
  93. public boolean isFinished() {
  94. ModuleDescriptor<?> descriptor = pluginAccessor.getPlugin("test.plugin")
  95. .getModuleDescriptors()
  96. .iterator()
  97. .next();
  98. boolean enabled = pluginAccessor.isPluginModuleEnabled(descriptor.getCompleteKey());
  99. return descriptor
  100. .getClass()
  101. .getSimpleName()
  102. .equals("UnrecognisedModuleDescriptor")
  103. && !enabled;
  104. }
  105. });
  106. // reinstall the module - the test plugin modules should be correct again
  107. pluginController.installPlugins(new JarPluginArtifact(pluginJar));
  108. assertTrue(waitForDynamicModuleEnabled());
  109. }
  110. @Test
  111. public void testDynamicPluginModuleUsingModuleTypeDescriptorWithImmediateReinstall() throws Exception {
  112. initPluginManager();
  113. final File pluginJar = new PluginJarBuilder("pluginType")
  114. .addFormattedResource("atlassian-plugin.xml",
  115. "<atlassian-plugin name='Test' key='test.plugin.module' pluginsVersion='2'>",
  116. " <plugin-info>",
  117. " <version>1.0</version>",
  118. " </plugin-info>",
  119. " <module-type key='foo' class='foo.MyModuleDescriptor' />",
  120. "</atlassian-plugin>")
  121. .addFormattedJava(getMyModuleDescriptorClass().left(), getMyModuleDescriptorClass().right())
  122. .build();
  123. final File pluginJar2 = buildDynamicModuleClientJar();
  124. pluginController.installPlugins(new JarPluginArtifact(pluginJar));
  125. pluginController.installPlugins(new JarPluginArtifact(pluginJar2));
  126. assertTrue(waitForDynamicModuleEnabled());
  127. PluginModuleDisabledListener disabledListener = new PluginModuleDisabledListener("dum2");
  128. PluginModuleEnabledListener enabledListener = new PluginModuleEnabledListener("dum2");
  129. pluginEventManager.register(disabledListener);
  130. pluginEventManager.register(enabledListener);
  131. // reinstall the module - the test plugin modules should be correct again
  132. pluginController.installPlugins(new JarPluginArtifact(pluginJar));
  133. assertTrue(waitForDynamicModuleEnabled());
  134. assertEquals(1, enabledListener.called);
  135. assertEquals(1, disabledListener.called);
  136. }
  137. @Test
  138. public void testDynamicPluginModuleUsingModuleTypeDescriptorWithImmediateReinstallOfBoth() throws Exception {
  139. initPluginManager();
  140. final File pluginJar = new PluginJarBuilder("pluginType")
  141. .addFormattedResource("atlassian-plugin.xml",
  142. "<atlassian-plugin name='Test' key='test.plugin.module' pluginsVersion='2'>",
  143. " <plugin-info>",
  144. " <version>1.0</version>",
  145. " </plugin-info>",
  146. " <module-type key='foo' class='foo.MyModuleDescriptor' />",
  147. "</atlassian-plugin>")
  148. .addFormattedJava(getMyModuleDescriptorClass().left(), getMyModuleDescriptorClass().right())
  149. .build();
  150. final File pluginJar2 = buildDynamicModuleClientJar();
  151. pluginController.installPlugins(new JarPluginArtifact(pluginJar));
  152. pluginController.installPlugins(new JarPluginArtifact(pluginJar2));
  153. assertTrue(waitForDynamicModuleEnabled());
  154. PluginModuleDisabledListener disabledListener = new PluginModuleDisabledListener("dum2");
  155. PluginModuleEnabledListener enabledListener = new PluginModuleEnabledListener("dum2");
  156. pluginEventManager.register(disabledListener);
  157. pluginEventManager.register(enabledListener);
  158. // reinstall the module - the test plugin modules should be correct again
  159. pluginController.installPlugins(new JarPluginArtifact(pluginJar2), new JarPluginArtifact(pluginJar));
  160. assertTrue(waitForDynamicModuleEnabled());
  161. assertEquals(pluginAccessor.getPluginModule("test.plugin:dum2").getClass(), pluginAccessor.getPlugin("test.plugin.module").loadClass("foo.MyModuleDescriptor", null));
  162. assertEquals(1, enabledListener.called);
  163. assertEquals(1, disabledListener.called);
  164. }
  165. private File buildDynamicModuleClientJar() throws IOException {
  166. return new PluginJarBuilder("fooUser")
  167. .addFormattedResource("atlassian-plugin.xml",
  168. "<atlassian-plugin name='Test 2' key='test.plugin' pluginsVersion='2'>",
  169. " <plugin-info>",
  170. " <version>1.0</version>",
  171. " </plugin-info>",
  172. " <foo key='dum2'/>",
  173. "</atlassian-plugin>")
  174. .build();
  175. }
  176. private boolean waitForDynamicModuleEnabled() {
  177. return WaitUntil.invoke(new BasicWaitCondition() {
  178. public boolean isFinished() {
  179. return pluginAccessor.getPlugin("test.plugin").getModuleDescriptors().iterator().next().getClass().getSimpleName().equals("MyModuleDescriptor");
  180. }
  181. });
  182. }
  183. @Test
  184. public void testUpgradeOfBundledPluginWithDynamicModule() throws Exception {
  185. final File pluginJar = new PluginJarBuilder("pluginType")
  186. .addFormattedResource("atlassian-plugin.xml",
  187. "<atlassian-plugin name='Test' key='test.plugin.module' pluginsVersion='2'>",
  188. " <plugin-info>",
  189. " <version>1.0</version>",
  190. " </plugin-info>",
  191. " <module-type key='foo' class='foo.MyModuleDescriptor' />",
  192. "</atlassian-plugin>")
  193. .addFormattedJava(getMyModuleDescriptorClass().left(), getMyModuleDescriptorClass().right())
  194. .build();
  195. final DefaultModuleDescriptorFactory factory = new DefaultModuleDescriptorFactory(hostContainer);
  196. initBundlingPluginManager(factory, pluginJar);
  197. assertEquals(1, pluginAccessor.getEnabledPlugins().size());
  198. final File pluginClientOld = buildDynamicModuleClientJar();
  199. final File pluginClientNew = new PluginJarBuilder("fooUser")
  200. .addFormattedResource("atlassian-plugin.xml",
  201. "<atlassian-plugin name='Test 2' key='test.plugin' pluginsVersion='2'>",
  202. " <plugin-info>",
  203. " <version>2.0</version>",
  204. " </plugin-info>",
  205. " <foo key='dum2'/>",
  206. "</atlassian-plugin>")
  207. .build();
  208. pluginController.installPlugins(new JarPluginArtifact(pluginClientOld), new JarPluginArtifact(pluginClientNew));
  209. assertTrue(waitForDynamicModuleEnabled());
  210. assertEquals(2, pluginAccessor.getEnabledPlugins().size());
  211. assertEquals("2.0", pluginAccessor.getPlugin("test.plugin").getPluginInformation().getVersion());
  212. }
  213. @Test
  214. public void testDynamicPluginModuleNotLinkToAllPlugins() throws Exception {
  215. new PluginJarBuilder("pluginType")
  216. .addFormattedResource("atlassian-plugin.xml",
  217. "<atlassian-plugin name='Test' key='test.plugin.module' pluginsVersion='2'>",
  218. " <plugin-info>",
  219. " <version>1.0</version>",
  220. " </plugin-info>",
  221. " <module-type key='foo' class='foo.MyModuleDescriptor'/>",
  222. "</atlassian-plugin>")
  223. .addFormattedJava(getMyModuleDescriptorClass().left(), getMyModuleDescriptorClass().right())
  224. .build(pluginsDir);
  225. new PluginJarBuilder("fooUser")
  226. .addFormattedResource("atlassian-plugin.xml",
  227. "<atlassian-plugin name='Test 2' key='test.plugin' pluginsVersion='2'>",
  228. " <plugin-info>",
  229. " <version>1.0</version>",
  230. " </plugin-info>",
  231. " <foo key='dum2'/>",
  232. "</atlassian-plugin>")
  233. .build(pluginsDir);
  234. new PluginJarBuilder("foootherUser")
  235. .addPluginInformation("unusing.plugin", "Unusing plugin", "1.0")
  236. .build(pluginsDir);
  237. initPluginManager(registrar -> {});
  238. assertEquals("MyModuleDescriptor", pluginAccessor.getPlugin("test.plugin").getModuleDescriptor("dum2").getClass().getSimpleName());
  239. Set<String> deps = findDependentBundles(((OsgiPlugin) pluginAccessor.getPlugin("test.plugin.module")).getBundle());
  240. assertTrue(deps.contains("test.plugin"));
  241. assertFalse(deps.contains("unusing.plugin"));
  242. }
  243. private Set<String> findDependentBundles(Bundle bundle) {
  244. Set<String> deps = new HashSet<>();
  245. final ServiceReference[] registeredServices = bundle.getRegisteredServices();
  246. if (registeredServices == null) {
  247. return deps;
  248. }
  249. for (final ServiceReference serviceReference : registeredServices) {
  250. final Bundle[] usingBundles = serviceReference.getUsingBundles();
  251. if (usingBundles == null) {
  252. continue;
  253. }
  254. for (final Bundle usingBundle : usingBundles) {
  255. deps.add(usingBundle.getSymbolicName());
  256. }
  257. }
  258. return deps;
  259. }
  260. @Test
  261. public void testDynamicPluginModuleUsingModuleTypeDescriptor() throws Exception {
  262. initPluginManager(registrar -> {});
  263. final File pluginJar = new PluginJarBuilder("pluginType")
  264. .addFormattedResource("atlassian-plugin.xml",
  265. "<atlassian-plugin name='Test' key='test.plugin.module' pluginsVersion='2'>",
  266. " <plugin-info>",
  267. " <version>1.0</version>",
  268. " </plugin-info>",
  269. " <module-type key='foo' class='foo.MyModuleDescriptor' />",
  270. "</atlassian-plugin>")
  271. .addFormattedJava(getMyModuleDescriptorClass().left(), getMyModuleDescriptorClass().right())
  272. .build();
  273. final File pluginJar2 = buildDynamicModuleClientJar();
  274. pluginController.installPlugins(new JarPluginArtifact(pluginJar));
  275. pluginController.installPlugins(new JarPluginArtifact(pluginJar2));
  276. WaitUntil.invoke(new BasicWaitCondition() {
  277. public boolean isFinished() {
  278. return pluginAccessor.getPlugin("test.plugin")
  279. .getModuleDescriptor("dum2")
  280. .getClass()
  281. .getSimpleName()
  282. .equals("MyModuleDescriptor");
  283. }
  284. });
  285. final Collection<ModuleDescriptor<?>> descriptors = pluginAccessor.getPlugin("test.plugin")
  286. .getModuleDescriptors();
  287. assertEquals(1, descriptors.size());
  288. final ModuleDescriptor<?> descriptor = descriptors.iterator()
  289. .next();
  290. assertEquals("MyModuleDescriptor", descriptor.getClass().getSimpleName());
  291. }
  292. @Test
  293. public void testDynamicPluginModuleWithClientAndHostEnabledSimultaneouslyCheckEvents() throws Exception {
  294. initPluginManager();
  295. final File pluginJar = new PluginJarBuilder("pluginType")
  296. .addFormattedResource("atlassian-plugin.xml",
  297. "<atlassian-plugin name='Test' key='host' pluginsVersion='2'>",
  298. " <plugin-info>",
  299. " <version>1.0</version>",
  300. " </plugin-info>",
  301. " <component key='foo' class='foo.MyModuleDescriptorFactory' public='true'>",
  302. " <interface>com.atlassian.plugin.osgi.external.ListableModuleDescriptorFactory</interface>",
  303. " </component>",
  304. "</atlassian-plugin>")
  305. .addFormattedJava("foo.MyModuleDescriptorFactory",
  306. "package foo;",
  307. "public class MyModuleDescriptorFactory extends com.atlassian.plugin.DefaultModuleDescriptorFactory ",
  308. " implements com.atlassian.plugin.osgi.external.ListableModuleDescriptorFactory{",
  309. " public MyModuleDescriptorFactory() throws Exception{",
  310. " super(new com.atlassian.plugin.hostcontainer.DefaultHostContainer());",
  311. " Thread.sleep(500);",
  312. " System.out.println('starting descriptor factory');",
  313. " addModuleDescriptor('foo', com.atlassian.plugin.osgi.EventTrackingModuleDescriptor.class);",
  314. " }",
  315. " public Iterable getModuleDescriptorKeys() {",
  316. " return java.util.Collections.singleton('foo');",
  317. " }",
  318. " public java.util.Set getModuleDescriptorClasses() {",
  319. " return java.util.Collections.singleton(com.atlassian.plugin.osgi.EventTrackingModuleDescriptor.class);",
  320. " }",
  321. "}")
  322. .build();
  323. final File pluginJar2 = new PluginJarBuilder("fooUser")
  324. .addFormattedResource("atlassian-plugin.xml",
  325. "<atlassian-plugin name='Test 2' key='client' pluginsVersion='2'>",
  326. " <plugin-info>",
  327. " <version>1.0</version>",
  328. " </plugin-info>",
  329. " <foo key='dum2'/>",
  330. "</atlassian-plugin>")
  331. .build();
  332. pluginController.installPlugins(new JarPluginArtifact(pluginJar), new JarPluginArtifact(pluginJar2));
  333. WaitUntil.invoke(new BasicWaitCondition() {
  334. public boolean isFinished() {
  335. return pluginAccessor.getPlugin("client").getModuleDescriptor("dum2").getClass().getSimpleName().equals("EventTrackingModuleDescriptor");
  336. }
  337. });
  338. EventTrackingModuleDescriptor desc = (EventTrackingModuleDescriptor) pluginAccessor.getPlugin("client").getModuleDescriptor("dum2");
  339. assertEquals(1, desc.getEnabledCount());
  340. }
  341. @Test
  342. public void testDynamicPluginModuleUsingModuleTypeDescriptorAndComponentInjection() throws Exception {
  343. initPluginManager(registrar -> {});
  344. final File pluginJar = new PluginJarBuilder("pluginType")
  345. .addFormattedResource("atlassian-plugin.xml",
  346. "<atlassian-plugin name='Test' key='test.plugin.module' pluginsVersion='2'>",
  347. " <plugin-info>",
  348. " <version>1.0</version>",
  349. " </plugin-info>",
  350. " <component key='comp' class='foo.MyComponent' />",
  351. " <module-type key='foo' class='foo.MyModuleDescriptor' />",
  352. "</atlassian-plugin>")
  353. .addFormattedJava("foo.MyComponent", "package foo;", "public class MyComponent {", "}")
  354. .addFormattedJava(getMyModuleDescriptorClass().left(), getMyModuleDescriptorClass().right())
  355. .build();
  356. final File pluginJar2 = buildDynamicModuleClientJar();
  357. pluginController.installPlugins(new JarPluginArtifact(pluginJar));
  358. pluginController.installPlugins(new JarPluginArtifact(pluginJar2));
  359. assertTrue(waitForDynamicModuleEnabled());
  360. final Collection<ModuleDescriptor<?>> descriptors = pluginAccessor.getPlugin("test.plugin")
  361. .getModuleDescriptors();
  362. assertEquals(1, descriptors.size());
  363. final ModuleDescriptor<?> descriptor = descriptors.iterator()
  364. .next();
  365. assertEquals("MyModuleDescriptor", descriptor.getClass().getSimpleName());
  366. }
  367. @Test
  368. public void testDynamicPluginModuleUsingModuleTypeDescriptorAfterTheFact() throws Exception {
  369. initPluginManager(registrar -> {});
  370. final File pluginJar = new PluginJarBuilder("pluginType")
  371. .addFormattedResource("atlassian-plugin.xml",
  372. "<atlassian-plugin name='Test' key='test.plugin.module' pluginsVersion='2'>",
  373. " <plugin-info>",
  374. " <version>1.0</version>",
  375. " </plugin-info>",
  376. " <module-type key='foo' class='foo.MyModuleDescriptor' />",
  377. "</atlassian-plugin>")
  378. .addFormattedJava(getMyModuleDescriptorClass().left(), getMyModuleDescriptorClass().right())
  379. .build();
  380. final File pluginJar2 = buildDynamicModuleClientJar();
  381. pluginController.installPlugins(new JarPluginArtifact(pluginJar2));
  382. pluginController.installPlugins(new JarPluginArtifact(pluginJar));
  383. waitForDynamicModuleEnabled();
  384. Collection<ModuleDescriptor<?>> descriptors = pluginAccessor.getPlugin("test.plugin")
  385. .getModuleDescriptors();
  386. assertEquals(1, descriptors.size());
  387. ModuleDescriptor<?> descriptor = descriptors.iterator()
  388. .next();
  389. assertEquals("MyModuleDescriptor", descriptor.getClass().getSimpleName());
  390. pluginController.uninstall(pluginAccessor.getPlugin("test.plugin.module"));
  391. WaitUntil.invoke(new BasicWaitCondition() {
  392. public boolean isFinished() {
  393. return pluginAccessor.getPlugin("test.plugin")
  394. .getModuleDescriptors()
  395. .iterator()
  396. .next()
  397. .getClass()
  398. .getSimpleName()
  399. .equals("UnrecognisedModuleDescriptor");
  400. }
  401. });
  402. descriptors = pluginAccessor.getPlugin("test.plugin")
  403. .getModuleDescriptors();
  404. assertEquals(1, descriptors.size());
  405. descriptor = descriptors.iterator()
  406. .next();
  407. assertEquals("UnrecognisedModuleDescriptor", descriptor.getClass().getSimpleName());
  408. pluginController.installPlugins(new JarPluginArtifact(pluginJar));
  409. descriptors = pluginAccessor.getPlugin("test.plugin")
  410. .getModuleDescriptors();
  411. assertEquals(1, descriptors.size());
  412. descriptor = descriptors.iterator()
  413. .next();
  414. assertEquals("MyModuleDescriptor", descriptor.getClass().getSimpleName());
  415. }
  416. @Test
  417. public void testDynamicPluginModuleUsingModuleTypeDescriptorAfterTheFactWithException() throws Exception {
  418. initPluginManager(registrar -> {});
  419. final File pluginJar = new PluginJarBuilder("pluginType")
  420. .addFormattedResource("atlassian-plugin.xml",
  421. "<atlassian-plugin name='Test' key='test.plugin.module' pluginsVersion='2'>",
  422. " <plugin-info>",
  423. " <version>1.0</version>",
  424. " </plugin-info>",
  425. " <module-type key='foo' class='foo.MyModuleDescriptor' />",
  426. "</atlassian-plugin>")
  427. .addFormattedJava("foo.MyModuleDescriptor",
  428. "package foo;",
  429. "import com.atlassian.plugin.module.ModuleFactory;",
  430. "public class MyModuleDescriptor extends com.atlassian.plugin.descriptors.AbstractModuleDescriptor {",
  431. " public MyModuleDescriptor() {",
  432. " super(ModuleFactory.LEGACY_MODULE_FACTORY);",
  433. " throw new RuntimeException('error loading module');",
  434. " }",
  435. " public Object getModule(){return null;}",
  436. "}")
  437. .build();
  438. final File pluginJar2 = buildDynamicModuleClientJar();
  439. pluginController.installPlugins(new JarPluginArtifact(pluginJar2));
  440. pluginController.installPlugins(new JarPluginArtifact(pluginJar));
  441. assertTrue(WaitUntil.invoke(new BasicWaitCondition() {
  442. public boolean isFinished() {
  443. UnrecognisedModuleDescriptor des = (UnrecognisedModuleDescriptor) pluginAccessor.getPlugin("test.plugin").getModuleDescriptor("dum2");
  444. return des.getErrorText().contains("error loading module");
  445. }
  446. }));
  447. }
  448. @Test
  449. public void testDynamicPluginModuleUsingModuleTypeDescriptorInSamePlugin() throws Exception {
  450. initPluginManager(registrar -> {});
  451. final File pluginJar = new PluginJarBuilder("pluginType")
  452. .addFormattedResource("atlassian-plugin.xml",
  453. "<atlassian-plugin name='Test' key='test.plugin' pluginsVersion='2'>",
  454. " <plugin-info>",
  455. " <version>1.0</version>",
  456. " </plugin-info>",
  457. " <module-type key='foo' class='foo.MyModuleDescriptor' />",
  458. " <foo key='dum2' />",
  459. "</atlassian-plugin>")
  460. .addFormattedJava(getMyModuleDescriptorClass().left(), getMyModuleDescriptorClass().right())
  461. .build();
  462. pluginController.installPlugins(new JarPluginArtifact(pluginJar));
  463. WaitUntil.invoke(new BasicWaitCondition() {
  464. public boolean isFinished() {
  465. return pluginAccessor.getPlugin("test.plugin")
  466. .getModuleDescriptor("dum2")
  467. .getClass()
  468. .getSimpleName()
  469. .equals("MyModuleDescriptor");
  470. }
  471. });
  472. final Collection<ModuleDescriptor<?>> descriptors = pluginAccessor.getPlugin("test.plugin")
  473. .getModuleDescriptors();
  474. assertEquals(2, descriptors.size());
  475. final ModuleDescriptor<?> descriptor = pluginAccessor.getPlugin("test.plugin")
  476. .getModuleDescriptor("dum2");
  477. assertEquals("MyModuleDescriptor", descriptor.getClass().getSimpleName());
  478. }
  479. @Test
  480. public void testDynamicPluginModuleUsingModuleTypeDescriptorInSamePluginWithRestart() throws Exception {
  481. initPluginManager();
  482. final File pluginJar = new PluginJarBuilder("pluginType")
  483. .addFormattedResource("atlassian-plugin.xml",
  484. "<atlassian-plugin name='Test' key='test.plugin' pluginsVersion='2'>",
  485. " <plugin-info>",
  486. " <version>1.0</version>",
  487. " </plugin-info>",
  488. " <module-type key='foo' class='foo.MyModuleDescriptor' />",
  489. " <foo key='dum2' />",
  490. "</atlassian-plugin>")
  491. .addFormattedJava(getMyModuleDescriptorClass().left(), getMyModuleDescriptorClass().right())
  492. .build();
  493. pluginController.installPlugins(new JarPluginArtifact(pluginJar));
  494. WaitUntil.invoke(new BasicWaitCondition() {
  495. public boolean isFinished() {
  496. return pluginAccessor.getPlugin("test.plugin")
  497. .getModuleDescriptor("dum2")
  498. .getClass()
  499. .getSimpleName()
  500. .equals("MyModuleDescriptor");
  501. }
  502. });
  503. Collection<ModuleDescriptor<?>> descriptors = pluginAccessor.getPlugin("test.plugin")
  504. .getModuleDescriptors();
  505. assertEquals(2, descriptors.size());
  506. ModuleDescriptor<?> descriptor = pluginAccessor.getPlugin("test.plugin")
  507. .getModuleDescriptor("dum2");
  508. assertEquals("MyModuleDescriptor", descriptor.getClass().getSimpleName());
  509. PluginModuleDisabledListener disabledListener = new PluginModuleDisabledListener("dum2");
  510. PluginModuleEnabledListener enabledListener = new PluginModuleEnabledListener("dum2");
  511. pluginEventManager.register(disabledListener);
  512. pluginEventManager.register(enabledListener);
  513. pluginController.installPlugins(new JarPluginArtifact(pluginJar));
  514. WaitUntil.invoke(new BasicWaitCondition() {
  515. public boolean isFinished() {
  516. return pluginAccessor.getPlugin("test.plugin")
  517. .getModuleDescriptor("dum2")
  518. .getClass()
  519. .getSimpleName()
  520. .equals("MyModuleDescriptor");
  521. }
  522. });
  523. descriptors = pluginAccessor.getPlugin("test.plugin")
  524. .getModuleDescriptors();
  525. assertEquals(2, descriptors.size());
  526. ModuleDescriptor<?> newdescriptor = pluginAccessor.getPlugin("test.plugin")
  527. .getModuleDescriptor("dum2");
  528. assertEquals("MyModuleDescriptor", newdescriptor.getClass().getSimpleName());
  529. assertNotSame(descriptor.getClass(), newdescriptor.getClass());
  530. assertEquals(1, disabledListener.called);
  531. assertEquals(1, enabledListener.called);
  532. }
  533. @Test
  534. public void testDynamicModuleDescriptor() throws Exception {
  535. initPluginManager(null);
  536. final File pluginJar = new PluginJarBuilder("pluginType").addPluginInformation("test.plugin", "foo", "1.0")
  537. .build();
  538. pluginController.installPlugins(new JarPluginArtifact(pluginJar));
  539. final BundleContext ctx = ((OsgiPlugin) pluginAccessor.getPlugin("test.plugin")).getBundle()
  540. .getBundleContext();
  541. final ServiceRegistration reg = ctx.registerService(ModuleDescriptor.class.getName(), new DummyModuleDescriptorWithKey(), null);
  542. final Collection<ModuleDescriptor<?>> descriptors = pluginAccessor.getPlugin("test.plugin")
  543. .getModuleDescriptors();
  544. assertEquals(1, descriptors.size());
  545. final ModuleDescriptor<?> descriptor = descriptors.iterator()
  546. .next();
  547. assertEquals("DummyModuleDescriptorWithKey", descriptor.getClass().getSimpleName());
  548. List<DummyModuleDescriptorWithKey> list = pluginAccessor.getEnabledModuleDescriptorsByClass(DummyModuleDescriptorWithKey.class);
  549. assertEquals(1, list.size());
  550. reg.unregister();
  551. list = pluginAccessor.getEnabledModuleDescriptorsByClass(DummyModuleDescriptorWithKey.class);
  552. assertEquals(0, list.size());
  553. }
  554. @Test
  555. public void testStateAwareDynamicModuleDescriptor() throws Exception {
  556. initPluginManager(null);
  557. final File pluginJar = new PluginJarBuilder("pluginType").addPluginInformation("test.plugin", "foo", "1.0")
  558. .build();
  559. pluginController.installPlugins(new JarPluginArtifact(pluginJar));
  560. final BundleContext ctx = ((OsgiPlugin) pluginAccessor.getPlugin("test.plugin")).getBundle()
  561. .getBundleContext();
  562. AtomicInteger timesEnabled = new AtomicInteger();
  563. AtomicInteger timesDisabled = new AtomicInteger();
  564. final ServiceRegistration reg = ctx.registerService(ModuleDescriptor.class.getName(),
  565. new DummyStateAwareModuleDescriptorWithKey(timesEnabled, timesDisabled), null);
  566. assertThat(timesEnabled.get(), equalTo(1));
  567. reg.unregister();
  568. assertThat(timesDisabled.get(), equalTo(1));
  569. }
  570. @Test
  571. public void testDynamicModuleDescriptorIsolatedToPlugin() throws Exception {
  572. initPluginManager(null);
  573. final File pluginJar = new PluginJarBuilder("pluginType").addPluginInformation("test.plugin", "foo", "1.0")
  574. .build();
  575. pluginController.installPlugins(new JarPluginArtifact(pluginJar));
  576. final BundleContext ctx = ((OsgiPlugin) pluginAccessor.getPlugin("test.plugin")).getBundle()
  577. .getBundleContext();
  578. ctx.registerService(ModuleDescriptor.class.getName(), new DummyModuleDescriptorWithKey(), null);
  579. final File pluginJar2 = new PluginJarBuilder("pluginType").addPluginInformation("test.plugin2", "foo", "1.0")
  580. .build();
  581. pluginController.installPlugins(new JarPluginArtifact(pluginJar2));
  582. final BundleContext ctx2 = ((OsgiPlugin) pluginAccessor.getPlugin("test.plugin2")).getBundle()
  583. .getBundleContext();
  584. final ServiceRegistration reg2 = ctx2.registerService(ModuleDescriptor.class.getName(), new DummyModuleDescriptorWithKey(), null);
  585. Collection<ModuleDescriptor<?>> descriptors = pluginAccessor.getPlugin("test.plugin")
  586. .getModuleDescriptors();
  587. assertEquals(1, descriptors.size());
  588. final ModuleDescriptor<?> descriptor = descriptors.iterator()
  589. .next();
  590. assertEquals("DummyModuleDescriptorWithKey", descriptor.getClass().getSimpleName());
  591. List<DummyModuleDescriptorWithKey> list = pluginAccessor.getEnabledModuleDescriptorsByClass(DummyModuleDescriptorWithKey.class);
  592. assertEquals(2, list.size());
  593. reg2.unregister();
  594. list = pluginAccessor.getEnabledModuleDescriptorsByClass(DummyModuleDescriptorWithKey.class);
  595. assertEquals(1, list.size());
  596. descriptors = pluginAccessor.getPlugin("test.plugin")
  597. .getModuleDescriptors();
  598. assertEquals(1, descriptors.size());
  599. }
  600. @Test
  601. public void testInstallUninstallInstallWithModuleTypePlugin() throws Exception {
  602. final PluginArtifact moduleTypeProviderArtifact = new JarPluginArtifact(new PluginJarBuilder()
  603. .addFormattedResource(
  604. "atlassian-plugin.xml",
  605. "<atlassian-plugin name='Foo Module Type Provider' key='test.fooModuleTypeProvider' pluginsVersion='2'>",
  606. " <plugin-info>",
  607. " <version>1.0</version>",
  608. " <bundle-instructions>",
  609. " <Export-Package>my</Export-Package>",
  610. " </bundle-instructions>",
  611. " </plugin-info>",
  612. " <module-type key='foo-module' class='my.FooModuleDescriptor'/>",
  613. "</atlassian-plugin>")
  614. .addClass(FooModule.class)
  615. .addClass(FooModuleDescriptor.class)
  616. .build());
  617. final PluginArtifact moduleTypeImplementerArtifact = new JarPluginArtifact(new PluginJarBuilder().addFormattedResource("atlassian-plugin.xml",
  618. "<atlassian-plugin name='Foo Module Type Implementer' key='test.fooModuleTypeImplementer' pluginsVersion='2'>",
  619. " <plugin-info>",
  620. " <version>1.0</version>",
  621. " <bundle-instructions>",
  622. " <Import-Package>my</Import-Package>",
  623. " </bundle-instructions>",
  624. " </plugin-info>",
  625. " <foo-module key='myFooModule' class='my.impl.FooModuleImpl'/>",
  626. "</atlassian-plugin>")
  627. .addFormattedJava(
  628. "my.impl.FooModuleImpl",
  629. "package my.impl;",
  630. "",
  631. "import my.FooModule;",
  632. "",
  633. "public class FooModuleImpl implements FooModule {",
  634. "}")
  635. .build());
  636. initPluginManager();
  637. pluginController.installPlugins(moduleTypeProviderArtifact);
  638. pluginController.installPlugins(moduleTypeImplementerArtifact);
  639. final long foo1InitialisationTime = assertFooImplEnabledAndGetInitialisationTime();
  640. pluginController.installPlugins(moduleTypeProviderArtifact);
  641. final long foo2InitialisationTime = assertFooImplEnabledAndGetInitialisationTime();
  642. assertTrue("FooModuleImpl implements old version of FooModule", foo2InitialisationTime > foo1InitialisationTime);
  643. }
  644. private long assertFooImplEnabledAndGetInitialisationTime() throws IllegalAccessException, NoSuchFieldException {
  645. assertTrue(pluginAccessor.isPluginModuleEnabled("test.fooModuleTypeProvider:foo-module"));
  646. assertTrue(pluginAccessor.isPluginModuleEnabled("test.fooModuleTypeImplementer:myFooModule"));
  647. final ModuleDescriptor<?> fooDescriptor = pluginAccessor.getEnabledPluginModule("test.fooModuleTypeImplementer:myFooModule");
  648. assertNotNull(fooDescriptor);
  649. final Object foo = fooDescriptor.getModule();
  650. assertNotNull(foo);
  651. final Class<? extends Object> fooClass = foo.getClass();
  652. assertEquals("my.impl.FooModuleImpl", fooClass.getName());
  653. return fooClass.getField("INITIALISATION_TIME").getLong(foo);
  654. }
  655. private static Pair<String, String[]> getMyModuleDescriptorClass() {
  656. return Pair.pair(
  657. "foo.MyModuleDescriptor",
  658. new String[]{
  659. "package foo;",
  660. "import com.atlassian.plugin.module.ModuleFactory;",
  661. "public class MyModuleDescriptor extends com.atlassian.plugin.descriptors.AbstractModuleDescriptor {",
  662. " public MyModuleDescriptor(){ super(ModuleFactory.LEGACY_MODULE_FACTORY); }",
  663. " public Object getModule(){return null;}",
  664. "}"
  665. });
  666. }
  667. public static class PluginModuleEnabledListener {
  668. public volatile int called;
  669. private final String key;
  670. public PluginModuleEnabledListener(String key) {
  671. this.key = key;
  672. }
  673. @PluginEventListener
  674. public void onEnable(PluginModuleEnabledEvent event) {
  675. if (event.getModule().getKey().equals(key)) {
  676. called++;
  677. }
  678. }
  679. }
  680. public static class PluginModuleDisabledListener {
  681. public volatile int called;
  682. private final String key;
  683. public PluginModuleDisabledListener(String key) {
  684. this.key = key;
  685. }
  686. @PluginEventListener
  687. public void onDisable(PluginModuleDisabledEvent event) {
  688. if (event.getModule().getKey().equals(key)) {
  689. called++;
  690. }
  691. }
  692. }
  693. }