View Javadoc

1   package com.atlassian.plugin.manager;
2   
3   import com.atlassian.plugin.DefaultModuleDescriptorFactory;
4   import com.atlassian.plugin.JarPluginArtifact;
5   import com.atlassian.plugin.Plugin;
6   import com.atlassian.plugin.PluginAccessor;
7   import com.atlassian.plugin.PluginInformation;
8   import com.atlassian.plugin.PluginParseException;
9   import com.atlassian.plugin.PluginState;
10  import com.atlassian.plugin.descriptors.MockUnusedModuleDescriptor;
11  import com.atlassian.plugin.descriptors.RequiresRestart;
12  import com.atlassian.plugin.event.PluginEventManager;
13  import com.atlassian.plugin.event.impl.DefaultPluginEventManager;
14  import com.atlassian.plugin.factories.LegacyDynamicPluginFactory;
15  import com.atlassian.plugin.factories.XmlDynamicPluginFactory;
16  import com.atlassian.plugin.hostcontainer.DefaultHostContainer;
17  import com.atlassian.plugin.impl.AbstractDelegatingPlugin;
18  import com.atlassian.plugin.impl.StaticPlugin;
19  import com.atlassian.plugin.loaders.DirectoryPluginLoader;
20  import com.atlassian.plugin.loaders.PluginLoader;
21  import com.atlassian.plugin.loaders.classloading.AbstractTestClassLoader;
22  import com.atlassian.plugin.manager.store.MemoryPluginPersistentStateStore;
23  import com.atlassian.plugin.mock.MockAnimalModuleDescriptor;
24  import com.atlassian.plugin.repositories.FilePluginInstaller;
25  import com.atlassian.plugin.test.PluginJarBuilder;
26  import com.mockobjects.dynamic.C;
27  import com.mockobjects.dynamic.Mock;
28  import org.apache.commons.io.FileUtils;
29  
30  import java.io.File;
31  import java.io.InputStream;
32  import java.util.ArrayList;
33  import java.util.Arrays;
34  import java.util.Collections;
35  import java.util.List;
36  
37  public class TestDefaultPluginManagerLongRunning extends AbstractTestClassLoader
38  {
39      /**
40       * the object being tested
41       */
42      private DefaultPluginManager manager;
43  
44      private PluginPersistentStateStore pluginStateStore;
45      private List<PluginLoader> pluginLoaders;
46      private DefaultModuleDescriptorFactory moduleDescriptorFactory; // we should be able to use the interface here?
47  
48      private DirectoryPluginLoader directoryPluginLoader;
49      private PluginEventManager pluginEventManager;
50  
51      @Override
52      protected void setUp() throws Exception
53      {
54          super.setUp();
55          pluginEventManager = new DefaultPluginEventManager();
56  
57          pluginStateStore = new MemoryPluginPersistentStateStore();
58          pluginLoaders = new ArrayList<PluginLoader>();
59          moduleDescriptorFactory = new DefaultModuleDescriptorFactory(new DefaultHostContainer());
60  
61          manager = new DefaultPluginManager(pluginStateStore, pluginLoaders, moduleDescriptorFactory, new DefaultPluginEventManager());
62      }
63  
64      @Override
65      protected void tearDown() throws Exception
66      {
67          manager = null;
68          moduleDescriptorFactory = null;
69          pluginLoaders = null;
70          pluginStateStore = null;
71  
72          if (directoryPluginLoader != null)
73          {
74              directoryPluginLoader.shutDown();
75              directoryPluginLoader = null;
76          }
77  
78          super.tearDown();
79      }
80  
81      public void testEnableFailed() throws PluginParseException
82      {
83          final Mock mockPluginLoader = new Mock(PluginLoader.class);
84          final Plugin plugin = new StaticPlugin()
85          {
86              public PluginState enableInternal()
87              {
88                  return PluginState.DISABLED;
89              }
90  
91              public void disableInternal()
92              {
93                  // do nothing
94              }
95          };
96          plugin.setKey("foo");
97          plugin.setEnabledByDefault(false);
98          plugin.setPluginInformation(new PluginInformation());
99  
100         mockPluginLoader.expectAndReturn("loadAllPlugins", C.ANY_ARGS, Collections.singletonList(plugin));
101 
102         final PluginLoader proxy = (PluginLoader) mockPluginLoader.proxy();
103         pluginLoaders.add(proxy);
104         manager.init();
105 
106         assertEquals(1, manager.getPlugins().size());
107         assertEquals(0, manager.getEnabledPlugins().size());
108         assertFalse(plugin.getPluginState() == PluginState.ENABLED);
109         manager.enablePlugin("foo");
110         assertEquals(1, manager.getPlugins().size());
111         assertEquals(0, manager.getEnabledPlugins().size());
112         assertFalse(plugin.getPluginState() == PluginState.ENABLED);
113     }
114 
115     private DefaultPluginManager makeClassLoadingPluginManager() throws PluginParseException
116     {
117         directoryPluginLoader = new DirectoryPluginLoader(pluginsTestDir, Arrays.asList(new LegacyDynamicPluginFactory(
118                 PluginAccessor.Descriptor.FILENAME), new XmlDynamicPluginFactory("foo")), pluginEventManager);
119         pluginLoaders.add(directoryPluginLoader);
120 
121         moduleDescriptorFactory.addModuleDescriptor("animal", MockAnimalModuleDescriptor.class);
122         manager.init();
123         return manager;
124     }
125 
126     public void testInstallPluginTwiceWithSameName() throws Exception
127     {
128         createFillAndCleanTempPluginDirectory();
129 
130         FileUtils.cleanDirectory(pluginsTestDir);
131         final File plugin = File.createTempFile("plugin", ".jar");
132         plugin.delete();
133         File jar = new PluginJarBuilder("plugin")
134                 .addPluginInformation("some.key", "My name", "1.0", 1)
135                 .addResource("foo.txt", "foo")
136                 .addJava("my.MyClass",
137                         "package my; public class MyClass {}")
138                 .build();
139         FileUtils.moveFile(jar, plugin);
140 
141         final DefaultPluginManager manager = makeClassLoadingPluginManager();
142         manager.setPluginInstaller(new FilePluginInstaller(pluginsTestDir));
143 
144         final String pluginKey = manager.installPlugin(new JarPluginArtifact(plugin));
145 
146         assertTrue(new File(pluginsTestDir, plugin.getName()).exists());
147 
148         final Plugin installedPlugin = manager.getPlugin(pluginKey);
149         assertNotNull(installedPlugin);
150         InputStream s0 = installedPlugin.getClassLoader().getResourceAsStream("foo.txt");
151         assertNotNull(s0);
152         s0.close();
153         assertNull(installedPlugin.getClassLoader().getResourceAsStream("bar.txt"));
154         assertNotNull(installedPlugin.getClassLoader().loadClass("my.MyClass"));
155         try
156         {
157             installedPlugin.getClassLoader().loadClass("my.MyNewClass");
158             fail("Expected ClassNotFoundException for unknown class");
159         }
160         catch (final ClassNotFoundException e)
161         {
162             // expected
163         }
164 
165         // sleep to ensure the new plugin is picked up
166         Thread.sleep(1000);
167 
168         File jartmp = new PluginJarBuilder("plugin")
169                 .addPluginInformation("some.key", "My name", "1.0", 1)
170                 .addResource("bar.txt", "bar")
171                 .addJava("my.MyNewClass",
172                         "package my; public class MyNewClass {}")
173                 .build();
174         plugin.delete();
175         FileUtils.moveFile(jartmp, plugin);
176 
177         // reinstall the plugin
178         final String pluginKey2 = manager.installPlugin(new JarPluginArtifact(plugin));
179 
180         assertTrue(new File(pluginsTestDir, plugin.getName()).exists());
181 
182         final Plugin installedPlugin2 = manager.getPlugin(pluginKey2);
183         assertNotNull(installedPlugin2);
184         assertEquals(1, manager.getEnabledPlugins().size());
185         assertNull(installedPlugin2.getClassLoader().getResourceAsStream("foo.txt"));
186         InputStream s1 = installedPlugin2.getClassLoader().getResourceAsStream("bar.txt");
187         assertNotNull(s1);
188         s1.close();
189         assertNotNull(installedPlugin2.getClassLoader().loadClass("my.MyNewClass"));
190         try
191         {
192             installedPlugin2.getClassLoader().loadClass("my.MyClass");
193             fail("Expected ClassNotFoundException for unknown class");
194         }
195         catch (final ClassNotFoundException e)
196         {
197             // expected
198         }
199     }
200 
201     public void testInstallPluginTwiceWithDifferentName() throws Exception
202     {
203         createFillAndCleanTempPluginDirectory();
204 
205         FileUtils.cleanDirectory(pluginsTestDir);
206         final File plugin1 = new PluginJarBuilder("plugin").addPluginInformation("some.key", "My name", "1.0", 1).addResource("foo.txt", "foo").addJava(
207                 "my.MyClass", "package my; public class MyClass {}").build();
208 
209         final DefaultPluginManager manager = makeClassLoadingPluginManager();
210         manager.setPluginInstaller(new FilePluginInstaller(pluginsTestDir));
211 
212         final String pluginKey = manager.installPlugin(new JarPluginArtifact(plugin1));
213 
214         assertTrue(new File(pluginsTestDir, plugin1.getName()).exists());
215 
216         final Plugin installedPlugin = manager.getPlugin(pluginKey);
217         assertNotNull(installedPlugin);
218         InputStream s0 = installedPlugin.getClassLoader().getResourceAsStream("foo.txt");
219         assertNotNull(s0);
220         s0.close();
221         InputStream s1 = installedPlugin.getClassLoader().getResourceAsStream("bar.txt");
222         assertNull(s1);
223         assertNotNull(installedPlugin.getClassLoader().loadClass("my.MyClass"));
224         try
225         {
226             installedPlugin.getClassLoader().loadClass("my.MyNewClass");
227             fail("Expected ClassNotFoundException for unknown class");
228         }
229         catch (final ClassNotFoundException e)
230         {
231             // expected
232         }
233 
234         // sleep to ensure the new plugin is picked up
235         Thread.sleep(1000);
236 
237         final File plugin2 = new PluginJarBuilder("plugin").addPluginInformation("some.key", "My name", "1.0", 1)
238                 .addResource("bar.txt", "bar").addJava("my.MyNewClass", "package my; public class MyNewClass {}")
239                 .build();
240 
241         // reinstall the plugin
242         final String pluginKey2 = manager.installPlugin(new JarPluginArtifact(plugin2));
243 
244         assertFalse(new File(pluginsTestDir, plugin1.getName()).exists());
245         assertTrue(new File(pluginsTestDir, plugin2.getName()).exists());
246 
247         final Plugin installedPlugin2 = manager.getPlugin(pluginKey2);
248         assertNotNull(installedPlugin2);
249         assertEquals(1, manager.getEnabledPlugins().size());
250         InputStream s2 = installedPlugin2.getClassLoader().getResourceAsStream("foo.txt");
251         assertNull(s2);
252         InputStream s3 = installedPlugin2.getClassLoader().getResourceAsStream("bar.txt");
253         assertNotNull(s3);
254         s3.close();
255         assertNotNull(installedPlugin2.getClassLoader().loadClass("my.MyNewClass"));
256         try
257         {
258             installedPlugin2.getClassLoader().loadClass("my.MyClass");
259             fail("Expected ClassNotFoundException for unknown class");
260         }
261         catch (final ClassNotFoundException e)
262         {
263             // expected
264         }
265     }
266 
267     public void testAddPluginsWithDependencyIssuesNoResolution() throws Exception
268     {
269         final Plugin servicePlugin = new EnableInPassPlugin("service.plugin", 4);
270         final Plugin clientPlugin = new EnableInPassPlugin("client.plugin", 1);
271 
272         manager.addPlugins(null, Arrays.asList(servicePlugin, clientPlugin));
273 
274         assertTrue(clientPlugin.getPluginState() == PluginState.ENABLED);
275         assertFalse(servicePlugin.getPluginState() == PluginState.ENABLED);
276     }
277 
278     public Plugin createPluginWithVersion(final String version)
279     {
280         final Plugin p = new StaticPlugin();
281         p.setKey("test.default.plugin");
282         final PluginInformation pInfo = p.getPluginInformation();
283         pInfo.setVersion(version);
284         return p;
285     }
286 
287     private static class EnableInPassPlugin extends AbstractDelegatingPlugin
288     {
289         private int pass;
290 
291         public EnableInPassPlugin(final String key, final int pass)
292         {
293             super(new StaticPlugin());
294             this.pass = pass;
295             setKey(key);
296         }
297 
298         @Override
299         public void enable()
300         {
301             if (--pass <= 0)
302             {
303                 super.enable();
304             }
305         }
306     }
307 
308     class NothingModuleDescriptor extends MockUnusedModuleDescriptor
309     {
310     }
311 
312     @RequiresRestart
313     public static class RequiresRestartModuleDescriptor extends MockUnusedModuleDescriptor
314     {
315     }
316 }