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