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