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