1 package com.atlassian.plugin;
2
3 import com.atlassian.plugin.classloader.PluginsClassLoader;
4 import com.atlassian.plugin.descriptors.UnloadableModuleDescriptor;
5 import com.atlassian.plugin.descriptors.UnloadableModuleDescriptorFactory;
6 import com.atlassian.plugin.impl.UnloadablePlugin;
7 import com.atlassian.plugin.impl.UnloadablePluginFactory;
8 import com.atlassian.plugin.loaders.DynamicPluginLoader;
9 import com.atlassian.plugin.loaders.PluginLoader;
10 import com.atlassian.plugin.parsers.DescriptorParserFactory;
11 import com.atlassian.plugin.predicate.*;
12 import com.atlassian.plugin.event.PluginEventManager;
13 import com.atlassian.plugin.event.events.PluginDisabledEvent;
14 import com.atlassian.plugin.event.events.PluginEnabledEvent;
15 import com.atlassian.plugin.event.events.PluginFrameworkStartedEvent;
16 import com.atlassian.plugin.event.events.PluginFrameworkShutdownEvent;
17 import com.atlassian.plugin.event.events.PluginFrameworkStartingEvent;
18 import com.atlassian.plugin.util.WaitUntil;
19 import com.atlassian.plugin.util.PluginUtils;
20 import org.apache.commons.collections.Closure;
21 import org.apache.commons.collections.CollectionUtils;
22 import org.apache.commons.collections.Predicate;
23 import org.apache.commons.logging.Log;
24 import org.apache.commons.logging.LogFactory;
25
26 import java.io.InputStream;
27 import java.util.*;
28 import static java.lang.Thread.*;
29
30
31
32
33
34
35
36
37
38
39
40
41 public class DefaultPluginManager implements PluginManager
42 {
43 private static final Log log = LogFactory.getLog(DefaultPluginManager.class);
44 private final List<PluginLoader> pluginLoaders;
45 private final PluginStateStore store;
46 private final ModuleDescriptorFactory moduleDescriptorFactory;
47 private final PluginsClassLoader classLoader;
48 private final Map<String,Plugin> plugins = new HashMap<String,Plugin>();
49 private final PluginEventManager pluginEventManager;
50
51
52
53
54 private PluginInstaller pluginInstaller;
55
56
57
58
59 private final Map<Plugin,PluginLoader> pluginToPluginLoader = new HashMap<Plugin,PluginLoader>();
60
61 public DefaultPluginManager(PluginStateStore store, List<PluginLoader> pluginLoaders, ModuleDescriptorFactory moduleDescriptorFactory, PluginEventManager pluginEventManager)
62 {
63 if (store == null)
64 {
65 throw new IllegalArgumentException("PluginStateStore must not be null.");
66 }
67 if (pluginLoaders == null)
68 {
69 throw new IllegalArgumentException("Plugin Loaders list must not be null.");
70 }
71 if (moduleDescriptorFactory == null)
72 {
73 throw new IllegalArgumentException("ModuleDescriptorFactory must not be null.");
74 }
75 if (pluginEventManager == null)
76 {
77 throw new IllegalArgumentException("PluginEventManager must not be null.");
78 }
79 this.pluginLoaders = pluginLoaders;
80 this.store = store;
81 this.moduleDescriptorFactory = moduleDescriptorFactory;
82 this.pluginEventManager = pluginEventManager;
83 classLoader = new PluginsClassLoader(this);
84 }
85
86
87
88
89
90
91 public void init() throws PluginParseException
92 {
93 log.info("Initialising the plugin system");
94 pluginEventManager.broadcast(new PluginFrameworkStartingEvent(this, this));
95 for (PluginLoader loader : pluginLoaders)
96 {
97 if (loader == null) continue;
98
99 addPlugins(loader, loader.loadAllPlugins(moduleDescriptorFactory));
100 }
101 pluginEventManager.broadcast(new PluginFrameworkStartedEvent(this, this));
102 }
103
104
105
106
107
108 public void shutdown()
109 {
110 log.info("Shutting down the plugin system");
111 pluginEventManager.broadcast(new PluginFrameworkShutdownEvent(this, this));
112 }
113
114
115
116
117
118
119
120 public void setPluginInstaller(PluginInstaller pluginInstaller)
121 {
122 this.pluginInstaller = pluginInstaller;
123 }
124
125 protected final PluginStateStore getStore()
126 {
127 return store;
128 }
129
130 public String installPlugin(PluginArtifact pluginArtifact) throws PluginParseException
131 {
132 String key = validatePlugin(pluginArtifact);
133 pluginInstaller.installPlugin(key, pluginArtifact);
134 scanForNewPlugins();
135 return key;
136 }
137
138
139
140
141
142
143
144
145
146
147 String validatePlugin(PluginArtifact pluginArtifact) throws PluginParseException
148 {
149 String key;
150
151 boolean foundADynamicPluginLoader = false;
152 for (PluginLoader loader : pluginLoaders)
153 {
154 if (loader instanceof DynamicPluginLoader)
155 {
156 foundADynamicPluginLoader = true;
157 key = ((DynamicPluginLoader) loader).canLoad(pluginArtifact);
158 if (key != null)
159 return key;
160 }
161 }
162
163 if (!foundADynamicPluginLoader)
164 {
165 throw new IllegalStateException("Should be at least one DynamicPluginLoader in the plugin loader list");
166 }
167 throw new PluginParseException("Jar " + pluginArtifact.getName() + " is not a valid plugin");
168 }
169
170 public int scanForNewPlugins() throws PluginParseException
171 {
172 int numberFound = 0;
173
174 for (PluginLoader loader : pluginLoaders)
175 {
176 if (loader != null)
177 {
178 if (loader.supportsAddition())
179 {
180 List<Plugin> pluginsToAdd = new ArrayList<Plugin>();
181 for (Plugin plugin : loader.addFoundPlugins(moduleDescriptorFactory))
182 {
183
184
185 if (!(plugin instanceof UnloadablePlugin) && PluginUtils.doesPluginRequireRestart(plugin))
186 {
187 try
188 {
189 plugin.close();
190 }
191 catch (RuntimeException ex)
192 {
193 log.warn("Unable to uninstall the plugin after it was determined to require a restart", ex);
194 }
195 UnloadablePlugin unloadablePlugin = new UnloadablePlugin("Plugin requires a restart of the application");
196 unloadablePlugin.setKey(plugin.getKey());
197 plugin = unloadablePlugin;
198 }
199 pluginsToAdd.add(plugin);
200 }
201 addPlugins(loader, pluginsToAdd);
202 numberFound = pluginsToAdd.size();
203 }
204 }
205 }
206
207 return numberFound;
208 }
209
210 public void uninstall(Plugin plugin) throws PluginException
211 {
212 unloadPlugin(plugin);
213
214
215 removeStateFromStore(getStore(), plugin);
216 }
217
218 protected void removeStateFromStore(PluginStateStore stateStore, Plugin plugin)
219 {
220 PluginManagerState currentState = stateStore.loadPluginState();
221 currentState.removeState(plugin.getKey());
222 for (ModuleDescriptor<?> moduleDescriptor : plugin.getModuleDescriptors())
223 {
224 currentState.removeState(moduleDescriptor.getCompleteKey());
225 }
226 stateStore.savePluginState(currentState);
227 }
228
229
230
231
232
233
234
235
236 protected void unloadPlugin(Plugin plugin) throws PluginException
237 {
238 if (!plugin.isUninstallable())
239 throw new PluginException("Plugin is not uninstallable: " + plugin.getKey());
240
241 PluginLoader loader = pluginToPluginLoader.get(plugin);
242
243 if (loader != null && !loader.supportsRemoval())
244 {
245 throw new PluginException("Not uninstalling plugin - loader doesn't allow removal. Plugin: " + plugin.getKey());
246 }
247
248 if (isPluginEnabled(plugin.getKey()))
249 notifyPluginDisabled(plugin);
250
251 notifyUninstallPlugin(plugin);
252 if (loader != null)
253 {
254 removePluginFromLoader(plugin);
255 }
256
257 plugins.remove(plugin.getKey());
258 }
259
260 private void removePluginFromLoader(Plugin plugin) throws PluginException
261 {
262 if (plugin.isDeleteable())
263 {
264 PluginLoader pluginLoader = pluginToPluginLoader.get(plugin);
265 pluginLoader.removePlugin(plugin);
266 }
267
268 pluginToPluginLoader.remove(plugin);
269 }
270
271 protected void notifyUninstallPlugin(Plugin plugin)
272 {
273 classLoader.notifyUninstallPlugin(plugin);
274
275 for (ModuleDescriptor descriptor : plugin.getModuleDescriptors())
276 {
277 descriptor.destroy(plugin);
278 }
279 }
280
281 protected PluginManagerState getState()
282 {
283 return getStore().loadPluginState();
284 }
285
286
287
288
289 protected void addPlugin(PluginLoader loader, Plugin plugin) throws PluginParseException
290 {
291 addPlugins(loader, Collections.singletonList(plugin));
292 }
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308 protected void addPlugins(PluginLoader loader, Collection<Plugin> pluginsToAdd) throws PluginParseException
309 {
310 final Set<Plugin> pluginsThatShouldBeEnabled = new HashSet<Plugin>();
311 for (Plugin plugin : new TreeSet<Plugin>(pluginsToAdd))
312 {
313
314 if (plugins.containsKey(plugin.getKey()))
315 {
316 Plugin existingPlugin = plugins.get(plugin.getKey());
317 if (plugin.compareTo(existingPlugin) >= 0)
318 {
319 try
320 {
321 updatePlugin(existingPlugin, plugin);
322 }
323 catch (PluginException e)
324 {
325 throw new PluginParseException("Duplicate plugin found (installed version is the same or older) and could not be unloaded: '" + plugin.getKey() + "'", e);
326 }
327 }
328 else
329 {
330
331 if (log.isDebugEnabled())
332 log.debug("Duplicate plugin found (installed version is newer): '" + plugin.getKey() + "'");
333
334 continue;
335 }
336 }
337
338 plugins.put(plugin.getKey(), plugin);
339 if (isPluginEnabled(plugin.getKey()))
340 {
341 plugin.setEnabled(true);
342 pluginsThatShouldBeEnabled.add(plugin);
343 }
344
345 pluginToPluginLoader.put(plugin, loader);
346 }
347
348 if (!plugins.isEmpty())
349 {
350
351 WaitUntil.invoke(new WaitUntil.WaitCondition()
352 {
353 public boolean isFinished()
354 {
355 for (Iterator<Plugin> i = pluginsThatShouldBeEnabled.iterator(); i.hasNext(); )
356 {
357 Plugin plugin = i.next();
358 if (plugin.isEnabled())
359 i.remove();
360 }
361 return pluginsThatShouldBeEnabled.isEmpty();
362 }
363
364 public String getWaitMessage() {return "Plugins that have yet to start: "+pluginsThatShouldBeEnabled;}
365 }, 60);
366
367
368
369 if (!pluginsThatShouldBeEnabled.isEmpty())
370 {
371 StringBuilder sb = new StringBuilder();
372 for (Plugin plugin : pluginsThatShouldBeEnabled)
373 {
374 sb.append(plugin.getKey()).append(',');
375 disablePlugin(plugin.getKey());
376 }
377 sb.deleteCharAt(sb.length() - 1);
378 log.error("Unable to start the following plugins: " + sb.toString());
379 }
380 }
381
382 for (Plugin plugin : pluginsToAdd)
383 if (plugin.isEnabled())
384 enablePluginModules(plugin);
385
386 }
387
388
389
390
391
392
393
394
395
396 protected void updatePlugin(final Plugin oldPlugin, final Plugin newPlugin) throws PluginException
397 {
398 if (!oldPlugin.getKey().equals(newPlugin.getKey()))
399 throw new IllegalArgumentException("New plugin must have the same key as the old plugin");
400
401 if (log.isInfoEnabled())
402 log.info("Updating plugin '" + oldPlugin + "' to '" + newPlugin + "'");
403
404
405
406
407 Map<String,Boolean> oldPluginState = getState().getPluginStateMap(oldPlugin);
408
409 if (log.isDebugEnabled()) log.debug("Uninstalling old plugin: " + oldPlugin);
410 uninstall(oldPlugin);
411 if (log.isDebugEnabled()) log.debug("Plugin uninstalled '" + oldPlugin +"', preserving old state");
412
413
414 final Set<String> newModuleKeys = new HashSet<String>();
415 newModuleKeys.add(newPlugin.getKey());
416
417 for (Iterator moduleIter = newPlugin.getModuleDescriptors().iterator(); moduleIter.hasNext();)
418 {
419 ModuleDescriptor moduleDescriptor = (ModuleDescriptor) moduleIter.next();
420 newModuleKeys.add(moduleDescriptor.getCompleteKey());
421 }
422
423
424 CollectionUtils.filter(oldPluginState.keySet(), new Predicate()
425 {
426 public boolean evaluate(Object o)
427 {
428 return newModuleKeys.contains(o);
429 }
430 });
431
432
433 PluginManagerState currentState = getState();
434 currentState.getMap().putAll(oldPluginState);
435 getStore().savePluginState(currentState);
436 }
437
438 public Collection<Plugin> getPlugins()
439 {
440 return plugins.values();
441 }
442
443
444
445
446
447 public Collection<Plugin> getPlugins(final PluginPredicate pluginPredicate)
448 {
449 return CollectionUtils.select(getPlugins(), new Predicate()
450 {
451 public boolean evaluate(Object o)
452 {
453 return pluginPredicate.matches((Plugin) o);
454 }
455 });
456 }
457
458
459
460
461 public Collection<Plugin> getEnabledPlugins()
462 {
463 return getPlugins(new EnabledPluginPredicate(this));
464 }
465
466
467
468
469
470 public <T> Collection<T> getModules(final ModuleDescriptorPredicate<T> moduleDescriptorPredicate)
471 {
472 Collection<ModuleDescriptor<T>> moduleDescriptors = getModuleDescriptors(moduleDescriptorPredicate);
473 return getModules(moduleDescriptors);
474 }
475
476
477
478
479
480 public <T> Collection<ModuleDescriptor<T>> getModuleDescriptors(final ModuleDescriptorPredicate<T> moduleDescriptorPredicate)
481 {
482 final Collection<ModuleDescriptor<T>> moduleDescriptors = new ArrayList<ModuleDescriptor<T>>();
483 for (ModuleDescriptor<?> desc : getModuleDescriptors(getPlugins()))
484 moduleDescriptors.add((ModuleDescriptor<T>) desc);
485
486 CollectionUtils.filter(moduleDescriptors, new Predicate()
487 {
488 public boolean evaluate(Object o)
489 {
490 return moduleDescriptorPredicate.matches((ModuleDescriptor) o);
491 }
492 });
493 return moduleDescriptors;
494 }
495
496
497
498
499
500
501
502 private Collection<ModuleDescriptor<?>> getModuleDescriptors(final Collection<Plugin> plugins)
503 {
504 final Collection<ModuleDescriptor<?>> moduleDescriptors = new LinkedList<ModuleDescriptor<?>>();
505 for (Plugin plugin : plugins)
506 {
507 moduleDescriptors.addAll(plugin.getModuleDescriptors());
508 }
509 return moduleDescriptors;
510 }
511
512
513
514
515
516
517
518
519 private <T> List<T> getModules(final Collection<ModuleDescriptor<T>> moduleDescriptors)
520 {
521 final List<T> result = new ArrayList<T>();
522 CollectionUtils.forAllDo(moduleDescriptors, new Closure()
523 {
524 public void execute(Object o)
525 {
526 CollectionUtils.addIgnoreNull(result, ((ModuleDescriptor) o).getModule());
527 }
528 });
529 return result;
530 }
531
532 public Plugin getPlugin(String key)
533 {
534 return plugins.get(key);
535 }
536
537 public Plugin getEnabledPlugin(String pluginKey)
538 {
539 if (!isPluginEnabled(pluginKey))
540 return null;
541
542 return getPlugin(pluginKey);
543 }
544
545 public ModuleDescriptor getPluginModule(String completeKey)
546 {
547 ModuleCompleteKey key = new ModuleCompleteKey(completeKey);
548
549 final Plugin plugin = getPlugin(key.getPluginKey());
550
551 if (plugin == null)
552 return null;
553
554 return plugin.getModuleDescriptor(key.getModuleKey());
555 }
556
557 public ModuleDescriptor getEnabledPluginModule(String completeKey)
558 {
559 ModuleCompleteKey key = new ModuleCompleteKey(completeKey);
560
561
562 if (!isPluginModuleEnabled(completeKey))
563 return null;
564
565 return getEnabledPlugin(key.getPluginKey()).getModuleDescriptor(key.getModuleKey());
566 }
567
568
569
570
571 public <T> List<T> getEnabledModulesByClass(final Class<T> moduleClass)
572 {
573 return getModules(getEnabledModuleDescriptorsByModuleClass(moduleClass));
574 }
575
576
577
578
579
580 public <T> List<T> getEnabledModulesByClassAndDescriptor(final Class<ModuleDescriptor<T>>[] descriptorClasses, final Class<T> moduleClass)
581 {
582 final Collection moduleDescriptors = getEnabledModuleDescriptorsByModuleClass(moduleClass);
583 filterModuleDescriptors(moduleDescriptors, new ModuleDescriptorOfClassPredicate(descriptorClasses));
584
585 return (List<T>) getModules(moduleDescriptors);
586 }
587
588
589
590
591
592 public <T> List<T> getEnabledModulesByClassAndDescriptor(final Class<ModuleDescriptor<T>> descriptorClass, final Class<T> moduleClass)
593 {
594 final Collection moduleDescriptors = getEnabledModuleDescriptorsByModuleClass(moduleClass);
595 filterModuleDescriptors(moduleDescriptors, new ModuleDescriptorOfClassPredicate(descriptorClass));
596
597 return (List<T>) getModules(moduleDescriptors);
598 }
599
600
601
602
603
604
605
606 private <T> Collection<ModuleDescriptor<T>> getEnabledModuleDescriptorsByModuleClass(final Class<T> moduleClass)
607 {
608 final Collection<ModuleDescriptor<?>> moduleDescriptors = getModuleDescriptors(getEnabledPlugins());
609 filterModuleDescriptors(moduleDescriptors, new ModuleOfClassPredicate(moduleClass));
610 filterModuleDescriptors(moduleDescriptors, new EnabledModulePredicate(this));
611
612
613 List<ModuleDescriptor<T>> list = new ArrayList<ModuleDescriptor<T>>();
614 for (Object o : moduleDescriptors)
615 list.add((ModuleDescriptor<T>) o);
616 return list;
617 }
618
619 public <T extends ModuleDescriptor> List<T> getEnabledModuleDescriptorsByClass(Class<T> moduleDescriptorClass)
620 {
621 return getEnabledModuleDescriptorsByClass(moduleDescriptorClass, false);
622 }
623
624
625
626
627
628
629
630
631 public <T extends ModuleDescriptor> List<T> getEnabledModuleDescriptorsByClass(Class<T> moduleDescriptorClass, boolean verbose)
632 {
633 final List<T> result = new LinkedList<T>();
634 for (Plugin plugin : plugins.values())
635 {
636
637 if (!isPluginEnabled(plugin.getKey()))
638 {
639 if (verbose && log.isInfoEnabled())
640 {
641 log.info("Plugin [" + plugin.getKey() + "] is disabled.");
642 }
643 continue;
644 }
645
646 for (ModuleDescriptor module : plugin.getModuleDescriptors())
647 {
648 if (moduleDescriptorClass.isInstance(module) && isPluginModuleEnabled(module.getCompleteKey()))
649 {
650 result.add((T) module);
651 } else
652 {
653 if (verbose && log.isInfoEnabled())
654 {
655 log.info("Module [" + module.getCompleteKey() + "] is disabled.");
656 }
657 }
658 }
659 }
660
661 return result;
662 }
663
664
665
666
667
668 public List<ModuleDescriptor<?>> getEnabledModuleDescriptorsByType(String type) throws PluginParseException, IllegalArgumentException
669 {
670 final Collection<ModuleDescriptor<?>> moduleDescriptors = getModuleDescriptors(getEnabledPlugins());
671 filterModuleDescriptors(moduleDescriptors, new ModuleDescriptorOfTypePredicate(moduleDescriptorFactory, type));
672 filterModuleDescriptors(moduleDescriptors, new EnabledModulePredicate(this));
673 return (List<ModuleDescriptor<?>>) moduleDescriptors;
674 }
675
676
677
678
679
680
681
682 private static void filterModuleDescriptors(final Collection moduleDescriptors, final ModuleDescriptorPredicate moduleDescriptorPredicate)
683 {
684 CollectionUtils.filter(moduleDescriptors, new Predicate()
685 {
686 public boolean evaluate(Object o)
687 {
688 return moduleDescriptorPredicate.matches((ModuleDescriptor) o);
689 }
690 });
691 }
692
693 public void enablePlugin(String key)
694 {
695 if (key == null)
696 throw new IllegalArgumentException("You must specify a plugin key to disable.");
697
698 if (!plugins.containsKey(key))
699 {
700 if (log.isInfoEnabled())
701 log.info("No plugin was found for key '" + key + "'. Not enabling.");
702
703 return;
704 }
705
706 Plugin plugin = (Plugin) plugins.get(key);
707
708 if (!plugin.getPluginInformation().satisfiesMinJavaVersion())
709 {
710 log.error("Minimum Java version of '" + plugin.getPluginInformation().getMinJavaVersion() + "' was not satisfied for module '" + key + "'. Not enabling.");
711 return;
712 }
713
714 plugin.setEnabled(true);
715
716
717 if (WaitUntil.invoke(new PluginEnabledCondition(plugin)))
718 {
719 enablePluginState(plugin, getStore());
720 notifyPluginEnabled(plugin);
721 }
722 }
723
724 protected void enablePluginState(Plugin plugin, PluginStateStore stateStore)
725 {
726 PluginManagerState currentState = stateStore.loadPluginState();
727 String key = plugin.getKey();
728 if (!plugin.isEnabledByDefault())
729 currentState.setState(key, Boolean.TRUE);
730 else
731 currentState.removeState(key);
732 stateStore.savePluginState(currentState);
733 }
734
735
736
737
738
739
740
741
742 protected void notifyPluginEnabled(Plugin plugin)
743 {
744 classLoader.notifyPluginOrModuleEnabled();
745 enablePluginModules(plugin);
746 pluginEventManager.broadcast(new PluginEnabledEvent(plugin));
747 }
748
749
750
751
752
753
754 private void enablePluginModules(Plugin plugin)
755 {
756 for (Iterator it = plugin.getModuleDescriptors().iterator(); it.hasNext();)
757 {
758 ModuleDescriptor descriptor = (ModuleDescriptor) it.next();
759
760 if (!(descriptor instanceof StateAware))
761 {
762 if (log.isDebugEnabled())
763 log.debug("ModuleDescriptor '" + descriptor.getName() + "' is not StateAware. No need to enable.");
764 continue;
765 }
766
767 if (!isPluginModuleEnabled(descriptor.getCompleteKey()))
768 {
769 if (log.isDebugEnabled())
770 log.debug("Plugin module is disabled, so not enabling ModuleDescriptor '" + descriptor.getName() + "'.");
771 continue;
772 }
773
774 try
775 {
776 if (log.isDebugEnabled())
777 log.debug("Enabling " + descriptor.getKey());
778 ((StateAware) descriptor).enabled();
779 }
780 catch (Throwable exception)
781 {
782 log.error("There was an error loading the descriptor '" + descriptor.getName() + "' of plugin '" + plugin.getKey() + "'. Disabling.", exception);
783 replacePluginWithUnloadablePlugin(plugin, descriptor, exception);
784 }
785 }
786 classLoader.notifyPluginOrModuleEnabled();
787 }
788
789 public void disablePlugin(String key)
790 {
791 if (key == null)
792 throw new IllegalArgumentException("You must specify a plugin key to disable.");
793
794 if (!plugins.containsKey(key))
795 {
796 if (log.isInfoEnabled())
797 log.info("No plugin was found for key '" + key + "'. Not disabling.");
798
799 return;
800 }
801
802 Plugin plugin = (Plugin) plugins.get(key);
803
804 notifyPluginDisabled(plugin);
805 disablePluginState(plugin, getStore());
806 }
807
808 protected void disablePluginState(Plugin plugin, PluginStateStore stateStore)
809 {
810 String key = plugin.getKey();
811 PluginManagerState currentState = stateStore.loadPluginState();
812 if (plugin.isEnabledByDefault())
813 currentState.setState(key, Boolean.FALSE);
814 else
815 currentState.removeState(key);
816 stateStore.savePluginState(currentState);
817 }
818
819 protected List<String> getEnabledStateAwareModuleKeys(Plugin plugin)
820 {
821 List<String> keys = new ArrayList<String>();
822 List<ModuleDescriptor> moduleDescriptors = new ArrayList<ModuleDescriptor>(plugin.getModuleDescriptors());
823 Collections.reverse(moduleDescriptors);
824 for (ModuleDescriptor md : moduleDescriptors)
825 {
826 if (md instanceof StateAware)
827 {
828 if (isPluginModuleEnabled(md.getCompleteKey()))
829 {
830 keys.add(md.getCompleteKey());
831 }
832 }
833 }
834 return keys;
835 }
836
837 protected void notifyPluginDisabled(Plugin plugin)
838 {
839 List<String> keysToDisable = getEnabledStateAwareModuleKeys(plugin);
840
841 for (String key : keysToDisable)
842 {
843 StateAware descriptor = (StateAware) getPluginModule(key);
844 descriptor.disabled();
845 }
846
847
848 plugin.setEnabled(false);
849 pluginEventManager.broadcast(new PluginDisabledEvent(plugin));
850 }
851
852 public void disablePluginModule(String completeKey)
853 {
854 if (completeKey == null)
855 throw new IllegalArgumentException("You must specify a plugin module key to disable.");
856
857 final ModuleDescriptor module = getPluginModule(completeKey);
858
859 if (module == null)
860 {
861 if (log.isInfoEnabled())
862 log.info("Returned module for key '" + completeKey + "' was null. Not disabling.");
863
864 return;
865 }
866 disablePluginModuleState(module, getStore());
867 notifyModuleDisabled(module);
868 }
869
870 protected void disablePluginModuleState(ModuleDescriptor module, PluginStateStore stateStore)
871 {
872 String completeKey = module.getCompleteKey();
873 PluginManagerState currentState = stateStore.loadPluginState();
874 if (module.isEnabledByDefault())
875 currentState.setState(completeKey, Boolean.FALSE);
876 else
877 currentState.removeState(completeKey);
878 stateStore.savePluginState(currentState);
879 }
880
881 protected void notifyModuleDisabled(ModuleDescriptor module)
882 {
883 if (module instanceof StateAware)
884 ((StateAware) module).disabled();
885 }
886
887 public void enablePluginModule(String completeKey)
888 {
889 if (completeKey == null)
890 throw new IllegalArgumentException("You must specify a plugin module key to disable.");
891
892 final ModuleDescriptor module = getPluginModule(completeKey);
893
894 if (module == null)
895 {
896 if (log.isInfoEnabled())
897 log.info("Returned module for key '" + completeKey + "' was null. Not enabling.");
898
899 return;
900 }
901
902 if (!module.satisfiesMinJavaVersion())
903 {
904 log.error("Minimum Java version of '" + module.getMinJavaVersion() + "' was not satisfied for module '" + completeKey + "'. Not enabling.");
905 return;
906 }
907 enablePluginModuleState(module, getStore());
908 notifyModuleEnabled(module);
909 }
910
911 protected void enablePluginModuleState(ModuleDescriptor module, PluginStateStore stateStore)
912 {
913 String completeKey = module.getCompleteKey();
914 PluginManagerState currentState = stateStore.loadPluginState();
915 if (!module.isEnabledByDefault())
916 currentState.setState(completeKey, Boolean.TRUE);
917 else
918 currentState.removeState(completeKey);
919 stateStore.savePluginState(currentState);
920 }
921
922 protected void notifyModuleEnabled(ModuleDescriptor module)
923 {
924 classLoader.notifyPluginOrModuleEnabled();
925 if (module instanceof StateAware)
926 ((StateAware) module).enabled();
927 }
928
929 public boolean isPluginModuleEnabled(String completeKey)
930 {
931
932 if (completeKey == null) {
933 return false;
934 }
935 ModuleCompleteKey key = new ModuleCompleteKey(completeKey);
936
937 final ModuleDescriptor pluginModule = getPluginModule(completeKey);
938 return isPluginEnabled(key.getPluginKey()) && pluginModule != null && getState().isEnabled(pluginModule);
939 }
940
941 public boolean isPluginEnabled(String key)
942 {
943 return plugins.containsKey(key) && getState().isEnabled((Plugin) plugins.get(key));
944 }
945
946 public InputStream getDynamicResourceAsStream(String name)
947 {
948 return getClassLoader().getResourceAsStream(name);
949 }
950
951 public Class getDynamicPluginClass(String className) throws ClassNotFoundException
952 {
953 return getClassLoader().loadClass(className);
954 }
955
956 public ClassLoader getClassLoader()
957 {
958 return classLoader;
959 }
960
961 public InputStream getPluginResourceAsStream(String pluginKey, String resourcePath)
962 {
963 Plugin plugin = getEnabledPlugin(pluginKey);
964 if (plugin == null)
965 {
966 log.error("Attempted to retreive resource " + resourcePath + " for non-existent or inactive plugin " + pluginKey);
967 return null;
968 }
969
970 return plugin.getResourceAsStream(resourcePath);
971 }
972
973
974
975
976
977
978
979
980
981 private UnloadablePlugin replacePluginWithUnloadablePlugin(Plugin plugin, ModuleDescriptor descriptor, Throwable throwable)
982 {
983 UnloadableModuleDescriptor unloadableDescriptor =
984 UnloadableModuleDescriptorFactory.createUnloadableModuleDescriptor(plugin, descriptor, throwable);
985 UnloadablePlugin unloadablePlugin = UnloadablePluginFactory.createUnloadablePlugin(plugin, unloadableDescriptor);
986
987 unloadablePlugin.setUninstallable(plugin.isUninstallable());
988 unloadablePlugin.setDeletable(plugin.isDeleteable());
989 plugins.put(plugin.getKey(), unloadablePlugin);
990
991
992 disablePluginState(plugin, getStore());
993 return unloadablePlugin;
994 }
995
996 public boolean isSystemPlugin(String key)
997 {
998 Plugin plugin = getPlugin(key);
999 return plugin != null && plugin.isSystemPlugin();
1000 }
1001
1002
1003
1004
1005 public void setDescriptorParserFactory(DescriptorParserFactory descriptorParserFactory)
1006 {
1007 }
1008
1009 private static class PluginEnabledCondition implements WaitUntil.WaitCondition
1010 {
1011 private final Plugin plugin;
1012
1013 public PluginEnabledCondition(Plugin plugin)
1014 {
1015 this.plugin = plugin;
1016 }
1017
1018 public boolean isFinished()
1019 {
1020 return plugin.isEnabled();
1021 }
1022
1023 public String getWaitMessage()
1024 {
1025 return "Waiting until plugin " + plugin + " is enabled";
1026 }
1027 }
1028 }