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
41
42 private DefaultPluginManager manager;
43
44 private PluginPersistentStateStore pluginStateStore;
45 private List<PluginLoader> pluginLoaders;
46 private DefaultModuleDescriptorFactory moduleDescriptorFactory;
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
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
163 }
164
165
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
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
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
232 }
233
234
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
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
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 }