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.PluginRestartState;
7 import com.atlassian.plugin.PluginState;
8 import com.atlassian.plugin.descriptors.AbstractModuleDescriptor;
9 import com.atlassian.plugin.descriptors.RequiresRestart;
10 import com.atlassian.plugin.hostcontainer.DefaultHostContainer;
11 import com.atlassian.plugin.module.ContainerManagedPlugin;
12 import com.atlassian.plugin.module.ModuleFactory;
13 import com.atlassian.plugin.osgi.hostcomponents.ComponentRegistrar;
14 import com.atlassian.plugin.osgi.hostcomponents.HostComponentProvider;
15 import com.atlassian.plugin.test.PluginJarBuilder;
16 import com.atlassian.plugin.util.WaitUntil;
17 import org.osgi.framework.Bundle;
18 import org.osgi.util.tracker.ServiceTracker;
19
20 import java.io.File;
21
22 public class TestEnableDisablePlugin extends PluginInContainerTestBase
23 {
24 public void testEnableDisableEnable() throws Exception
25 {
26 File pluginJar = new PluginJarBuilder("enabledisabletest")
27 .addPluginInformation("enabledisable", "foo", "1.0")
28 .addJava("my.Foo", "package my;" +
29 "public class Foo {}")
30 .build();
31 initPluginManager(null);
32 pluginManager.installPlugin(new JarPluginArtifact(pluginJar));
33 Plugin plugin = pluginManager.getPlugin("enabledisable");
34 assertNotNull(((ContainerManagedPlugin)plugin).getContainerAccessor().createBean(plugin.loadClass("my.Foo", this.getClass())));
35 pluginManager.disablePlugin("enabledisable");
36 pluginManager.enablePlugin("enabledisable");
37
38 plugin = pluginManager.getPlugin("enabledisable");
39
40 assertNotNull(((ContainerManagedPlugin)plugin).getContainerAccessor().createBean(plugin.loadClass("my.Foo", this.getClass())));
41 }
42
43 public void testEnableDisableEnableWithPublicComponent() throws Exception
44 {
45 File pluginJar = new PluginJarBuilder("enabledisabletest")
46 .addFormattedResource("atlassian-plugin.xml",
47 "<atlassian-plugin name='Test 2' key='enabledisablewithcomponent' pluginsVersion='2'>",
48 " <plugin-info>",
49 " <version>1.0</version>",
50 " </plugin-info>",
51 " <component key='foo' class='my.Foo' public='true' interface='my.Fooable'/>",
52 "</atlassian-plugin>")
53 .addJava("my.Fooable", "package my;" +
54 "public interface Fooable {}")
55 .addFormattedJava("my.Foo", "package my;",
56 "public class Foo implements Fooable, org.springframework.beans.factory.DisposableBean {",
57 " public void destroy() throws Exception { Thread.sleep(500); }",
58 "}")
59 .build();
60 initPluginManager(null);
61 pluginManager.installPlugin(new JarPluginArtifact(pluginJar));
62 Plugin plugin = pluginManager.getPlugin("enabledisablewithcomponent");
63 assertEquals(PluginState.ENABLED, plugin.getPluginState());
64 assertNotNull(((ContainerManagedPlugin)plugin).getContainerAccessor().createBean(plugin.loadClass("my.Foo", this.getClass())));
65 pluginManager.disablePlugin("enabledisablewithcomponent");
66 pluginManager.enablePlugin("enabledisablewithcomponent");
67
68 plugin = pluginManager.getPlugin("enabledisablewithcomponent");
69 assertEquals(PluginState.ENABLED, plugin.getPluginState());
70
71 assertNotNull(((ContainerManagedPlugin)plugin).getContainerAccessor().createBean(plugin.loadClass("my.Foo", this.getClass())));
72 }
73
74 public void testDisableEnableOfPluginThatRequiresRestart() throws Exception
75 {
76 final DefaultModuleDescriptorFactory factory = new DefaultModuleDescriptorFactory(new DefaultHostContainer());
77 factory.addModuleDescriptor("requiresRestart", RequiresRestartModuleDescriptor.class);
78 new PluginJarBuilder()
79 .addFormattedResource("atlassian-plugin.xml",
80 "<atlassian-plugin name='Test 2' key='test.restartrequired' pluginsVersion='2'>",
81 " <plugin-info>",
82 " <version>1.0</version>",
83 " </plugin-info>",
84 " <requiresRestart key='foo' />",
85 "</atlassian-plugin>")
86 .build(pluginsDir);
87
88 initPluginManager(null, factory);
89
90 assertEquals(1, pluginManager.getPlugins().size());
91 assertNotNull(pluginManager.getPlugin("test.restartrequired"));
92 assertTrue(pluginManager.isPluginEnabled("test.restartrequired"));
93 assertEquals(1, pluginManager.getEnabledModuleDescriptorsByClass(RequiresRestartModuleDescriptor.class).size());
94 assertEquals(PluginRestartState.NONE, pluginManager.getPluginRestartState("test.restartrequired"));
95
96 pluginManager.disablePlugin("test.restartrequired");
97 assertFalse(pluginManager.isPluginEnabled("test.restartrequired"));
98 pluginManager.enablePlugin("test.restartrequired");
99
100 assertEquals(1, pluginManager.getPlugins().size());
101 assertNotNull(pluginManager.getPlugin("test.restartrequired"));
102 assertTrue(pluginManager.isPluginEnabled("test.restartrequired"));
103 assertEquals(PluginRestartState.NONE, pluginManager.getPluginRestartState("test.restartrequired"));
104 assertEquals(1, pluginManager.getEnabledModuleDescriptorsByClass(RequiresRestartModuleDescriptor.class).size());
105 }
106
107 public void testEnableEnablesDependentPlugins() throws Exception
108 {
109 PluginJarBuilder builderProvider = new PluginJarBuilder("enabledisable-prov")
110 .addFormattedResource("atlassian-plugin.xml",
111 "<atlassian-plugin name='Test' key='provider' pluginsVersion='2'>",
112 " <plugin-info>",
113 " <version>1.0</version>",
114 " <bundle-instructions><Export-Package>my</Export-Package></bundle-instructions>",
115 " </plugin-info>",
116 "</atlassian-plugin>")
117 .addJava("my.Foo", "package my;" +
118 "public interface Foo {}");
119
120 PluginJarBuilder builderConsumer = new PluginJarBuilder("enabledisable-con", builderProvider.getClassLoader())
121 .addFormattedResource("atlassian-plugin.xml",
122 "<atlassian-plugin name='Test' key='consumer' pluginsVersion='2'>",
123 " <plugin-info>",
124 " <version>1.0</version>",
125 " <bundle-instructions><Import-Package>my</Import-Package></bundle-instructions>",
126 " </plugin-info>",
127 "</atlassian-plugin>")
128 .addJava("my2.Bar", "package my2;" +
129 "public class Bar implements my.Foo {}");
130
131 initPluginManager(null);
132 pluginManager.installPlugin(new JarPluginArtifact(builderProvider.build()));
133 pluginManager.installPlugin(new JarPluginArtifact(builderConsumer.build()));
134
135 Plugin provider = pluginManager.getPlugin("provider");
136 Plugin consumer = pluginManager.getPlugin("consumer");
137 assertEquals(PluginState.ENABLED, provider.getPluginState());
138 assertEquals(PluginState.ENABLED, consumer.getPluginState());
139
140 pluginManager.disablePlugin("provider");
141 pluginManager.disablePlugin("consumer");
142
143 assertEquals(PluginState.DISABLED, provider.getPluginState());
144 assertEquals(PluginState.DISABLED, consumer.getPluginState());
145
146 pluginManager.enablePlugin("consumer");
147 assertEquals(PluginState.ENABLED, consumer.getPluginState());
148 assertEquals(PluginState.ENABLED, provider.getPluginState());
149 }
150
151 public void testStoppedOsgiBundleDetected() throws Exception
152 {
153 new PluginJarBuilder("osgi")
154 .addFormattedResource("META-INF/MANIFEST.MF",
155 "Manifest-Version: 1.0",
156 "Bundle-SymbolicName: my",
157 "Bundle-Version: 1.0",
158 "")
159 .build(pluginsDir);
160 initPluginManager();
161 Plugin plugin = pluginManager.getPlugin("my-1.0");
162 assertTrue(pluginManager.isPluginEnabled("my-1.0"));
163 assertTrue(plugin.getPluginState() == PluginState.ENABLED);
164
165 for (Bundle bundle : osgiContainerManager.getBundles())
166 {
167 if (bundle.getSymbolicName().equals("my"))
168 {
169 bundle.stop();
170 }
171 }
172
173 assertFalse(pluginManager.isPluginEnabled("my-1.0"));
174 assertTrue(plugin.getPluginState() == PluginState.DISABLED);
175
176 }
177
178 public void testStartedOsgiBundleDetected() throws Exception
179 {
180 new PluginJarBuilder("osgi")
181 .addFormattedResource("META-INF/MANIFEST.MF",
182 "Manifest-Version: 1.0",
183 "Bundle-SymbolicName: my",
184 "Bundle-Version: 1.0",
185 "")
186 .build(pluginsDir);
187 initPluginManager();
188 Plugin plugin = pluginManager.getPlugin("my-1.0");
189 assertTrue(pluginManager.isPluginEnabled("my-1.0"));
190 assertTrue(plugin.getPluginState() == PluginState.ENABLED);
191
192 for (Bundle bundle : osgiContainerManager.getBundles())
193 {
194 if (bundle.getSymbolicName().equals("my"))
195 {
196 bundle.stop();
197 bundle.start();
198 }
199 }
200
201 assertTrue(WaitUntil.invoke(new WaitUntil.WaitCondition()
202 {
203 public boolean isFinished()
204 {
205 return pluginManager.isPluginEnabled("my-1.0");
206 }
207
208 public String getWaitMessage()
209 {
210 return null;
211 }
212 }));
213 assertTrue(pluginManager.isPluginEnabled("my-1.0"));
214 assertTrue(plugin.getPluginState() == PluginState.ENABLED);
215 }
216
217
218 public void testStoppedOsgiPluginDetected() throws Exception
219 {
220 new PluginJarBuilder("osgi")
221 .addPluginInformation("my", "foo", "1.0")
222 .build(pluginsDir);
223 initPluginManager();
224 Plugin plugin = pluginManager.getPlugin("my");
225 assertTrue(pluginManager.isPluginEnabled("my"));
226 assertTrue(plugin.getPluginState() == PluginState.ENABLED);
227
228 for (Bundle bundle : osgiContainerManager.getBundles())
229 {
230 if (bundle.getSymbolicName().equals("my"))
231 {
232 bundle.stop();
233 }
234 }
235
236 assertFalse(pluginManager.isPluginEnabled("my"));
237 assertTrue(plugin.getPluginState() == PluginState.DISABLED);
238
239 }
240
241
242 public void testEnableEnablesDependentPluginsWithBundles() throws Exception
243 {
244 PluginJarBuilder builderProvider = new PluginJarBuilder("enabledisable-prov")
245 .addFormattedResource("META-INF/MANIFEST.MF",
246 "Manifest-Version: 1.0",
247 "Bundle-SymbolicName: my",
248 "Atlassian-Plugin-Key: provider",
249 "Export-Package: my",
250 "")
251 .addJava("my.Foo", "package my;" +
252 "public interface Foo {}");
253
254
255
256 PluginJarBuilder builderConsumer = new PluginJarBuilder("enabledisable-con", builderProvider.getClassLoader())
257 .addFormattedResource("atlassian-plugin.xml",
258 "<atlassian-plugin name='Test' key='consumer' pluginsVersion='2'>",
259 " <plugin-info>",
260 " <version>1.0</version>",
261 " <bundle-instructions><Import-Package>my</Import-Package></bundle-instructions>",
262 " </plugin-info>",
263 "</atlassian-plugin>")
264 .addJava("my2.Bar", "package my2;" +
265 "public class Bar implements my.Foo {}");
266
267 initPluginManager(null);
268 pluginManager.installPlugin(new JarPluginArtifact(builderProvider.build()));
269 pluginManager.installPlugin(new JarPluginArtifact(builderConsumer.build()));
270
271 Plugin provider = pluginManager.getPlugin("provider");
272 Plugin consumer = pluginManager.getPlugin("consumer");
273 assertEquals(PluginState.ENABLED, provider.getPluginState());
274 assertEquals(PluginState.ENABLED, consumer.getPluginState());
275
276 pluginManager.disablePlugin("provider");
277 pluginManager.disablePlugin("consumer");
278
279 assertEquals(PluginState.DISABLED, provider.getPluginState());
280 assertEquals(PluginState.DISABLED, consumer.getPluginState());
281
282 pluginManager.enablePlugin("consumer");
283 assertEquals(PluginState.ENABLED, consumer.getPluginState());
284 assertEquals(PluginState.ENABLED, provider.getPluginState());
285 }
286
287 public void testDisableDoesNotKillLongRunningOperation() throws Exception
288 {
289 File pluginJar = new PluginJarBuilder("longrunning")
290 .addFormattedResource("atlassian-plugin.xml",
291 "<atlassian-plugin name='Test' key='longrunning' pluginsVersion='2'>",
292 " <plugin-info>",
293 " <version>1.0</version>",
294 " </plugin-info>",
295 " <component key='comp' class='my.Foo' public='true'>",
296 " <interface>com.atlassian.plugin.osgi.Callable3</interface>",
297 " </component>",
298 "</atlassian-plugin>")
299 .addFormattedJava("my.Foo",
300 "package my;",
301 "import com.atlassian.plugin.osgi.*;",
302 "public class Foo implements Callable3{",
303 " private Callable2 callable;",
304 " public Foo(Callable2 callable) {",
305 " this.callable = callable;",
306 " }",
307 " public String call() throws Exception {",
308 " Thread.sleep(2000);",
309 " return callable.call();",
310 " }",
311 "}")
312 .build();
313 initPluginManager(new HostComponentProvider()
314 {
315 public void provide(ComponentRegistrar registrar)
316 {
317 registrar.register(Callable2.class).forInstance(new Callable2()
318 {
319
320 public String call()
321 {
322 return "called";
323 }
324 }).withName("foobar");
325 }
326 });
327
328 pluginManager.installPlugin(new JarPluginArtifact(pluginJar));
329 assertTrue(pluginManager.getPlugin("longrunning").getPluginState() == PluginState.ENABLED);
330 final ServiceTracker tracker = osgiContainerManager.getServiceTracker("com.atlassian.plugin.osgi.Callable3");
331 final Callable3 service = (Callable3) tracker.getService();
332 final StringBuilder sb = new StringBuilder();
333 Thread t = new Thread()
334 {
335 public void run()
336 {
337 try
338 {
339 sb.append(service.call());
340 }
341 catch (Exception e)
342 {
343 throw new RuntimeException(e);
344 }
345 }
346 };
347 t.start();
348 pluginManager.disablePlugin("longrunning");
349 t.join();
350 assertEquals("called", sb.toString());
351 }
352
353 @RequiresRestart
354 public static class RequiresRestartModuleDescriptor extends AbstractModuleDescriptor<Void>
355 {
356 public RequiresRestartModuleDescriptor()
357 {
358 super(ModuleFactory.LEGACY_MODULE_FACTORY);
359 }
360
361 @Override
362 public Void getModule()
363 {
364 throw new UnsupportedOperationException("You should never be getting a module from this descriptor " + this.getClass().getName());
365 }
366 }
367 }