PluginLoader { @SuppressWarnings("unchecked") public boolean unload(Plugin plugin) { if (!loadedPlugins.contains(plugin)) { return false; } knownPlugins.stream() .filter(p -> requires(p.getClass(), plugin.getClass())) .forEach(this::unload); log.info("Unloading plugin " + plugin.fullIdString()); components.getActiveWidgets().stream() .filter(w -> w.getSources().stream().anyMatch(s -> !(s instanceof DestroyedSource))) .filter(w -> { return w.getSources().stream().anyMatch(s -> plugin.getDataTypes().contains(s.getDataType())) || w.getSources().stream().anyMatch(s -> plugin.getSourceTypes().contains(s.getType())); }) .forEach(w -> { if (w instanceof SingleSourceWidget) { SingleSourceWidget singleSource = (SingleSourceWidget) w; singleSource.setSource(new DestroyedSource<>(singleSource.getSource())); } else { w.getSources().replaceAll(s -> { if (!(s instanceof DestroyedSource) && (plugin.getDataTypes().contains(s.getDataType()) || plugin.getSourceTypes().contains(s.getType()))) { return new DestroyedSource<>(s); } return s; }); } }); components.unregisterAll(plugin.getComponents()); sourceTypes.unregisterAll(plugin.getSourceTypes()); plugin.getTypeAdapters().forEach(Serializers::remove); dataTypes.unregisterAll(plugin.getDataTypes()); themes.unregisterAll(plugin.getThemes()); tabInfoRegistry.unregisterAll(plugin.getDefaultTabInfo()); converters.unregisterAll(plugin.getRecordingConverters()); propertyParsers.unregisterAll(plugin.getPropertyParsers()); plugin.onUnload(); plugin.setLoaded(false); loadedPlugins.remove(plugin); return true; } PluginLoader(DataTypes dataTypes,
                      SourceTypes sourceTypes,
                      Components components,
                      Themes themes,
                      TabInfoRegistry tabInfoRegistry,
                      Converters converters,
                      PropertyParsers propertyParsers); static PluginLoader getDefault(); void loadAllJarsFromDir(Path directory); void loadPluginJar(URI jarUri); boolean loadPluginClass(Class<? extends Plugin> clazz); boolean load(Plugin plugin); boolean canLoad(Plugin plugin); @SuppressWarnings("unchecked") boolean unload(Plugin plugin); ObservableList<Plugin> getKnownPlugins(); ObservableSet<Plugin> getLoadedPlugins(); ObservableList<ClassLoader> getClassLoaders();  }
@Test public void testUnload() { MockPlugin plugin = new MockPlugin(); assumeTrue(loader.load(plugin)); assertTrue(loader.unload(plugin), "The plugin was not unloaded"); assertFalse(plugin.isLoaded()); assertFalse(loader.getLoadedPlugins().contains(plugin)); assertTrue(loader.getKnownPlugins().contains(plugin)); assertFalse(dataTypes.isRegistered(MockPlugin.dataType)); assertFalse(sourceTypes.isRegistered(MockPlugin.sourceType)); assertFalse(components.isRegistered(MockPlugin.component)); assertFalse(themes.isRegistered(MockPlugin.theme)); }