View Javadoc

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