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