View Javadoc

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