View Javadoc
1   package it.com.atlassian.plugin.osgi;
2   
3   import com.atlassian.plugin.DefaultModuleDescriptorFactory;
4   import com.atlassian.plugin.JarPluginArtifact;
5   import com.atlassian.plugin.Plugin;
6   import com.atlassian.plugin.hostcontainer.DefaultHostContainer;
7   import com.atlassian.plugin.osgi.AbstractWaitCondition;
8   import com.atlassian.plugin.osgi.AnotherInterface;
9   import com.atlassian.plugin.osgi.Callable2;
10  import com.atlassian.plugin.osgi.DummyModuleDescriptor;
11  import com.atlassian.plugin.osgi.EventTrackingModuleDescriptor;
12  import com.atlassian.plugin.osgi.PluginInContainerTestBase;
13  import com.atlassian.plugin.osgi.SomeInterface;
14  import com.atlassian.plugin.osgi.container.felix.FelixOsgiContainerManager;
15  import com.atlassian.plugin.osgi.factory.OsgiPlugin;
16  import com.atlassian.plugin.osgi.hostcomponents.ComponentRegistrar;
17  import com.atlassian.plugin.osgi.hostcomponents.HostComponentProvider;
18  import com.atlassian.plugin.test.PluginJarBuilder;
19  import com.atlassian.plugin.util.WaitUntil;
20  import org.junit.Test;
21  import org.osgi.util.tracker.ServiceTracker;
22  
23  import java.io.File;
24  import java.util.concurrent.Callable;
25  
26  import static org.hamcrest.Matchers.contains;
27  import static org.hamcrest.Matchers.empty;
28  import static org.junit.Assert.assertEquals;
29  import static org.junit.Assert.assertThat;
30  import static org.junit.Assert.assertTrue;
31  
32  public class TestPluginDependencies extends PluginInContainerTestBase {
33      @Test
34      public void testPluginDependentOnPackageImport() throws Exception {
35          PluginJarBuilder parentBuilder = new PluginJarBuilder("parent")
36                  .addFormattedResource("atlassian-plugin.xml",
37                          "<atlassian-plugin name='Test' key='parent' pluginsVersion='2'>",
38                          "    <plugin-info>",
39                          "        <version>1.0</version>",
40                          "        <bundle-instructions>",
41                          "            <Import-Package>foo</Import-Package>",
42                          "            <Export-Package>foo</Export-Package>",
43                          "        </bundle-instructions>",
44                          "    </plugin-info>",
45                          "</atlassian-plugin>")
46                  .addFormattedJava("foo.Bar",
47                          "package foo;",
48                          "public interface Bar {}");
49  
50          new PluginJarBuilder("child", parentBuilder.getClassLoader())
51                  .addFormattedResource("atlassian-plugin.xml",
52                          "<atlassian-plugin name='Test' key='child' pluginsVersion='2'>",
53                          "    <plugin-info>",
54                          "        <version>1.0</version>",
55                          "    </plugin-info>",
56                          "</atlassian-plugin>")
57                  .addFormattedJava("second.MyImpl",
58                          "package second;",
59                          "public class MyImpl {",
60                          "    public MyImpl(foo.Bar config) {",
61                          "    }",
62                          "}")
63                  .build(pluginsDir);
64  
65          parentBuilder.build(pluginsDir);
66          initPluginManager();
67          assertEquals(2, pluginAccessor.getEnabledPlugins().size());
68          assertThat(pluginAccessor.getPlugin("child").getDependencies().getOptional(), contains("parent"));
69          assertThat(pluginAccessor.getPlugin("child").getDependencies().getMandatory(), empty());
70      }
71  
72      @Test
73      public void testPluginDependentOnDynamicPackageImport() throws Exception {
74          PluginJarBuilder parentBuilder = new PluginJarBuilder("parent")
75                  .addFormattedResource("atlassian-plugin.xml",
76                          "<atlassian-plugin name='Test' key='parent' pluginsVersion='2'>",
77                          "    <plugin-info>",
78                          "        <version>1.0</version>",
79                          "        <bundle-instructions>",
80                          "            <Import-Package>foo</Import-Package>",
81                          "            <Export-Package>foo</Export-Package>",
82                          "        </bundle-instructions>",
83                          "    </plugin-info>",
84                          "</atlassian-plugin>")
85                  .addFormattedJava("foo.Bar",
86                          "package foo;",
87                          "public interface Bar {}");
88  
89          new PluginJarBuilder("child", parentBuilder.getClassLoader())
90                  .addFormattedResource("atlassian-plugin.xml",
91                          "<atlassian-plugin name='Test' key='child' pluginsVersion='2'>",
92                          "    <plugin-info>",
93                          "        <version>1.0</version>",
94                          "        <bundle-instructions>",
95                          "          <Import-Package />",
96                          "          <DynamicImport-Package>foo</DynamicImport-Package>",
97                          "        </bundle-instructions>",
98                          "    </plugin-info>",
99                          "</atlassian-plugin>")
100                 .addFormattedJava("second.MyImpl",
101                         "package second;",
102                         "public class MyImpl {",
103                         "    public MyImpl(foo.Bar config) {",
104                         "    }",
105                         "}")
106                 .build(pluginsDir);
107 
108         parentBuilder.build(pluginsDir);
109         initPluginManager();
110         assertEquals(2, pluginAccessor.getEnabledPlugins().size());
111         Plugin childPlugin = pluginAccessor.getPlugin("child");
112         childPlugin.loadClass("foo.Bar", null);
113         assertThat(pluginAccessor.getPlugin("child").getDependencies().getOptional(), contains("parent"));
114         assertThat(pluginAccessor.getPlugin("child").getDependencies().getMandatory(), empty());
115     }
116 
117     @Test
118     public void testUninstallingPluginDependentOnPackageImport() throws Exception {
119         PluginJarBuilder parentBuilder = new PluginJarBuilder("parent")
120                 .addFormattedResource("atlassian-plugin.xml",
121                         "<atlassian-plugin name='Test' key='parent' pluginsVersion='2'>",
122                         "    <plugin-info>",
123                         "        <version>1.0</version>",
124                         "        <bundle-instructions>",
125                         "            <Import-Package>foo</Import-Package>",
126                         "            <Export-Package>foo</Export-Package>",
127                         "        </bundle-instructions>",
128                         "    </plugin-info>",
129                         "</atlassian-plugin>")
130                 .addFormattedJava("foo.Bar",
131                         "package foo;",
132                         "public interface Bar {}");
133 
134         new PluginJarBuilder("child", parentBuilder.getClassLoader())
135                 .addFormattedResource("atlassian-plugin.xml",
136                         "<atlassian-plugin name='Test' key='child' pluginsVersion='2'>",
137                         "    <plugin-info>",
138                         "        <version>1.0</version>",
139                         "    </plugin-info>",
140                         "</atlassian-plugin>")
141                 .addFormattedJava("second.MyImpl",
142                         "package second;",
143                         "public class MyImpl {",
144                         "    public MyImpl(foo.Bar config) {",
145                         "    }",
146                         "}")
147                 .build(pluginsDir);
148 
149         parentBuilder.build(pluginsDir);
150         initPluginManager();
151         assertEquals(2, pluginAccessor.getEnabledPlugins().size());
152         pluginController.uninstall(pluginAccessor.getPlugin("parent"));
153         assertEquals(1, pluginAccessor.getEnabledPlugins().size());
154     }
155 
156     @Test
157     public void testUpgradeWithNewComponentImplementation() throws Exception {
158         final DefaultModuleDescriptorFactory factory = new DefaultModuleDescriptorFactory(new DefaultHostContainer());
159         factory.addModuleDescriptor("dummy", DummyModuleDescriptor.class);
160         initPluginManager(new HostComponentProvider() {
161             public void provide(final ComponentRegistrar registrar) {
162                 registrar.register(SomeInterface.class).forInstance(new SomeInterface() {
163                 });
164                 registrar.register(AnotherInterface.class).forInstance(new AnotherInterface() {
165                 });
166             }
167         }, factory);
168 
169         final File pluginJar = new PluginJarBuilder("first")
170                 .addFormattedResource("atlassian-plugin.xml",
171                         "<atlassian-plugin name='Test' key='test.plugin' pluginsVersion='2'>",
172                         "    <plugin-info>",
173                         "        <version>1.0</version>",
174                         "    </plugin-info>",
175                         "    <component key='svc' class='my.ServiceImpl' public='true'>",
176                         "    <interface>java.util.concurrent.Callable</interface>",
177                         "    </component>",
178                         "</atlassian-plugin>")
179                 .addFormattedJava("my.ServiceImpl",
180                         "package my;",
181                         "import java.util.concurrent.Callable;",
182                         "public class ServiceImpl implements Callable {",
183                         "    public Object call() throws Exception { return 'hi';}",
184                         "}")
185                 .build();
186         final File pluginJar2 = new PluginJarBuilder("second")
187                 .addFormattedResource("atlassian-plugin.xml",
188                         "<atlassian-plugin name='Test 2' key='test2.plugin' pluginsVersion='2'>",
189                         "    <plugin-info>",
190                         "        <version>1.0</version>",
191                         "    </plugin-info>",
192                         "    <component-import key='svc' interface='java.util.concurrent.Callable' />",
193                         "    <component key='del' class='my2.ServiceDelegate' public='true'>",
194                         "    <interface>com.atlassian.plugin.osgi.Callable2</interface>",
195                         "    </component>",
196                         "</atlassian-plugin>")
197                 .addFormattedJava("my2.ServiceDelegate",
198                         "package my2;",
199                         "import com.atlassian.plugin.osgi.Callable2;",
200                         "import java.util.concurrent.Callable;",
201                         "public class ServiceDelegate implements Callable2 {",
202                         "    private final Callable delegate;",
203                         "    public ServiceDelegate(Callable foo) { this.delegate = foo;}",
204                         "    public String call() throws Exception { return (String)delegate.call();}",
205                         "}")
206                 .build();
207 
208         pluginController.installPlugins(new JarPluginArtifact(pluginJar));
209         assertEquals(1, pluginAccessor.getEnabledPlugins().size());
210 
211         pluginController.installPlugins(new JarPluginArtifact(pluginJar2));
212         final ServiceTracker tracker = osgiContainerManager.getServiceTracker("com.atlassian.plugin.osgi.Callable2");
213 
214         for (final Object svc : tracker.getServices()) {
215             final Callable2 callable = (Callable2) svc;
216             assertEquals("hi", callable.call());
217         }
218         assertEquals(2, pluginAccessor.getEnabledPlugins().size());
219 
220         final File updatedJar = new PluginJarBuilder("first")
221                 .addFormattedResource("atlassian-plugin.xml",
222                         "<atlassian-plugin name='Test' key='test.plugin' pluginsVersion='2'>",
223                         "    <plugin-info>",
224                         "        <version>1.0</version>",
225                         "    </plugin-info>",
226                         "    <component key='svc' class='my.ServiceImpl' public='true'>",
227                         "    <interface>java.util.concurrent.Callable</interface>",
228                         "    </component>",
229                         "</atlassian-plugin>")
230                 .addFormattedJava("my.ServiceImpl",
231                         "package my;",
232                         "import java.util.concurrent.Callable;",
233                         "public class ServiceImpl implements Callable {",
234                         "    public Object call() throws Exception { return 'bob';}",
235                         "}")
236                 .build();
237 
238         pluginController.installPlugins(new JarPluginArtifact(updatedJar));
239         WaitUntil.invoke(new AbstractWaitCondition() {
240             public boolean isFinished() {
241                 return pluginAccessor.getEnabledPlugins().size() == 2;
242             }
243         });
244         assertEquals(2, pluginAccessor.getEnabledPlugins().size());
245         for (final Object svc : tracker.getServices()) {
246             final Callable2 callable = (Callable2) svc;
247             assertEquals("bob", callable.call());
248         }
249     }
250 
251     @Test
252     public void testUpgradeWithNewComponentImplementationWithInterfaceInPlugin() throws Exception {
253         final DefaultModuleDescriptorFactory factory = new DefaultModuleDescriptorFactory(new DefaultHostContainer());
254         factory.addModuleDescriptor("dummy", DummyModuleDescriptor.class);
255         initPluginManager(new HostComponentProvider() {
256             public void provide(final ComponentRegistrar registrar) {
257                 registrar.register(SomeInterface.class).forInstance(new SomeInterface() {
258                 });
259                 registrar.register(AnotherInterface.class).forInstance(new AnotherInterface() {
260                 });
261             }
262         }, factory);
263 
264         final PluginJarBuilder builder1 = new PluginJarBuilder("first")
265                 .addFormattedResource("atlassian-plugin.xml",
266                         "<atlassian-plugin name='Test' key='test.plugin' pluginsVersion='2'>",
267                         "    <plugin-info>",
268                         "        <version>1.0</version>",
269                         "    </plugin-info>",
270                         "    <component key='svc' class='my.ServiceImpl' public='true'>",
271                         "    <interface>my.Service</interface>",
272                         "    </component>",
273                         "</atlassian-plugin>")
274                 .addFormattedJava("my.Service",
275                         "package my;",
276                         "public interface Service {",
277                         "    public Object call() throws Exception;",
278                         "}")
279                 .addFormattedJava("my.ServiceImpl",
280                         "package my;",
281                         "public class ServiceImpl implements Service {",
282                         "    public Object call() throws Exception { return 'hi';}",
283                         "}");
284         final File pluginJar = builder1.build();
285         final File pluginJar2 = new PluginJarBuilder("second", builder1.getClassLoader())
286                 .addFormattedResource("atlassian-plugin.xml",
287                         "<atlassian-plugin name='Test 2' key='test2.plugin' pluginsVersion='2'>",
288                         "    <plugin-info>",
289                         "        <version>1.0</version>",
290                         "    </plugin-info>",
291                         "    <component-import key='svc' interface='my.Service' />",
292                         "    <component key='del' class='my2.ServiceDelegate' public='true'>",
293                         "    <interface>java.util.concurrent.Callable</interface>",
294                         "    </component>",
295                         "</atlassian-plugin>")
296                 .addFormattedJava("my2.ServiceDelegate",
297                         "package my2;",
298                         "import my.Service;",
299                         "import java.util.concurrent.Callable;",
300                         "public class ServiceDelegate implements Callable {",
301                         "    private final Service delegate;",
302                         "    public ServiceDelegate(Service foo) { this.delegate = foo;}",
303                         "    public Object call() throws Exception { return delegate.call();}",
304                         "}")
305                 .build();
306 
307         pluginController.installPlugins(new JarPluginArtifact(pluginJar));
308         assertEquals(1, pluginAccessor.getEnabledPlugins().size());
309         final ServiceTracker tracker = osgiContainerManager.getServiceTracker(Callable.class.getName());
310         final ServiceTracker svcTracker = osgiContainerManager.getServiceTracker("my.Service");
311 
312         pluginController.installPlugins(new JarPluginArtifact(pluginJar2));
313         assertEquals("hi", svcTracker.getService().getClass().getMethod("call").invoke(svcTracker.getService()));
314         assertEquals("hi", ((Callable) tracker.getService()).call());
315 
316         assertEquals(2, pluginAccessor.getEnabledPlugins().size());
317 
318         final File updatedJar = new PluginJarBuilder("first")
319                 .addFormattedResource("atlassian-plugin.xml",
320                         "<atlassian-plugin name='Test' key='test.plugin' pluginsVersion='2'>",
321                         "    <plugin-info>",
322                         "        <version>1.0</version>",
323                         "    </plugin-info>",
324                         "    <component key='svc' class='my.Service2Impl' public='true'>",
325                         "    <interface>my.Service</interface>",
326                         "    </component>",
327                         "</atlassian-plugin>")
328                 .addFormattedJava("my.Service",
329                         "package my;",
330                         "public interface Service {",
331                         "    public Object call() throws Exception;",
332                         "}")
333                 .addFormattedJava("my.Service2Impl",
334                         "package my;",
335                         "public class Service2Impl implements Service {",
336                         "    public Object call() throws Exception {return 'bob';}",
337                         "}")
338                 .build();
339 
340         pluginController.installPlugins(new JarPluginArtifact(updatedJar));
341         assertEquals("bob", svcTracker.getService().getClass().getMethod("call").invoke(svcTracker.getService()));
342         tracker.waitForService(5000);
343         assertEquals("bob", ((Callable) tracker.getService()).call());
344     }
345 
346     @Test
347     public void testUpgradeWithRefreshingAffectingOtherPlugins() throws Exception {
348         final DefaultModuleDescriptorFactory factory = new DefaultModuleDescriptorFactory(new DefaultHostContainer());
349         initPluginManager(new HostComponentProvider() {
350             public void provide(final ComponentRegistrar registrar) {
351             }
352         }, factory);
353 
354         PluginJarBuilder pluginBuilder = new PluginJarBuilder("first")
355                 .addFormattedResource("atlassian-plugin.xml",
356                         "<atlassian-plugin name='Test' key='test.plugin' pluginsVersion='2'>",
357                         "    <plugin-info>",
358                         "        <version>1.0</version>",
359                         "        <bundle-instructions><Export-Package>my</Export-Package></bundle-instructions>",
360                         "    </plugin-info>",
361                         "    <component key='svc' class='my.ServiceImpl' public='true'>",
362                         "    <interface>java.util.concurrent.Callable</interface>",
363                         "    </component>",
364                         "</atlassian-plugin>")
365                 .addFormattedJava("my.ServiceImpl",
366                         "package my;",
367                         "import java.util.concurrent.Callable;",
368                         "public class ServiceImpl implements Callable {",
369                         "    public Object call() throws Exception { return 'hi';}",
370                         "}");
371         final File pluginJar = pluginBuilder.build();
372 
373         final File pluginJar2 = new PluginJarBuilder("second", pluginBuilder.getClassLoader())
374                 .addFormattedResource("atlassian-plugin.xml",
375                         "<atlassian-plugin name='Test 2' key='test2.plugin' pluginsVersion='2'>",
376                         "    <plugin-info>",
377                         "        <version>1.0</version>",
378                         "        <bundle-instructions><Import-Package>my</Import-Package></bundle-instructions>",
379                         "    </plugin-info>",
380                         "    <component-import key='svc' interface='java.util.concurrent.Callable' />",
381                         "    <component-import key='othersvc' interface='com.atlassian.plugin.osgi.Callable3' />",
382                         "    <component key='del' class='my2.ServiceDelegate' public='true'>",
383                         "    <interface>com.atlassian.plugin.osgi.Callable2</interface>",
384                         "    </component>",
385                         "</atlassian-plugin>")
386                 .addFormattedJava("my2.ServiceDelegate",
387                         "package my2;",
388                         "import com.atlassian.plugin.osgi.Callable2;",
389                         "import com.atlassian.plugin.osgi.Callable3;",
390                         "import java.util.concurrent.Callable;",
391                         "public class ServiceDelegate implements Callable2 {",
392                         "    private final Callable delegate;",
393                         "    private final Callable3 othersvc;",
394                         "    public ServiceDelegate(Callable foo,Callable3 othersvc) {",
395                         "        this.delegate = foo;",
396                         "        this.othersvc = othersvc;",
397                         "    }",
398                         "    public String call() throws Exception { return othersvc.call() + (String)delegate.call();}",
399                         "}")
400                 .build();
401         final File otherSvcJar = new PluginJarBuilder("otherSvc")
402                 .addFormattedResource("atlassian-plugin.xml",
403                         "<atlassian-plugin name='Test' key='test.othersvc.plugin' pluginsVersion='2'>",
404                         "    <plugin-info>",
405                         "        <version>1.0</version>",
406                         "    </plugin-info>",
407                         "    <component key='othersvc' class='othersvc.ServiceImpl' public='true'>",
408                         "    <interface>com.atlassian.plugin.osgi.Callable3</interface>",
409                         "    </component>",
410                         "</atlassian-plugin>")
411                 .addFormattedJava("othersvc.ServiceImpl",
412                         "package othersvc;",
413                         "import com.atlassian.plugin.osgi.Callable3;",
414                         "public class ServiceImpl implements Callable3 {",
415                         "    public String call() throws Exception { return 'hi';}",
416                         "}")
417                 .build();
418 
419 
420         pluginController.installPlugins(new JarPluginArtifact(pluginJar));
421         assertEquals(1, pluginAccessor.getEnabledPlugins().size());
422 
423         pluginController.installPlugins(new JarPluginArtifact(otherSvcJar));
424         pluginController.installPlugins(new JarPluginArtifact(pluginJar2));
425 
426         assertEquals("hi", ((OsgiPlugin) pluginAccessor.getPlugin("test2.plugin")).getContainerAccessor().createBean(TestPluginInstall.Callable3Aware.class).call());
427         assertEquals(3, pluginAccessor.getEnabledPlugins().size());
428 
429         final File updatedJar = new PluginJarBuilder("first")
430                 .addFormattedResource("atlassian-plugin.xml",
431                         "<atlassian-plugin name='Test' key='test.plugin' pluginsVersion='2'>",
432                         "    <plugin-info>",
433                         "        <version>1.0</version>",
434                         "        <bundle-instructions><Export-Package>my</Export-Package></bundle-instructions>",
435                         "    </plugin-info>",
436                         "    <component key='svc' class='my.ServiceImpl' public='true'>",
437                         "    <interface>java.util.concurrent.Callable</interface>",
438                         "    </component>",
439                         "</atlassian-plugin>")
440                 .addFormattedJava("my.ServiceImpl",
441                         "package my;",
442                         "import java.util.concurrent.Callable;",
443                         "public class ServiceImpl implements Callable {",
444                         "    public Object call() throws Exception { return 'bob';}",
445                         "}")
446                 .build();
447 
448         pluginController.installPlugins(new JarPluginArtifact(updatedJar));
449         assertEquals(3, pluginAccessor.getEnabledPlugins().size());
450         assertEquals("hi", ((OsgiPlugin) pluginAccessor.getPlugin("test2.plugin")).getContainerAccessor().createBean(TestPluginInstall.Callable3Aware.class).call());
451     }
452 
453     @Test
454     public void testUpgradeOfBundledPluginWithRefreshingAffectingOtherPluginsCheckingModuleEvents() throws Exception {
455         DefaultModuleDescriptorFactory factory = new DefaultModuleDescriptorFactory(new DefaultHostContainer());
456         factory.addModuleDescriptor("dummy", EventTrackingModuleDescriptor.class);
457 
458 
459         PluginJarBuilder hostBuilder = new PluginJarBuilder("first")
460                 .addFormattedResource("atlassian-plugin.xml",
461                         "<atlassian-plugin name='Test' key='host' pluginsVersion='2'>",
462                         "    <plugin-info>",
463                         "        <version>1.0</version>",
464                         "        <bundle-instructions><Export-Package>my</Export-Package></bundle-instructions>",
465                         "    </plugin-info>",
466                         "    <dummy key='foo'/>",
467                         "</atlassian-plugin>")
468                 .addFormattedJava("my.Serviceable",
469                         "package my;",
470                         "public interface Serviceable {}");
471         final File hostJar = hostBuilder.build();
472 
473         final File clientJar = new PluginJarBuilder("second", hostBuilder.getClassLoader())
474                 .addFormattedResource("atlassian-plugin.xml",
475                         "<atlassian-plugin name='Test 2' key='client' pluginsVersion='2'>",
476                         "    <plugin-info>",
477                         "        <version>1.0</version>",
478                         "    </plugin-info>",
479                         "    <dummy key='foo'/>",
480                         "</atlassian-plugin>")
481                 .addFormattedJava("my2.Service",
482                         "package my2;",
483                         "public class Service implements my.Serviceable {}")
484                 .build();
485 
486         initBundlingPluginManager(factory, hostJar);
487         assertEquals(1, pluginAccessor.getEnabledPlugins().size());
488 
489         pluginController.installPlugins(new JarPluginArtifact(clientJar));
490 
491         EventTrackingModuleDescriptor hostModule = (EventTrackingModuleDescriptor) pluginAccessor.getPlugin("host").getModuleDescriptor("foo");
492         assertEquals(1, hostModule.getEnabledCount());
493         assertEquals(0, hostModule.getDisabledCount());
494 
495         EventTrackingModuleDescriptor clientModule = (EventTrackingModuleDescriptor) pluginAccessor.getPlugin("client").getModuleDescriptor("foo");
496         assertEquals(1, clientModule.getEnabledCount());
497         assertEquals(0, clientModule.getDisabledCount());
498 
499         pluginController.installPlugins(new JarPluginArtifact(hostJar));
500 
501         hostModule = (EventTrackingModuleDescriptor) pluginAccessor.getPlugin("host").getModuleDescriptor("foo");
502         assertEquals(1, hostModule.getEnabledCount());
503         assertEquals(0, hostModule.getDisabledCount());
504 
505         clientModule = (EventTrackingModuleDescriptor) pluginAccessor.getPlugin("client").getModuleDescriptor("foo");
506         assertEquals(1, clientModule.getDisabledCount());
507         assertEquals(2, clientModule.getEnabledCount());
508     }
509 
510     @Test
511     public void testUpgradeWithRefreshingAffectingOtherPluginsWithClassLoadingOnShutdown() throws Exception {
512         final DefaultModuleDescriptorFactory factory = new DefaultModuleDescriptorFactory(new DefaultHostContainer());
513         initPluginManager(new HostComponentProvider() {
514             public void provide(final ComponentRegistrar registrar) {
515             }
516         }, factory);
517 
518         PluginJarBuilder pluginBuilder = new PluginJarBuilder("first")
519                 .addFormattedResource("atlassian-plugin.xml",
520                         "<atlassian-plugin name='Test' key='test.plugin' pluginsVersion='2'>",
521                         "    <plugin-info>",
522                         "        <version>1.0</version>",
523                         "        <bundle-instructions><Export-Package>my</Export-Package></bundle-instructions>",
524                         "    </plugin-info>",
525                         "    <component key='svc' class='my.ServiceImpl' public='true'>",
526                         "    <interface>java.util.concurrent.Callable</interface>",
527                         "    </component>",
528                         "</atlassian-plugin>")
529                 .addFormattedJava("my.ServiceImpl",
530                         "package my;",
531                         "import java.util.concurrent.Callable;",
532                         "public class ServiceImpl implements Callable {",
533                         "    public Object call() throws Exception { return 'hi';}",
534                         "}");
535         final File pluginJar = pluginBuilder.build();
536 
537         final File pluginJar2 = new PluginJarBuilder("second", pluginBuilder.getClassLoader())
538                 .addFormattedResource("atlassian-plugin.xml",
539                         "<atlassian-plugin name='Test 2' key='test2.plugin' pluginsVersion='2'>",
540                         "    <plugin-info>",
541                         "        <version>1.0</version>",
542                         "        <bundle-instructions><Import-Package>my</Import-Package>",
543                         "          <DynamicImport-Package>foo</DynamicImport-Package></bundle-instructions>",
544                         "    </plugin-info>",
545                         "    <component-import key='svc' interface='java.util.concurrent.Callable' />",
546                         "    <component-import key='othersvc' interface='com.atlassian.plugin.osgi.Callable3' />",
547                         "    <component key='del' class='my2.ServiceDelegate' public='true'>",
548                         "    <interface>com.atlassian.plugin.osgi.Callable2</interface>",
549                         "    </component>",
550                         "</atlassian-plugin>")
551                 .addFormattedJava("my2.ServiceDelegate",
552                         "package my2;",
553                         "import com.atlassian.plugin.osgi.Callable2;",
554                         "import com.atlassian.plugin.osgi.Callable3;",
555                         "import java.util.concurrent.Callable;",
556                         "public class ServiceDelegate implements Callable2, org.springframework.beans.factory.DisposableBean {",
557                         "    private final Callable delegate;",
558                         "    private final Callable3 othersvc;",
559                         "    public ServiceDelegate(Callable foo,Callable3 othersvc) {",
560                         "        this.delegate = foo;",
561                         "        this.othersvc = othersvc;",
562                         "    }",
563                         "    public void destroy() {",
564                         "       try {",
565                         "          getClass().getClassLoader().loadClass('foo.bar');",
566                         "       } catch (ClassNotFoundException ex) {}",
567                         "    }",
568                         "    public String call() throws Exception { return othersvc.call() + (String)delegate.call();}",
569                         "}")
570                 .build();
571         final File otherSvcJar = new PluginJarBuilder("otherSvc")
572                 .addFormattedResource("atlassian-plugin.xml",
573                         "<atlassian-plugin name='Test' key='test.othersvc.plugin' pluginsVersion='2'>",
574                         "    <plugin-info>",
575                         "        <version>1.0</version>",
576                         "    </plugin-info>",
577                         "    <component key='othersvc' class='othersvc.ServiceImpl' public='true'>",
578                         "    <interface>com.atlassian.plugin.osgi.Callable3</interface>",
579                         "    </component>",
580                         "</atlassian-plugin>")
581                 .addFormattedJava("othersvc.ServiceImpl",
582                         "package othersvc;",
583                         "import com.atlassian.plugin.osgi.Callable3;",
584                         "public class ServiceImpl implements Callable3 {",
585                         "    public String call() throws Exception { return 'hi';}",
586                         "}")
587                 .build();
588 
589 
590         pluginController.installPlugins(new JarPluginArtifact(pluginJar));
591         assertEquals(1, pluginAccessor.getEnabledPlugins().size());
592 
593         pluginController.installPlugins(new JarPluginArtifact(otherSvcJar));
594         pluginController.installPlugins(new JarPluginArtifact(pluginJar2));
595 
596         assertEquals("hi", ((OsgiPlugin) pluginAccessor.getPlugin("test2.plugin")).getContainerAccessor().createBean(TestPluginInstall.Callable3Aware.class).call());
597         assertEquals(3, pluginAccessor.getEnabledPlugins().size());
598 
599         final File updatedJar = new PluginJarBuilder("first")
600                 .addFormattedResource("atlassian-plugin.xml",
601                         "<atlassian-plugin name='Test' key='test.plugin' pluginsVersion='2'>",
602                         "    <plugin-info>",
603                         "        <version>1.0</version>",
604                         "        <bundle-instructions><Export-Package>my</Export-Package></bundle-instructions>",
605                         "    </plugin-info>",
606                         "    <component key='svc' class='my.ServiceImpl' public='true'>",
607                         "    <interface>java.util.concurrent.Callable</interface>",
608                         "    </component>",
609                         "</atlassian-plugin>")
610                 .addFormattedJava("my.ServiceImpl",
611                         "package my;",
612                         "import java.util.concurrent.Callable;",
613                         "public class ServiceImpl implements Callable {",
614                         "    public Object call() throws Exception { return 'bob';}",
615                         "}")
616                 .build();
617 
618         long start = System.currentTimeMillis();
619         pluginController.installPlugins(new JarPluginArtifact(updatedJar));
620         long timeWaitingForRefresh = System.currentTimeMillis() - start;
621         assertTrue("Refresh seemed to have timed out, which is bad", timeWaitingForRefresh < FelixOsgiContainerManager.REFRESH_TIMEOUT * 1000);
622         assertEquals(3, pluginAccessor.getEnabledPlugins().size());
623         assertEquals("hi", ((OsgiPlugin) pluginAccessor.getPlugin("test2.plugin")).getContainerAccessor().createBean(TestPluginInstall.Callable3Aware.class).call());
624     }
625 
626     @Test
627     public void testUninstallWithShutdownAffectingOtherPluginsWithClassLoadingOnShutdown() throws Exception {
628         final DefaultModuleDescriptorFactory factory = new DefaultModuleDescriptorFactory(new DefaultHostContainer());
629         initPluginManager(new HostComponentProvider() {
630             public void provide(final ComponentRegistrar registrar) {
631             }
632         }, factory);
633 
634         PluginJarBuilder pluginBuilder = new PluginJarBuilder("first")
635                 .addFormattedResource("atlassian-plugin.xml",
636                         "<atlassian-plugin name='Test' key='test.plugin' pluginsVersion='2'>",
637                         "    <plugin-info>",
638                         "        <version>1.0</version>",
639                         "        <bundle-instructions><Export-Package>my</Export-Package></bundle-instructions>",
640                         "    </plugin-info>",
641                         "    <component key='svc' class='my.ServiceImpl' public='true'>",
642                         "    <interface>java.util.concurrent.Callable</interface>",
643                         "    </component>",
644                         "</atlassian-plugin>")
645                 .addFormattedJava("my.ServiceImpl",
646                         "package my;",
647                         "import java.util.concurrent.Callable;",
648                         "public class ServiceImpl implements Callable {",
649                         "    public Object call() throws Exception { return 'hi';}",
650                         "}");
651         final File pluginJar = pluginBuilder.build();
652 
653         final File pluginJar2 = new PluginJarBuilder("second", pluginBuilder.getClassLoader())
654                 .addFormattedResource("atlassian-plugin.xml",
655                         "<atlassian-plugin name='Test 2' key='test2.plugin' pluginsVersion='2'>",
656                         "    <plugin-info>",
657                         "        <version>1.0</version>",
658                         "        <bundle-instructions><Import-Package>my</Import-Package>",
659                         "          <DynamicImport-Package>foo</DynamicImport-Package></bundle-instructions>",
660                         "    </plugin-info>",
661                         "    <component-import key='svc' interface='java.util.concurrent.Callable' />",
662                         "    <component key='del' class='my2.Consumer'/>",
663                         "</atlassian-plugin>")
664                 .addFormattedJava("my2.Consumer",
665                         "package my2;",
666                         "import java.util.concurrent.Callable;",
667                         "public class Consumer implements org.springframework.beans.factory.DisposableBean {",
668                         "    private final Callable delegate;",
669                         "    public Consumer(Callable foo) {",
670                         "        this.delegate = foo;",
671                         "    }",
672                         "    public void destroy() {",
673                         "       try {",
674                         "          getClass().getClassLoader().loadClass('foo.bar');",
675                         "       } catch (ClassNotFoundException ex) {}",
676                         "    }",
677                         "}")
678                 .build();
679 
680         pluginController.installPlugins(new JarPluginArtifact(pluginJar));
681         assertEquals(1, pluginAccessor.getEnabledPlugins().size());
682 
683         pluginController.installPlugins(new JarPluginArtifact(pluginJar2));
684 
685         assertEquals(2, pluginAccessor.getEnabledPlugins().size());
686 
687         long start = System.currentTimeMillis();
688         pluginController.uninstall(pluginAccessor.getPlugin("test.plugin"));
689         long timeWaitingForRefresh = System.currentTimeMillis() - start;
690         assertTrue("Refresh seemed to have timed out, which is bad", timeWaitingForRefresh < FelixOsgiContainerManager.REFRESH_TIMEOUT * 1000);
691         assertEquals(0, pluginAccessor.getEnabledPlugins().size());
692     }
693 }