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