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