View Javadoc

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