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