1 package com.atlassian.plugin.osgi;
2
3 import com.atlassian.plugin.DefaultModuleDescriptorFactory;
4 import com.atlassian.plugin.JarPluginArtifact;
5 import com.atlassian.plugin.PluginState;
6 import com.atlassian.plugin.event.PluginEventListener;
7 import com.atlassian.plugin.event.events.PluginRefreshedEvent;
8 import com.atlassian.plugin.hostcontainer.DefaultHostContainer;
9 import com.atlassian.plugin.hostcontainer.HostContainer;
10 import com.atlassian.plugin.osgi.external.SingleModuleDescriptorFactory;
11 import com.atlassian.plugin.osgi.factory.OsgiPlugin;
12 import com.atlassian.plugin.osgi.hostcomponents.ComponentRegistrar;
13 import com.atlassian.plugin.osgi.hostcomponents.HostComponentProvider;
14 import com.atlassian.plugin.servlet.DefaultServletModuleManager;
15 import com.atlassian.plugin.servlet.ServletModuleManager;
16 import com.atlassian.plugin.servlet.descriptors.ServletModuleDescriptor;
17 import com.atlassian.plugin.test.PluginJarBuilder;
18 import com.atlassian.plugin.util.WaitUntil;
19 import com.mockobjects.dynamic.C;
20 import com.mockobjects.dynamic.Mock;
21 import org.osgi.util.tracker.ServiceTracker;
22
23 import javax.servlet.ServletConfig;
24 import javax.servlet.ServletContext;
25 import javax.servlet.http.HttpServlet;
26 import java.io.File;
27 import java.util.Collections;
28 import java.util.concurrent.Callable;
29 import java.util.concurrent.TimeUnit;
30 import java.util.concurrent.locks.Lock;
31 import java.util.concurrent.locks.ReentrantLock;
32
33 public class TestPluginInstall extends PluginInContainerTestBase
34 {
35 public void testUpgradeOfBundledPlugin() throws Exception
36 {
37 final DefaultModuleDescriptorFactory factory = new DefaultModuleDescriptorFactory(new DefaultHostContainer());
38 factory.addModuleDescriptor("object", ObjectModuleDescriptor.class);
39
40 final File pluginJar = new PluginJarBuilder("testUpgradeOfBundledPlugin")
41 .addFormattedResource("atlassian-plugin.xml",
42 "<atlassian-plugin name='Test' key='test.bundled.plugin' pluginsVersion='2'>",
43 " <plugin-info>",
44 " <version>1.0</version>",
45 " </plugin-info>",
46 " <object key='obj' class='my.Foo'/>",
47 "</atlassian-plugin>")
48 .addFormattedJava("my.Foo",
49 "package my;",
50 "public class Foo {}")
51 .build();
52 initBundlingPluginManager(factory, pluginJar);
53 assertEquals(1, pluginManager.getEnabledPlugins().size());
54 assertEquals("Test", pluginManager.getPlugin("test.bundled.plugin").getName());
55 assertEquals("my.Foo", pluginManager.getPlugin("test.bundled.plugin").getModuleDescriptor("obj").getModule().getClass().getName());
56
57 final File pluginJar2 = new PluginJarBuilder("testUpgradeOfBundledPlugin")
58 .addFormattedResource("atlassian-plugin.xml",
59 "<atlassian-plugin name='Test' key='test.bundled.plugin' pluginsVersion='2'>",
60 " <plugin-info>",
61 " <version>1.0</version>",
62 " </plugin-info>",
63 " <object key='obj' class='my.Bar'/>",
64 "</atlassian-plugin>")
65 .addFormattedJava("my.Bar",
66 "package my;",
67 "public class Bar {}")
68 .build();
69
70 pluginManager.installPlugin(new JarPluginArtifact(pluginJar2));
71
72 assertEquals(1, pluginManager.getEnabledPlugins().size());
73 assertEquals("Test", pluginManager.getPlugin("test.bundled.plugin").getName());
74 assertEquals("my.Bar", pluginManager.getPlugin("test.bundled.plugin").getModuleDescriptor("obj").getModule().getClass().getName());
75
76 }
77
78 public void testUpgradeOfBadPlugin() throws Exception
79 {
80 new PluginJarBuilder("testUpgradeOfBundledPlugin-old")
81 .addFormattedResource("atlassian-plugin.xml",
82 "<atlassian-plugin name='Test' key='test.bundled.plugin' pluginsVersion='2'>",
83 " <plugin-info>",
84 " <version>1.0</version>",
85 " </plugin-info>",
86 " <component key='obj' class='my.Foo'/>",
87 "</atlassian-plugin>")
88 .addFormattedJava("my.Foo",
89 "package my;",
90 "public class Foo {",
91 " public Foo() { throw new RuntimeException('bad plugin');}",
92 "}")
93 .build(pluginsDir);
94 new PluginJarBuilder("testUpgradeOfBundledPlugin-new")
95 .addFormattedResource("atlassian-plugin.xml",
96 "<atlassian-plugin name='Test' key='test.bundled.plugin' pluginsVersion='2'>",
97 " <plugin-info>",
98 " <version>2.0</version>",
99 " </plugin-info>",
100 " <component key='obj' class='my.Foo'/>",
101 "</atlassian-plugin>")
102 .addFormattedJava("my.Foo",
103 "package my;",
104 "public class Foo {",
105 " public Foo() {}",
106 "}")
107 .build(pluginsDir);
108 initPluginManager();
109 assertEquals(1, pluginManager.getEnabledPlugins().size());
110 assertEquals("Test", pluginManager.getPlugin("test.bundled.plugin").getName());
111 assertEquals("2.0", pluginManager.getPlugin("test.bundled.plugin").getPluginInformation().getVersion());
112 }
113
114 public void testUpgradeWithNewComponentImports() throws Exception
115 {
116 final DefaultModuleDescriptorFactory factory = new DefaultModuleDescriptorFactory(new DefaultHostContainer());
117 factory.addModuleDescriptor("dummy", DummyModuleDescriptor.class);
118 initPluginManager(new HostComponentProvider()
119 {
120 public void provide(final ComponentRegistrar registrar)
121 {
122 registrar.register(SomeInterface.class).forInstance(new SomeInterface()
123 {});
124 registrar.register(AnotherInterface.class).forInstance(new AnotherInterface()
125 {});
126 }
127 }, factory);
128
129 final File pluginJar = new PluginJarBuilder("first")
130 .addFormattedResource("atlassian-plugin.xml",
131 "<atlassian-plugin name='Test' key='test.plugin' pluginsVersion='2'>",
132 " <plugin-info>",
133 " <version>1.0</version>",
134 " </plugin-info>",
135 " <component-import key='comp1' interface='com.atlassian.plugin.osgi.SomeInterface' />",
136 " <dummy key='dum1'/>", "</atlassian-plugin>")
137 .build();
138 final File pluginJar2 = new PluginJarBuilder("second")
139 .addFormattedResource("atlassian-plugin.xml",
140 "<atlassian-plugin name='Test 2' key='test.plugin' pluginsVersion='2'>",
141 " <plugin-info>",
142 " <version>1.0</version>",
143 " </plugin-info>",
144 " <component-import key='comp1' interface='com.atlassian.plugin.osgi.SomeInterface' />",
145 " <component-import key='comp2' interface='com.atlassian.plugin.osgi.AnotherInterface' />",
146 " <dummy key='dum1'/>",
147 " <dummy key='dum2'/>",
148 "</atlassian-plugin>")
149 .build();
150
151 pluginManager.installPlugin(new JarPluginArtifact(pluginJar));
152 assertEquals(1, pluginManager.getEnabledPlugins().size());
153 assertEquals("Test", pluginManager.getPlugin("test.plugin").getName());
154 assertEquals(2, pluginManager.getPlugin("test.plugin").getModuleDescriptors().size());
155 pluginManager.installPlugin(new JarPluginArtifact(pluginJar2));
156 assertEquals(1, pluginManager.getEnabledPlugins().size());
157 assertEquals(4, pluginManager.getPlugin("test.plugin").getModuleDescriptors().size());
158 assertEquals("Test 2", pluginManager.getPlugin("test.plugin").getName());
159 }
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186 public void testUpgradeWithNoAutoDisable() throws Exception
187 {
188 DefaultModuleDescriptorFactory factory = new DefaultModuleDescriptorFactory(new DefaultHostContainer());
189 factory.addModuleDescriptor("dummy", DummyModuleDescriptor.class);
190 initPluginManager(new HostComponentProvider(){
191 public void provide(ComponentRegistrar registrar)
192 {
193 registrar.register(SomeInterface.class).forInstance(new SomeInterface(){});
194 registrar.register(AnotherInterface.class).forInstance(new AnotherInterface(){});
195 }
196 }, factory);
197
198 File pluginJar = new PluginJarBuilder("first")
199 .addFormattedResource("atlassian-plugin.xml",
200 "<atlassian-plugin name='Test' key='test.plugin' pluginsVersion='2'>",
201 " <plugin-info>",
202 " <version>1.0</version>",
203 " </plugin-info>",
204 " <component-import key='comp1' interface='com.atlassian.plugin.osgi.SomeInterface' />",
205 " <dummy key='dum1'/>",
206 "</atlassian-plugin>")
207 .build();
208 final File pluginJar2 = new PluginJarBuilder("second")
209 .addFormattedResource("atlassian-plugin.xml",
210 "<atlassian-plugin name='Test 2' key='test.plugin' pluginsVersion='2'>",
211 " <plugin-info>",
212 " <version>1.0</version>",
213 " </plugin-info>",
214 " <component-import key='comp1' interface='com.atlassian.plugin.osgi.SomeInterface' />",
215 " <dummy key='dum1'/>",
216 " <dummy key='dum2'/>",
217 "</atlassian-plugin>")
218 .build();
219
220 pluginManager.installPlugin(new JarPluginArtifact(pluginJar));
221 assertTrue(pluginManager.isPluginEnabled("test.plugin"));
222
223 final Lock lock = new ReentrantLock();
224 Thread upgradeThread = new Thread()
225 {
226 public void run()
227 {
228 lock.lock();
229 pluginManager.installPlugin(new JarPluginArtifact(pluginJar2));
230 lock.unlock();
231 }
232 };
233
234 Thread isEnabledThread = new Thread()
235 {
236 public void run()
237 {
238 try
239 {
240 while (!lock.tryLock(10, TimeUnit.SECONDS))
241 pluginManager.isPluginEnabled("test.plugin");
242 }
243 catch (InterruptedException e)
244 {
245 fail();
246 }
247 }
248 };
249 upgradeThread.start();
250 isEnabledThread.start();
251
252 upgradeThread.join(10000);
253
254 assertTrue(pluginManager.isPluginEnabled("test.plugin"));
255 }
256
257
258 public void testUpgradeWithNewComponentImplementation() throws Exception
259 {
260 final DefaultModuleDescriptorFactory factory = new DefaultModuleDescriptorFactory(new DefaultHostContainer());
261 factory.addModuleDescriptor("dummy", DummyModuleDescriptor.class);
262 initPluginManager(new HostComponentProvider()
263 {
264 public void provide(final ComponentRegistrar registrar)
265 {
266 registrar.register(SomeInterface.class).forInstance(new SomeInterface()
267 {});
268 registrar.register(AnotherInterface.class).forInstance(new AnotherInterface()
269 {});
270 }
271 }, factory);
272
273 final File pluginJar = new PluginJarBuilder("first")
274 .addFormattedResource("atlassian-plugin.xml",
275 "<atlassian-plugin name='Test' key='test.plugin' pluginsVersion='2'>",
276 " <plugin-info>",
277 " <version>1.0</version>",
278 " </plugin-info>",
279 " <component key='svc' class='my.ServiceImpl' public='true'>",
280 " <interface>java.util.concurrent.Callable</interface>",
281 " </component>",
282 "</atlassian-plugin>")
283 .addFormattedJava("my.ServiceImpl",
284 "package my;",
285 "import java.util.concurrent.Callable;",
286 "public class ServiceImpl implements Callable {",
287 " public Object call() throws Exception { return 'hi';}",
288 "}")
289 .build();
290 final File pluginJar2 = new PluginJarBuilder("second")
291 .addFormattedResource("atlassian-plugin.xml",
292 "<atlassian-plugin name='Test 2' key='test2.plugin' pluginsVersion='2'>",
293 " <plugin-info>",
294 " <version>1.0</version>",
295 " </plugin-info>",
296 " <component-import key='svc' interface='java.util.concurrent.Callable' />",
297 " <component key='del' class='my2.ServiceDelegate' public='true'>",
298 " <interface>com.atlassian.plugin.osgi.Callable2</interface>",
299 " </component>",
300 "</atlassian-plugin>")
301 .addFormattedJava("my2.ServiceDelegate",
302 "package my2;",
303 "import com.atlassian.plugin.osgi.Callable2;",
304 "import java.util.concurrent.Callable;",
305 "public class ServiceDelegate implements Callable2 {",
306 " private final Callable delegate;",
307 " public ServiceDelegate(Callable foo) { this.delegate = foo;}",
308 " public String call() throws Exception { return (String)delegate.call();}",
309 "}")
310 .build();
311
312 pluginManager.installPlugin(new JarPluginArtifact(pluginJar));
313 assertEquals(1, pluginManager.getEnabledPlugins().size());
314
315 pluginManager.installPlugin(new JarPluginArtifact(pluginJar2));
316 final ServiceTracker tracker = osgiContainerManager.getServiceTracker("com.atlassian.plugin.osgi.Callable2");
317
318 for (final Object svc : tracker.getServices())
319 {
320 final Callable2 callable = (Callable2) svc;
321 assertEquals("hi", callable.call());
322 }
323 assertEquals(2, pluginManager.getEnabledPlugins().size());
324
325 final File updatedJar = new PluginJarBuilder("first")
326 .addFormattedResource("atlassian-plugin.xml",
327 "<atlassian-plugin name='Test' key='test.plugin' pluginsVersion='2'>",
328 " <plugin-info>",
329 " <version>1.0</version>",
330 " </plugin-info>",
331 " <component key='svc' class='my.ServiceImpl' public='true'>",
332 " <interface>java.util.concurrent.Callable</interface>",
333 " </component>",
334 "</atlassian-plugin>")
335 .addFormattedJava("my.ServiceImpl",
336 "package my;",
337 "import java.util.concurrent.Callable;",
338 "public class ServiceImpl implements Callable {",
339 " public Object call() throws Exception { return 'bob';}",
340 "}")
341 .build();
342
343 pluginManager.installPlugin(new JarPluginArtifact(updatedJar));
344 WaitUntil.invoke(new AbstractWaitCondition()
345 {
346 public boolean isFinished()
347 {
348 return pluginManager.getEnabledPlugins().size() == 2;
349 }
350 });
351 assertEquals(2, pluginManager.getEnabledPlugins().size());
352 for (final Object svc : tracker.getServices())
353 {
354 final Callable2 callable = (Callable2) svc;
355 assertEquals("bob", callable.call());
356 }
357 }
358
359 public void testUpgradeWithNewComponentImplementationWithInterfaceInPlugin() throws Exception
360 {
361 final DefaultModuleDescriptorFactory factory = new DefaultModuleDescriptorFactory(new DefaultHostContainer());
362 factory.addModuleDescriptor("dummy", DummyModuleDescriptor.class);
363 initPluginManager(new HostComponentProvider()
364 {
365 public void provide(final ComponentRegistrar registrar)
366 {
367 registrar.register(SomeInterface.class).forInstance(new SomeInterface()
368 {});
369 registrar.register(AnotherInterface.class).forInstance(new AnotherInterface()
370 {});
371 }
372 }, factory);
373
374 final PluginJarBuilder builder1 = new PluginJarBuilder("first")
375 .addFormattedResource("atlassian-plugin.xml",
376 "<atlassian-plugin name='Test' key='test.plugin' pluginsVersion='2'>",
377 " <plugin-info>",
378 " <version>1.0</version>",
379 " </plugin-info>",
380 " <component key='svc' class='my.ServiceImpl' public='true'>",
381 " <interface>my.Service</interface>",
382 " </component>",
383 "</atlassian-plugin>")
384 .addFormattedJava("my.Service",
385 "package my;",
386 "public interface Service {",
387 " public Object call() throws Exception;",
388 "}")
389 .addFormattedJava("my.ServiceImpl",
390 "package my;",
391 "public class ServiceImpl implements Service {",
392 " public Object call() throws Exception { return 'hi';}",
393 "}");
394 final File pluginJar = builder1.build();
395 final File pluginJar2 = new PluginJarBuilder("second", builder1.getClassLoader())
396 .addFormattedResource("atlassian-plugin.xml",
397 "<atlassian-plugin name='Test 2' key='test2.plugin' pluginsVersion='2'>",
398 " <plugin-info>",
399 " <version>1.0</version>",
400 " </plugin-info>",
401 " <component-import key='svc' interface='my.Service' />",
402 " <component key='del' class='my2.ServiceDelegate' public='true'>",
403 " <interface>java.util.concurrent.Callable</interface>",
404 " </component>",
405 "</atlassian-plugin>")
406 .addFormattedJava("my2.ServiceDelegate",
407 "package my2;",
408 "import my.Service;",
409 "import java.util.concurrent.Callable;",
410 "public class ServiceDelegate implements Callable {",
411 " private final Service delegate;",
412 " public ServiceDelegate(Service foo) { this.delegate = foo;}",
413 " public Object call() throws Exception { return delegate.call();}",
414 "}")
415 .build();
416
417 pluginManager.installPlugin(new JarPluginArtifact(pluginJar));
418 assertEquals(1, pluginManager.getEnabledPlugins().size());
419 final ServiceTracker tracker = osgiContainerManager.getServiceTracker(Callable.class.getName());
420 final ServiceTracker svcTracker = osgiContainerManager.getServiceTracker("my.Service");
421
422 pluginManager.installPlugin(new JarPluginArtifact(pluginJar2));
423 assertEquals("hi", svcTracker.getService().getClass().getMethod("call").invoke(svcTracker.getService()));
424 assertEquals("hi", ((Callable) tracker.getService()).call());
425
426 assertEquals(2, pluginManager.getEnabledPlugins().size());
427
428 final File updatedJar = new PluginJarBuilder("first")
429 .addFormattedResource("atlassian-plugin.xml",
430 "<atlassian-plugin name='Test' key='test.plugin' pluginsVersion='2'>",
431 " <plugin-info>",
432 " <version>1.0</version>",
433 " </plugin-info>",
434 " <component key='svc' class='my.Service2Impl' public='true'>",
435 " <interface>my.Service</interface>",
436 " </component>",
437 "</atlassian-plugin>")
438 .addFormattedJava("my.Service",
439 "package my;",
440 "public interface Service {",
441 " public Object call() throws Exception;",
442 "}")
443 .addFormattedJava("my.Service2Impl",
444 "package my;",
445 "public class Service2Impl implements Service {",
446 " public Object call() throws Exception {return 'bob';}",
447 "}")
448 .build();
449
450 pluginManager.installPlugin(new JarPluginArtifact(updatedJar));
451 assertEquals("bob", svcTracker.getService().getClass().getMethod("call").invoke(svcTracker.getService()));
452 tracker.waitForService(5000);
453 assertEquals("bob", ((Callable) tracker.getService()).call());
454 }
455
456 public void testUpgradeWithRefreshingAffectingOtherPlugins() throws Exception
457 {
458 final DefaultModuleDescriptorFactory factory = new DefaultModuleDescriptorFactory(new DefaultHostContainer());
459 initPluginManager(new HostComponentProvider()
460 {
461 public void provide(final ComponentRegistrar registrar)
462 {
463 }
464 }, factory);
465
466 PluginJarBuilder pluginBuilder = new PluginJarBuilder("first")
467 .addFormattedResource("atlassian-plugin.xml",
468 "<atlassian-plugin name='Test' key='test.plugin' pluginsVersion='2'>",
469 " <plugin-info>",
470 " <version>1.0</version>",
471 " <bundle-instructions><Export-Package>my</Export-Package></bundle-instructions>",
472 " </plugin-info>",
473 " <component key='svc' class='my.ServiceImpl' public='true'>",
474 " <interface>java.util.concurrent.Callable</interface>",
475 " </component>",
476 "</atlassian-plugin>")
477 .addFormattedJava("my.ServiceImpl",
478 "package my;",
479 "import java.util.concurrent.Callable;",
480 "public class ServiceImpl implements Callable {",
481 " public Object call() throws Exception { return 'hi';}",
482 "}");
483 final File pluginJar = pluginBuilder.build();
484
485 final File pluginJar2 = new PluginJarBuilder("second", pluginBuilder.getClassLoader())
486 .addFormattedResource("atlassian-plugin.xml",
487 "<atlassian-plugin name='Test 2' key='test2.plugin' pluginsVersion='2'>",
488 " <plugin-info>",
489 " <version>1.0</version>",
490 " <bundle-instructions><Import-Package>my,*</Import-Package></bundle-instructions>",
491 " </plugin-info>",
492 " <component-import key='svc' interface='java.util.concurrent.Callable' />",
493 " <component-import key='othersvc' interface='com.atlassian.plugin.osgi.Callable3' />",
494 " <component key='del' class='my2.ServiceDelegate' public='true'>",
495 " <interface>com.atlassian.plugin.osgi.Callable2</interface>",
496 " </component>",
497 "</atlassian-plugin>")
498 .addFormattedJava("my2.ServiceDelegate",
499 "package my2;",
500 "import com.atlassian.plugin.osgi.Callable2;",
501 "import com.atlassian.plugin.osgi.Callable3;",
502 "import java.util.concurrent.Callable;",
503 "public class ServiceDelegate implements Callable2 {",
504 " private final Callable delegate;",
505 " private final Callable3 othersvc;",
506 " public ServiceDelegate(Callable foo,Callable3 othersvc) {",
507 " this.delegate = foo;",
508 " this.othersvc = othersvc;",
509 " }",
510 " public String call() throws Exception { return othersvc.call() + (String)delegate.call();}",
511 "}")
512 .build();
513 final File otherSvcJar = new PluginJarBuilder("otherSvc")
514 .addFormattedResource("atlassian-plugin.xml",
515 "<atlassian-plugin name='Test' key='test.othersvc.plugin' pluginsVersion='2'>",
516 " <plugin-info>",
517 " <version>1.0</version>",
518 " </plugin-info>",
519 " <component key='othersvc' class='othersvc.ServiceImpl' public='true'>",
520 " <interface>com.atlassian.plugin.osgi.Callable3</interface>",
521 " </component>",
522 "</atlassian-plugin>")
523 .addFormattedJava("othersvc.ServiceImpl",
524 "package othersvc;",
525 "import com.atlassian.plugin.osgi.Callable3;",
526 "public class ServiceImpl implements Callable3 {",
527 " public String call() throws Exception { return 'hi';}",
528 "}")
529 .build();
530
531
532 pluginManager.installPlugin(new JarPluginArtifact(pluginJar));
533 assertEquals(1, pluginManager.getEnabledPlugins().size());
534
535 pluginManager.installPlugin(new JarPluginArtifact(otherSvcJar));
536 pluginManager.installPlugin(new JarPluginArtifact(pluginJar2));
537
538 assertEquals("hi", ((OsgiPlugin)pluginManager.getPlugin("test2.plugin")).autowire(Callable3Aware.class).call());
539 assertEquals(3, pluginManager.getEnabledPlugins().size());
540
541 final File updatedJar = new PluginJarBuilder("first")
542 .addFormattedResource("atlassian-plugin.xml",
543 "<atlassian-plugin name='Test' key='test.plugin' pluginsVersion='2'>",
544 " <plugin-info>",
545 " <version>1.0</version>",
546 " <bundle-instructions><Export-Package>my</Export-Package></bundle-instructions>",
547 " </plugin-info>",
548 " <component key='svc' class='my.ServiceImpl' public='true'>",
549 " <interface>java.util.concurrent.Callable</interface>",
550 " </component>",
551 "</atlassian-plugin>")
552 .addFormattedJava("my.ServiceImpl",
553 "package my;",
554 "import java.util.concurrent.Callable;",
555 "public class ServiceImpl implements Callable {",
556 " public Object call() throws Exception { return 'bob';}",
557 "}")
558 .build();
559
560 final RefreshHappened refresh = new RefreshHappened();
561 pluginEventManager.register(refresh);
562 pluginManager.installPlugin(new JarPluginArtifact(updatedJar));
563 WaitUntil.invoke(new BasicWaitCondition()
564 {
565 public boolean isFinished()
566 {
567 return refresh.refreshHappened;
568 }
569
570 });
571 assertEquals(3, pluginManager.getEnabledPlugins().size());
572 assertEquals("hi", ((OsgiPlugin)pluginManager.getPlugin("test2.plugin")).autowire(Callable3Aware.class).call());
573 }
574
575
576
577 public void testUpgradeTestingForCachedXml() throws Exception
578 {
579 final DefaultModuleDescriptorFactory factory = new DefaultModuleDescriptorFactory(new DefaultHostContainer());
580 factory.addModuleDescriptor("dummy", DummyModuleDescriptor.class);
581 initPluginManager(new HostComponentProvider()
582 {
583 public void provide(final ComponentRegistrar registrar)
584 {
585 registrar.register(SomeInterface.class).forInstance(new SomeInterface()
586 {});
587 registrar.register(AnotherInterface.class).forInstance(new AnotherInterface()
588 {});
589 }
590 }, factory);
591
592 final File pluginJar = new PluginJarBuilder("first").addFormattedResource("atlassian-plugin.xml",
593 "<atlassian-plugin name='Test' key='test.plugin' pluginsVersion='2'>", " <plugin-info>", " <version>1.0</version>",
594 " </plugin-info>", " <component key='comp1' interface='com.atlassian.plugin.osgi.SomeInterface' class='my.ServiceImpl' />",
595 "</atlassian-plugin>").addFormattedJava("my.ServiceImpl", "package my;",
596 "public class ServiceImpl implements com.atlassian.plugin.osgi.SomeInterface {}").build();
597 final File pluginJar2 = new PluginJarBuilder("second").addFormattedResource("atlassian-plugin.xml",
598 "<atlassian-plugin name='Test 2' key='test.plugin' pluginsVersion='2'>", " <plugin-info>", " <version>1.0</version>",
599 " </plugin-info>", "</atlassian-plugin>").build();
600
601 pluginManager.installPlugin(new JarPluginArtifact(pluginJar));
602 assertEquals(1, pluginManager.getEnabledPlugins().size());
603 assertEquals("Test", pluginManager.getPlugin("test.plugin").getName());
604 pluginManager.installPlugin(new JarPluginArtifact(pluginJar2));
605 assertEquals(1, pluginManager.getEnabledPlugins().size());
606 assertEquals("Test 2", pluginManager.getPlugin("test.plugin").getName());
607 }
608
609 public void testPluginDependentOnPackageImport() throws Exception
610 {
611 HostComponentProvider prov = new HostComponentProvider()
612 {
613 public void provide(final ComponentRegistrar registrar)
614 {
615 registrar.register(ServletConfig.class).forInstance(new HttpServlet() {});
616 }
617 };
618 File servletJar = new PluginJarBuilder("first")
619 .addFormattedResource("META-INF/MANIFEST.MF",
620 "Export-Package: javax.servlet.http;version='4.0.0',javax.servlet;version='4.0.0'",
621 "Import-Package: javax.servlet.http;version='4.0.0',javax.servlet;version='4.0.0'",
622 "Bundle-SymbolicName: first",
623 "Bundle-Version: 4.0.0",
624 "Manifest-Version: 1.0",
625 "")
626 .addFormattedJava("javax.servlet.Servlet",
627 "package javax.servlet;",
628 "public interface Servlet {}")
629 .addFormattedJava("javax.servlet.http.HttpServlet",
630 "package javax.servlet.http;",
631 "public abstract class HttpServlet implements javax.servlet.Servlet{}")
632 .build();
633
634 File pluginJar = new PluginJarBuilder("asecond")
635 .addFormattedResource("atlassian-plugin.xml",
636 "<atlassian-plugin name='Test' key='second' pluginsVersion='2'>",
637 " <plugin-info>",
638 " <version>1.0</version>",
639 " <bundle-instructions><Import-Package>javax.servlet.http;version='[2.3,2.3]',javax.servlet;version='[2.3,2.3]',*</Import-Package></bundle-instructions>",
640 " </plugin-info>",
641 "</atlassian-plugin>")
642 .addFormattedJava("second.MyImpl",
643 "package second;",
644 "public class MyImpl {",
645 " public MyImpl(javax.servlet.ServletConfig config) {",
646 " }",
647 "}")
648 .build();
649
650 initPluginManager(prov);
651 pluginManager.installPlugin(new JarPluginArtifact(servletJar));
652 pluginManager.installPlugin(new JarPluginArtifact(pluginJar));
653
654 assertEquals(2, pluginManager.getEnabledPlugins().size());
655 assertNotNull(pluginManager.getPlugin("first-4.0.0"));
656 assertNotNull(pluginManager.getPlugin("second"));
657 }
658
659 public void testPluginWithHostComponentUsingOldPackageImport() throws Exception
660 {
661 final PluginJarBuilder firstBuilder = new PluginJarBuilder("first");
662 firstBuilder
663 .addFormattedResource("atlassian-plugin.xml",
664 "<atlassian-plugin name='Test' key='first' pluginsVersion='2'>",
665 " <plugin-info>",
666 " <version>1.0</version>",
667 " <bundle-instructions>",
668 " <Export-Package>first</Export-Package>",
669 " </bundle-instructions>",
670 " </plugin-info>",
671 " <servlet key='foo' class='second.MyServlet'>",
672 " <url-pattern>/foo</url-pattern>",
673 " </servlet>",
674 "</atlassian-plugin>")
675 .addFormattedJava("first.MyInterface",
676 "package first;",
677 "public interface MyInterface {}")
678 .build(pluginsDir);
679
680 new PluginJarBuilder("asecond", firstBuilder.getClassLoader())
681 .addPluginInformation("second", "Some name", "1.0")
682 .addFormattedJava("second.MyImpl",
683 "package second;",
684 "public class MyImpl implements first.MyInterface {}")
685 .build(pluginsDir);
686
687 initPluginManager();
688
689 assertEquals(2, pluginManager.getEnabledPlugins().size());
690 assertNotNull(pluginManager.getPlugin("first"));
691 assertNotNull(pluginManager.getPlugin("second"));
692 }
693
694 public void testPluginWithServletDependentOnPackageImport() throws Exception
695 {
696 final PluginJarBuilder firstBuilder = new PluginJarBuilder("first");
697 firstBuilder
698 .addPluginInformation("first", "Some name", "1.0")
699 .addFormattedJava("first.MyInterface",
700 "package first;",
701 "public interface MyInterface {}")
702 .addFormattedResource("META-INF/MANIFEST.MF",
703 "Manifest-Version: 1.0",
704 "Bundle-SymbolicName: first",
705 "Bundle-Version: 1.0",
706 "Export-Package: first",
707 "")
708 .build(pluginsDir);
709
710 new PluginJarBuilder("asecond", firstBuilder.getClassLoader())
711 .addFormattedResource("atlassian-plugin.xml",
712 "<atlassian-plugin name='Test' key='asecond' pluginsVersion='2'>",
713 " <plugin-info>",
714 " <version>1.0</version>",
715 " </plugin-info>",
716 " <servlet key='foo' class='second.MyServlet'>",
717 " <url-pattern>/foo</url-pattern>",
718 " </servlet>",
719 "</atlassian-plugin>")
720 .addFormattedJava("second.MyServlet",
721 "package second;",
722 "public class MyServlet extends javax.servlet.http.HttpServlet implements first.MyInterface {}")
723 .build(pluginsDir);
724
725 initPluginManager(null, new SingleModuleDescriptorFactory(new DefaultHostContainer(), "servlet", StubServletModuleDescriptor.class));
726
727 assertEquals(2, pluginManager.getEnabledPlugins().size());
728 assertTrue(pluginManager.getPlugin("first").getPluginState() == PluginState.ENABLED);
729 assertNotNull(pluginManager.getPlugin("asecond").getPluginState() == PluginState.ENABLED);
730 }
731
732 public void testPluginWithServletRefreshedAfterOtherPluginUpgraded() throws Exception
733 {
734 final PluginJarBuilder firstBuilder = new PluginJarBuilder("first");
735 firstBuilder
736 .addPluginInformation("first", "Some name", "1.0")
737 .addFormattedJava("first.MyInterface",
738 "package first;",
739 "public interface MyInterface {}")
740 .addFormattedResource("META-INF/MANIFEST.MF",
741 "Manifest-Version: 1.0",
742 "Bundle-SymbolicName: first",
743 "Bundle-Version: 1.0",
744 "Export-Package: first",
745 "")
746 .build(pluginsDir);
747
748 new PluginJarBuilder("asecond", firstBuilder.getClassLoader())
749 .addFormattedResource("atlassian-plugin.xml",
750 "<atlassian-plugin name='Test' key='asecond' pluginsVersion='2'>",
751 " <plugin-info>",
752 " <version>1.0</version>",
753 " </plugin-info>",
754 " <servlet key='foo' class='second.MyServlet'>",
755 " <url-pattern>/foo</url-pattern>",
756 " </servlet>",
757 "</atlassian-plugin>")
758 .addFormattedJava("second.MyServlet",
759 "package second;",
760 "import com.atlassian.plugin.osgi.Callable2;",
761 "public class MyServlet extends javax.servlet.http.HttpServlet implements first.MyInterface {",
762 " private Callable2 callable;",
763 " public MyServlet(Callable2 cal) { this.callable = cal; }",
764 " public String getServletInfo() {",
765 " try {return callable.call() + ' bob';} catch (Exception ex) { throw new RuntimeException(ex);}",
766 " }",
767 "}")
768 .build(pluginsDir);
769
770 HostComponentProvider prov = new HostComponentProvider()
771 {
772
773 public void provide(ComponentRegistrar registrar)
774 {
775 registrar.register(Callable2.class).forInstance(new Callable2()
776 {
777 public String call()
778 {
779 return "hi";
780 }
781 });
782
783 }
784 };
785
786 Mock mockServletContext = new Mock(ServletContext.class);
787 mockServletContext.expectAndReturn("getInitParameterNames", Collections.enumeration(Collections.emptyList()));
788 mockServletContext.expect("log", C.ANY_ARGS);
789 mockServletContext.expect("log", C.ANY_ARGS);
790 mockServletContext.expect("log", C.ANY_ARGS);
791 Mock mockServletConfig = new Mock(ServletConfig.class);
792 mockServletConfig.matchAndReturn("getServletContext", mockServletContext.proxy());
793
794 ServletModuleManager mgr = new DefaultServletModuleManager(pluginEventManager);
795 Mock mockHostContainer = new Mock(HostContainer.class);
796 mockHostContainer.matchAndReturn("create", C.args(C.eq(ServletModuleDescriptor.class)), new StubServletModuleDescriptor(mgr));
797 initPluginManager(prov, new SingleModuleDescriptorFactory(
798 (HostContainer) mockHostContainer.proxy(),
799 "servlet",
800 ServletModuleDescriptor.class));
801
802 assertEquals(2, pluginManager.getEnabledPlugins().size());
803 assertTrue(pluginManager.getPlugin("first").getPluginState() == PluginState.ENABLED);
804 assertNotNull(pluginManager.getPlugin("asecond").getPluginState() == PluginState.ENABLED);
805 assertEquals("hi bob", mgr.getServlet("/foo", (ServletConfig) mockServletConfig.proxy()).getServletInfo());
806
807
808
809 final File updatedJar = new PluginJarBuilder("first-updated")
810 .addPluginInformation("foo", "Some name", "1.0")
811 .addFormattedJava("first.MyInterface",
812 "package first;",
813 "public interface MyInterface {}")
814 .addFormattedResource("META-INF/MANIFEST.MF",
815 "Manifest-Version: 1.0",
816 "Bundle-SymbolicName: foo",
817 "Bundle-Version: 1.0",
818 "Export-Package: first",
819 "")
820 .build();
821 pluginManager.installPlugin(new JarPluginArtifact(updatedJar));
822
823 WaitUntil.invoke(new BasicWaitCondition()
824 {
825 public boolean isFinished()
826 {
827 return pluginManager.isPluginEnabled("asecond");
828 }
829
830 });
831
832 assertEquals("hi bob", mgr.getServlet("/foo", (ServletConfig) mockServletConfig.proxy()).getServletInfo());
833 }
834
835 public void testLotsOfHostComponents() throws Exception
836 {
837 new PluginJarBuilder("first")
838 .addFormattedResource("atlassian-plugin.xml",
839 "<atlassian-plugin name='Test' key='test.plugin' pluginsVersion='2'>",
840 " <plugin-info>",
841 " <version>1.0</version>",
842 " </plugin-info>",
843 " <dummy key='dum1'/>",
844 "</atlassian-plugin>")
845 .build(pluginsDir);
846 new PluginJarBuilder("second")
847 .addFormattedResource("atlassian-plugin.xml",
848 "<atlassian-plugin name='Test 2' key='test.plugin2' pluginsVersion='2'>",
849 " <plugin-info>",
850 " <version>1.0</version>",
851 " </plugin-info>",
852 " <dummy key='dum1'/>",
853 " <dummy key='dum2'/>",
854 "</atlassian-plugin>")
855 .build(pluginsDir);
856
857 final DefaultModuleDescriptorFactory factory = new DefaultModuleDescriptorFactory(new DefaultHostContainer());
858 factory.addModuleDescriptor("dummy", DummyModuleDescriptor.class);
859 initPluginManager(new HostComponentProvider()
860 {
861 public void provide(final ComponentRegistrar registrar)
862 {
863 for (int x = 0; x < 100; x++)
864 {
865 registrar.register(SomeInterface.class).forInstance(new SomeInterface()
866 {}).withName("some" + x);
867 registrar.register(AnotherInterface.class).forInstance(new AnotherInterface()
868 {}).withName("another" + x);
869 }
870 }
871 }, factory);
872
873 assertEquals(2, pluginManager.getEnabledPlugins().size());
874 }
875
876 public void testInstallWithManifestNoSpringContextAndComponents() throws Exception
877 {
878 final BooleanFlag flag = new DefaultBooleanFlag(false);
879 new PluginJarBuilder("first")
880 .addFormattedResource("atlassian-plugin.xml",
881 "<atlassian-plugin name='Test' key='first' pluginsVersion='2'>",
882 " <plugin-info>",
883 " <version>1.0</version>",
884 " </plugin-info>",
885 " <component key='foo' class='first.MyClass' interface='first.MyInterface' public='true'/>",
886 "</atlassian-plugin>")
887 .addFormattedJava("first.MyInterface",
888 "package first;",
889 "public interface MyInterface {}")
890 .addFormattedJava("first.MyClass",
891 "package first;",
892 "public class MyClass implements MyInterface{",
893 " public MyClass(com.atlassian.plugin.osgi.BooleanFlag bool) { bool.set(true); }",
894 "}")
895 .addFormattedResource("META-INF/MANIFEST.MF",
896 "Manifest-Version: 1.0",
897 "Bundle-SymbolicName: foo",
898 "Bundle-Version: 1.0",
899 "Export-Package: first",
900 "")
901 .build(pluginsDir);
902
903 initPluginManager(new HostComponentProvider()
904 {
905 public void provide(ComponentRegistrar registrar)
906 {
907 registrar.register(BooleanFlag.class).forInstance(flag).withName("bob");
908 }
909 });
910
911 assertEquals(1, pluginManager.getEnabledPlugins().size());
912 assertNotNull(pluginManager.getPlugin("first"));
913 assertTrue(flag.get());
914 }
915
916 public void testInstallWithStrangePath() throws Exception
917 {
918 File strangeDir = new File(tmpDir, "20%time");
919 strangeDir.mkdir();
920 File oldTmp = tmpDir;
921 try
922 {
923 tmpDir = strangeDir;
924 cacheDir = new File(tmpDir, "felix-cache");
925 cacheDir.mkdir();
926 pluginsDir = new File(tmpDir, "plugins");
927 pluginsDir.mkdir();
928
929
930 new PluginJarBuilder("strangePath")
931 .addFormattedResource("atlassian-plugin.xml",
932 "<atlassian-plugin name='Test' key='test.plugin' pluginsVersion='2'>",
933 " <plugin-info>",
934 " <version>1.0</version>",
935 " </plugin-info>",
936 "</atlassian-plugin>")
937 .build(pluginsDir);
938
939 final DefaultModuleDescriptorFactory factory = new DefaultModuleDescriptorFactory(new DefaultHostContainer());
940 factory.addModuleDescriptor("dummy", DummyModuleDescriptor.class);
941 initPluginManager(new HostComponentProvider()
942 {
943 public void provide(final ComponentRegistrar registrar)
944 {
945 }
946 }, factory);
947
948 assertEquals(1, pluginManager.getEnabledPlugins().size());
949 }
950 finally
951 {
952 tmpDir = oldTmp;
953 }
954 }
955
956 public void testInstallWithUnsatisifedDependency() throws Exception
957 {
958 File plugin = new PluginJarBuilder("unsatisifiedDependency")
959 .addFormattedResource("atlassian-plugin.xml",
960 "<atlassian-plugin name='Test' key='test.plugin' pluginsVersion='2'>",
961 " <plugin-info>",
962 " <version>1.0</version>",
963 " </plugin-info>",
964 " <component-import key='foo' interface='java.util.concurrent.Callable' />",
965 "</atlassian-plugin>")
966 .build(pluginsDir);
967
968 long start = System.currentTimeMillis();
969
970 System.setProperty("atlassian.dev.mode", "true");
971 try
972 {
973 initPluginManager();
974
975 assertTrue(start + (60 * 1000) > System.currentTimeMillis());
976 }
977 finally
978 {
979
980 System.setProperty("atlassian.dev.mode", "false");
981 }
982 }
983 public void testInstallSimplePluginNoSpring() throws Exception
984 {
985 File jar = new PluginJarBuilder("strangePath")
986 .addPluginInformation("no-spring", "foo", "1.0")
987 .build();
988
989 initPluginManager();
990 pluginManager.installPlugin(new JarPluginArtifact(jar));
991
992 assertEquals(1, pluginManager.getEnabledPlugins().size());
993 }
994
995 public static class Callable3Aware
996 {
997 private final Callable3 callable;
998
999 public Callable3Aware(Callable3 callable)
1000 {
1001 this.callable = callable;
1002 }
1003
1004 public String call() throws Exception
1005 {
1006 return callable.call();
1007 }
1008 }
1009
1010 public static class RefreshHappened
1011 {
1012 public volatile boolean refreshHappened = false;
1013 @PluginEventListener
1014 public void foo(PluginRefreshedEvent evt)
1015 {
1016 if (evt.getPlugin().getKey().equals("test2.plugin"))
1017 {
1018 refreshHappened = true;
1019 }
1020 }
1021 }
1022 }