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