Skip to content

Commit

Permalink
Merge branch 'dev4' of https://github.com/Col-E/Recaf into dev4
Browse files Browse the repository at this point in the history
  • Loading branch information
Col-E committed Feb 29, 2024
2 parents f635185 + 0429889 commit 23f335b
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@
import jakarta.inject.Inject;
import org.slf4j.Logger;
import software.coley.recaf.analytics.logging.Logging;
import software.coley.recaf.cdi.EagerInitialization;
import software.coley.recaf.plugin.*;
import software.coley.recaf.services.file.RecafDirectoriesConfig;
import software.coley.recaf.util.TestEnvironment;
import software.coley.recaf.util.io.ByteSource;
import software.coley.recaf.util.io.ByteSources;

Expand All @@ -24,6 +26,7 @@
* @author xDark
*/
@ApplicationScoped
@EagerInitialization
public class BasicPluginManager implements PluginManager {
private static final Logger logger = Logging.get(BasicPluginManager.class);
private final List<PluginLoader> loaders = new ArrayList<>();
Expand All @@ -45,7 +48,11 @@ public BasicPluginManager(PluginManagerConfig config, CdiClassAllocator classAll
@PostConstruct
@SuppressWarnings("unused")
private void setup(RecafDirectoriesConfig directoriesConfig) {
if (config.isAllowLocalScan())
// Do not load plugins in a test environment
if (TestEnvironment.isTestEnv())
return;

if (config.doScanOnStartup())
scanPlugins(directoriesConfig.getPluginDirectory());
}

Expand Down Expand Up @@ -135,20 +142,36 @@ public void removeLoader(@Nonnull PluginLoader loader) {
loaders.remove(loader);
}

@Override
public boolean isPluginLoaded(@Nonnull String name) {
return nameMap.get(name) != null;
}

@Nonnull
@Override
public <T extends Plugin> PluginContainer<T> loadPlugin(@Nonnull PluginContainer<T> container) throws PluginLoadException {
String name = container.getInformation().getName();

// Throw if a plugin with the same name is already loaded.
PluginLoader loader = container.getLoader();
if (nameMap.putIfAbsent(name.toLowerCase(Locale.ROOT), container) != null) {
// Plugin already exists, we do not allow
// multiple plugins with the same name.
// Plugin already exists, we do not allow multiple plugins with the same name.
// The passed in plugin container will be disabled since it shouldn't be used.
try {
container.getLoader().disablePlugin(container);
logger.warn("Attempted to load duplicate instance of plugin '{}'", name);
loader.disablePlugin(container);
} catch (Exception ignored) {
}
throw new PluginLoadException("Duplicate plugin: " + name);
}

// Update the instance registry.
instanceMap.put(container.getPlugin(), container);

// If configured, we'll want to load the plugin immediately.
if (shouldEnablePluginOnLoad(container))
loader.enablePlugin(container);

return container;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,25 +121,35 @@ default <T> Collection<T> getPluginsOfType(@Nonnull Class<T> type) {
*/
@Nonnull
default <T extends Plugin> PluginContainer<T> loadPlugin(@Nonnull ByteSource source) throws PluginLoadException {
ClassAllocator allocator = getAllocator();
for (PluginLoader loader : getLoaders()) {
try {
// Skip unsupported sources
if (!loader.isSupported(source))
continue;

// Load and record plugin container
PluginContainer<T> container = loader.load(getAllocator(), source);
PluginContainer<T> loadedContainer = loadPlugin(container);
if (shouldEnablePluginOnLoad(loadedContainer))
loader.enablePlugin(loadedContainer);
return loadedContainer;
// Load the plugin container from the source with the current allocator.
PluginContainer<T> container = loader.load(allocator, source);

// Register the plugin with the manager.
return loadPlugin(container);
} catch (IOException | UnsupportedSourceException ex) {
throw new PluginLoadException("Could not load plugin due to an error", ex);
}
}
throw new PluginLoadException("Plugin manager was unable to locate suitable loader for the source.");
}

/**
* Checks if a plugin is loaded.
*
* @param name
* Name of plugin to check for.
*
* @return {@code true} if the plugin has been registered/loaded by this manager.
*/
boolean isPluginLoaded(@Nonnull String name);

/**
* Loads and registers a plugin.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package software.coley.recaf.services.plugin;

import jakarta.annotation.Nonnull;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import software.coley.observables.ObservableBoolean;
import software.coley.recaf.config.BasicConfigContainer;
import software.coley.recaf.config.BasicConfigValue;
import software.coley.recaf.config.ConfigGroups;
import software.coley.recaf.services.ServiceConfig;

Expand All @@ -13,27 +16,19 @@
*/
@ApplicationScoped
public class PluginManagerConfig extends BasicConfigContainer implements ServiceConfig {
private boolean allowLocalScan = true;
private final ObservableBoolean scanOnStartup = new ObservableBoolean(true);

@Inject
public PluginManagerConfig() {
super(ConfigGroups.SERVICE_PLUGIN, PluginManager.SERVICE_ID + CONFIG_SUFFIX);
addValue(new BasicConfigValue<>("scan-on-start", boolean.class, scanOnStartup));
}

/**
* @return {@code true} when local plugins should be scanned when the plugin manager implementation initializes.
* {@code false} to disable local automatic plugin loading.
*/
public boolean isAllowLocalScan() {
return allowLocalScan;
}

/**
* @param allowLocalScan
* {@code true} when local plugins should be scanned when the plugin manager implementation initializes.
* {@code false} to disable local automatic plugin loading.
*/
public void setAllowLocalScan(boolean allowLocalScan) {
this.allowLocalScan = allowLocalScan;
public boolean doScanOnStartup() {
return scanOnStartup.getValue();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import software.coley.recaf.plugin.*;
import software.coley.recaf.test.TestBase;
import software.coley.recaf.util.ZipCreationUtils;
import software.coley.recaf.util.io.ByteSource;
import software.coley.recaf.util.io.ByteSources;

import java.io.IOException;
Expand Down Expand Up @@ -70,7 +71,8 @@ public String description() {

try {
// Load the plugin
PluginContainer<Plugin> container = pluginManager.loadPlugin(ByteSources.wrap(zip));
ByteSource pluginSource = ByteSources.wrap(zip);
PluginContainer<Plugin> container = pluginManager.loadPlugin(pluginSource);

// Assert the information stuck
PluginInfo information = container.getInformation();
Expand All @@ -83,6 +85,13 @@ public String description() {
assertEquals(1, pluginManager.getPlugins().size());
assertSame(container, pluginManager.getPlugin(name));

// Assert that loading the same plugin twice throws an exception, and does
// not actually register a 2nd instance of the plugin.
assertThrows(PluginLoadException.class, () -> pluginManager.loadPlugin(pluginSource),
"Duplicate plugin loading should fail");
assertEquals(1, pluginManager.getPlugins().size());
assertSame(container, pluginManager.getPlugin(name));

// Now unload it
pluginManager.unloadPlugin(container);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,6 @@ public static void setupWorkspaceManager() {
// We'll use this a lot so may as well grab it
workspaceManager = recaf.get(WorkspaceManager.class);
workspaceManager.setCurrent(null);

// Disable plugin scanning in tests
PluginManagerConfig pluginConfig = recaf.get(PluginManagerConfig.class);
pluginConfig.setAllowLocalScan(false);
}

/**
Expand Down

0 comments on commit 23f335b

Please sign in to comment.