View Javadoc

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