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 }