mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 02:39:44 +02:00
Refactored plugin configuration methods
This commit is contained in:
parent
5719632656
commit
f5f71426d9
17 changed files with 274 additions and 176 deletions
|
@ -30,7 +30,7 @@ import ghidra.framework.model.Project;
|
|||
import ghidra.framework.options.Options;
|
||||
import ghidra.framework.options.ToolOptions;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.framework.plugintool.util.PluginClassManager;
|
||||
import ghidra.framework.plugintool.util.PluginsConfiguration;
|
||||
import ghidra.program.database.ProgramBuilder;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
|
||||
|
@ -413,8 +413,8 @@ public class AnalyzeAllOpenProgramsTaskTest extends AbstractGhidraHeadedIntegrat
|
|||
}
|
||||
|
||||
@Override
|
||||
public PluginClassManager getPluginClassManager() {
|
||||
return null;
|
||||
public PluginsConfiguration createPluginsConfigurations() {
|
||||
return null; // prevent slow class loading
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.framework.main;
|
||||
|
||||
import ghidra.framework.plugintool.Plugin;
|
||||
import ghidra.framework.plugintool.util.PluginsConfiguration;
|
||||
|
||||
/**
|
||||
* A configuration that only includes {@link ApplicationLevelPlugin} plugins.
|
||||
*/
|
||||
class ApplicationLevelPluginsConfiguration extends PluginsConfiguration {
|
||||
@Override
|
||||
protected boolean accepts(Class<? extends Plugin> c) {
|
||||
return ApplicationLevelPlugin.class.isAssignableFrom(c);
|
||||
}
|
||||
}
|
|
@ -131,7 +131,6 @@ public class FrontEndTool extends PluginTool implements OptionsChangeListener {
|
|||
|
||||
private WindowListener windowListener;
|
||||
private DockingAction configureToolAction;
|
||||
private PluginClassManager pluginClassManager;
|
||||
|
||||
/**
|
||||
* Construct a new Ghidra Project Window.
|
||||
|
@ -190,11 +189,8 @@ public class FrontEndTool extends PluginTool implements OptionsChangeListener {
|
|||
}
|
||||
|
||||
@Override
|
||||
public PluginClassManager getPluginClassManager() {
|
||||
if (pluginClassManager == null) {
|
||||
pluginClassManager = new PluginClassManager(ApplicationLevelPlugin.class, null);
|
||||
}
|
||||
return pluginClassManager;
|
||||
protected PluginsConfiguration createPluginsConfigurations() {
|
||||
return new ApplicationLevelPluginsConfiguration();
|
||||
}
|
||||
|
||||
public void selectFiles(Set<DomainFile> files) {
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -17,9 +16,9 @@
|
|||
package ghidra.framework.main;
|
||||
|
||||
/**
|
||||
* Marker interface for plugins that only get constructed programatically for specific purposes.
|
||||
* Marker interface for plugins that only get constructed programmatically for specific purposes.
|
||||
* Plugins that implement this interface should never be added via the config GUIs.
|
||||
*/
|
||||
public interface ProgramaticUseOnly {
|
||||
|
||||
// marker interface
|
||||
}
|
||||
|
|
|
@ -20,13 +20,13 @@ import java.util.List;
|
|||
import ghidra.framework.plugintool.util.*;
|
||||
|
||||
/**
|
||||
* The default plugin package provider that uses the {@link PluginClassManager} to supply packages
|
||||
* The default plugin package provider that uses the {@link PluginsConfiguration} to supply packages
|
||||
*/
|
||||
public class DeafultPluginPackagingProvider implements PluginPackagingProvider {
|
||||
|
||||
private PluginClassManager pluginClassManager;
|
||||
private PluginsConfiguration pluginClassManager;
|
||||
|
||||
DeafultPluginPackagingProvider(PluginClassManager pluginClassManager) {
|
||||
DeafultPluginPackagingProvider(PluginsConfiguration pluginClassManager) {
|
||||
this.pluginClassManager = pluginClassManager;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ package ghidra.framework.plugintool;
|
|||
|
||||
import ghidra.framework.main.AppInfo;
|
||||
import ghidra.framework.model.Project;
|
||||
import ghidra.framework.plugintool.util.PluginClassManager;
|
||||
import ghidra.framework.plugintool.util.PluginsConfiguration;
|
||||
|
||||
/**
|
||||
* PluginTool that is used by the Merge process to resolve conflicts
|
||||
|
@ -44,7 +44,7 @@ public class ModalPluginTool extends PluginTool {
|
|||
}
|
||||
|
||||
@Override
|
||||
public PluginClassManager getPluginClassManager() {
|
||||
return null;
|
||||
public PluginsConfiguration createPluginsConfigurations() {
|
||||
return null; // no need to load plugins
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ public class PluginConfigurationModel {
|
|||
|
||||
public PluginConfigurationModel(PluginTool tool) {
|
||||
this(new DefaultPluginInstaller(tool),
|
||||
new DeafultPluginPackagingProvider(tool.getPluginClassManager()));
|
||||
new DeafultPluginPackagingProvider(tool.getPluginsConfiguration()));
|
||||
}
|
||||
|
||||
public PluginConfigurationModel(PluginInstaller pluginInstaller,
|
||||
|
|
|
@ -23,6 +23,7 @@ import org.apache.logging.log4j.LogManager;
|
|||
import org.apache.logging.log4j.Logger;
|
||||
import org.jdom.Element;
|
||||
|
||||
import ghidra.framework.main.UtilityPluginPackage;
|
||||
import ghidra.framework.model.DomainFile;
|
||||
import ghidra.framework.model.DomainObject;
|
||||
import ghidra.framework.options.SaveState;
|
||||
|
@ -33,15 +34,40 @@ import ghidra.util.classfinder.ClassSearcher;
|
|||
import ghidra.util.exception.MultipleCauses;
|
||||
|
||||
class PluginManager {
|
||||
static final Logger log = LogManager.getLogger(PluginManager.class);
|
||||
private static final Logger log = LogManager.getLogger(PluginManager.class);
|
||||
|
||||
private PluginsConfiguration pluginsConfiguration;
|
||||
private List<Plugin> pluginList = new ArrayList<>();
|
||||
private PluginTool tool;
|
||||
private ServiceManager serviceMgr;
|
||||
|
||||
PluginManager(PluginTool tool, ServiceManager serviceMgr) {
|
||||
PluginManager(PluginTool tool, ServiceManager serviceMgr,
|
||||
PluginsConfiguration pluginsConfiguration) {
|
||||
this.tool = tool;
|
||||
this.serviceMgr = serviceMgr;
|
||||
this.pluginsConfiguration = pluginsConfiguration;
|
||||
}
|
||||
|
||||
void installUtilityPlugins() throws PluginException {
|
||||
|
||||
PluginPackage utilityPackage = PluginPackage.getPluginPackage(UtilityPluginPackage.NAME);
|
||||
List<PluginDescription> descriptions =
|
||||
pluginsConfiguration.getPluginDescriptions(utilityPackage);
|
||||
if (descriptions == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Set<String> classNames = new HashSet<>();
|
||||
for (PluginDescription description : descriptions) {
|
||||
String pluginClass = description.getPluginClass().getName();
|
||||
classNames.add(pluginClass);
|
||||
}
|
||||
|
||||
addPlugins(classNames);
|
||||
}
|
||||
|
||||
PluginsConfiguration getPluginsConfiguration() {
|
||||
return pluginsConfiguration;
|
||||
}
|
||||
|
||||
boolean acceptData(DomainFile[] data) {
|
||||
|
@ -72,7 +98,7 @@ class PluginManager {
|
|||
return false;
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
void dispose() {
|
||||
for (Iterator<Plugin> it = pluginList.iterator(); it.hasNext();) {
|
||||
Plugin plugin = it.next();
|
||||
plugin.cleanup();
|
||||
|
@ -255,15 +281,14 @@ class PluginManager {
|
|||
}
|
||||
|
||||
void saveToXml(Element root, boolean includeConfigState) {
|
||||
PluginClassManager pluginClassManager = tool.getPluginClassManager();
|
||||
pluginClassManager.addXmlElementsForPlugins(root, pluginList);
|
||||
|
||||
pluginsConfiguration.savePluginsToXml(root, pluginList);
|
||||
|
||||
if (!includeConfigState) {
|
||||
return;
|
||||
}
|
||||
|
||||
SaveState saveState = new SaveState("PLUGIN_STATE");
|
||||
|
||||
Iterator<Plugin> it = pluginList.iterator();
|
||||
while (it.hasNext()) {
|
||||
Plugin p = it.next();
|
||||
|
@ -279,8 +304,8 @@ class PluginManager {
|
|||
|
||||
void restorePluginsFromXml(Element root) throws PluginException {
|
||||
boolean isOld = isOldToolConfig(root);
|
||||
Collection<String> classNames =
|
||||
isOld ? getPluginClassNamesFromOldXml(root) : getPluginClassNamesToLoad(root);
|
||||
Collection<String> classNames = isOld ? getPluginClassNamesFromOldXml(root)
|
||||
: pluginsConfiguration.getPluginClassNames(root);
|
||||
Map<String, SaveState> map = isOld ? getPluginSavedStates(root, "PLUGIN")
|
||||
: getPluginSavedStates(root, "PLUGIN_STATE");
|
||||
|
||||
|
@ -324,19 +349,14 @@ class PluginManager {
|
|||
String className = elem.getAttributeValue("CLASS");
|
||||
classNames.add(className);
|
||||
}
|
||||
PluginClassManager pluginClassManager = tool.getPluginClassManager();
|
||||
return pluginClassManager.fillInPackageClasses(classNames);
|
||||
|
||||
return pluginsConfiguration.getPluginNamesByCurrentPackage(classNames);
|
||||
}
|
||||
|
||||
private boolean isOldToolConfig(Element root) {
|
||||
return root.getChild("PLUGIN") != null;
|
||||
}
|
||||
|
||||
private Set<String> getPluginClassNamesToLoad(Element root) {
|
||||
PluginClassManager pluginClassManager = tool.getPluginClassManager();
|
||||
return pluginClassManager.getPluginClasses(root);
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore the data state from the given XML element.
|
||||
* @param root XML element containing plugins' data state
|
||||
|
@ -465,8 +485,9 @@ class PluginManager {
|
|||
// TODO: this following loop is searching for any non-loaded Plugin that implements
|
||||
// the required service class interface.
|
||||
// This doesn't seem exactly right as a Service implementation shouldn't
|
||||
// be automagically pulled in and instantiated UNLESS it was specified as the "defaultProvider",
|
||||
// which we've already checked for in the previous PluginUtils.getDefaultProviderForServiceClass().
|
||||
// be automagically pulled in and instantiated UNLESS it was specified as the
|
||||
// "defaultProvider", which we've already checked for in the previous
|
||||
// PluginUtils.getDefaultProviderForServiceClass().
|
||||
// TODO: this also should be filtered by the PluginClassManager so we don't
|
||||
// pull in classes that have been excluded.
|
||||
for (Class<? extends Plugin> pc : ClassSearcher.getClasses(Plugin.class)) {
|
||||
|
|
|
@ -45,7 +45,8 @@ import ghidra.framework.OperatingSystem;
|
|||
import ghidra.framework.Platform;
|
||||
import ghidra.framework.cmd.BackgroundCommand;
|
||||
import ghidra.framework.cmd.Command;
|
||||
import ghidra.framework.main.*;
|
||||
import ghidra.framework.main.AppInfo;
|
||||
import ghidra.framework.main.UserAgreementDialog;
|
||||
import ghidra.framework.model.*;
|
||||
import ghidra.framework.options.*;
|
||||
import ghidra.framework.plugintool.dialog.ExtensionTableProvider;
|
||||
|
@ -175,7 +176,7 @@ public abstract class PluginTool extends AbstractDockingTool {
|
|||
eventMgr = new EventManager(this);
|
||||
serviceMgr = new ServiceManager();
|
||||
installServices();
|
||||
pluginMgr = new PluginManager(this, serviceMgr);
|
||||
pluginMgr = new PluginManager(this, serviceMgr, createPluginsConfigurations());
|
||||
dialogMgr = new DialogManager(this);
|
||||
initActions();
|
||||
initOptions();
|
||||
|
@ -192,7 +193,13 @@ public abstract class PluginTool extends AbstractDockingTool {
|
|||
// non-public constructor for stub subclasses
|
||||
}
|
||||
|
||||
public abstract PluginClassManager getPluginClassManager();
|
||||
protected PluginsConfiguration createPluginsConfigurations() {
|
||||
return new DefaultPluginsConfiguration();
|
||||
}
|
||||
|
||||
protected PluginsConfiguration getPluginsConfiguration() {
|
||||
return pluginMgr.getPluginsConfiguration();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method exists here, as opposed to inline in the constructor, so that subclasses can
|
||||
|
@ -233,21 +240,15 @@ public abstract class PluginTool extends AbstractDockingTool {
|
|||
*/
|
||||
protected void installUtilityPlugins() {
|
||||
|
||||
PluginClassManager classManager = getPluginClassManager();
|
||||
PluginPackage utilityPackage = PluginPackage.getPluginPackage(UtilityPluginPackage.NAME);
|
||||
List<PluginDescription> descriptions = classManager.getPluginDescriptions(utilityPackage);
|
||||
|
||||
Set<String> classNames = new HashSet<>();
|
||||
if (descriptions == null) {
|
||||
return;
|
||||
}
|
||||
for (PluginDescription description : descriptions) {
|
||||
String pluginClass = description.getPluginClass().getName();
|
||||
classNames.add(pluginClass);
|
||||
}
|
||||
|
||||
try {
|
||||
addPlugins(classNames);
|
||||
checkedRunSwingNow(() -> {
|
||||
try {
|
||||
pluginMgr.installUtilityPlugins();
|
||||
}
|
||||
finally {
|
||||
setConfigChanged(true);
|
||||
}
|
||||
}, PluginException.class);
|
||||
}
|
||||
catch (PluginException e) {
|
||||
Msg.showError(this, null, "Error Adding Utility Plugins",
|
||||
|
|
|
@ -23,12 +23,12 @@ import docking.action.*;
|
|||
import docking.tool.ToolConstants;
|
||||
import ghidra.framework.OperatingSystem;
|
||||
import ghidra.framework.Platform;
|
||||
import ghidra.framework.plugintool.util.PluginClassManager;
|
||||
import ghidra.framework.plugintool.util.PluginsConfiguration;
|
||||
import ghidra.util.HelpLocation;
|
||||
|
||||
public class StandAlonePluginTool extends PluginTool {
|
||||
|
||||
private PluginClassManager pluginClassManager;
|
||||
private PluginsConfiguration pluginClassManager;
|
||||
private DockingAction configureToolAction;
|
||||
private final GenericStandAloneApplication app;
|
||||
private final String name;
|
||||
|
@ -39,14 +39,6 @@ public class StandAlonePluginTool extends PluginTool {
|
|||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PluginClassManager getPluginClassManager() {
|
||||
if (pluginClassManager == null) {
|
||||
pluginClassManager = new PluginClassManager(Plugin.class, null);
|
||||
}
|
||||
return pluginClassManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addExitAction() {
|
||||
DockingAction exitAction = new DockingAction("Exit", ToolConstants.TOOL_OWNER) {
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.framework.plugintool.util;
|
||||
|
||||
import ghidra.framework.plugintool.Plugin;
|
||||
|
||||
/**
|
||||
* A configuration that includes all plugins on the classpath.
|
||||
*/
|
||||
public class DefaultPluginsConfiguration extends PluginsConfiguration {
|
||||
@Override
|
||||
protected boolean accepts(Class<? extends Plugin> pluginClass) {
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -33,48 +33,6 @@ import ghidra.util.exception.AssertException;
|
|||
*/
|
||||
public class PluginUtils {
|
||||
|
||||
/**
|
||||
* Finds all {@link PluginDescription} objects that match a given set of plugin classes. This
|
||||
* effectively tells the caller which of the given plugins have been loaded by the class loader.
|
||||
* <p>
|
||||
* eg: If the list of plugin classes contains the class "FooPlugin.class", this method
|
||||
* will search the {@link PluginConfigurationModel} for any plugin with the name "FooPlugin" and
|
||||
* return its {@link PluginDescription}.
|
||||
* <p>
|
||||
* Note that this method does not take path/package information into account when finding
|
||||
* plugins; in the example above, if there is more than one plugin with the name "FooPlugin",
|
||||
* only one will be found (the one found is not guaranteed to be the first).
|
||||
*
|
||||
* @param tool the current tool
|
||||
* @param plugins the list of plugin classes to search for
|
||||
* @return list of plugin descriptions
|
||||
*/
|
||||
public static List<PluginDescription> getPluginDescriptions(PluginTool tool,
|
||||
List<Class<?>> plugins) {
|
||||
|
||||
// First define the list of plugin descriptions to return
|
||||
List<PluginDescription> retPlugins = new ArrayList<>();
|
||||
|
||||
// Get all plugins that have been loaded
|
||||
PluginClassManager pluginClassManager = tool.getPluginClassManager();
|
||||
List<PluginDescription> allPluginDescriptions =
|
||||
pluginClassManager.getManagedPluginDescriptions();
|
||||
|
||||
// see if an entry exists in the list of all loaded plugins
|
||||
for (Class<?> plugin : plugins) {
|
||||
String pluginName = plugin.getSimpleName();
|
||||
|
||||
Optional<PluginDescription> desc = allPluginDescriptions.stream()
|
||||
.filter(d -> (pluginName.equals(d.getName())))
|
||||
.findAny();
|
||||
if (desc.isPresent()) {
|
||||
retPlugins.add(desc.get());
|
||||
}
|
||||
}
|
||||
|
||||
return retPlugins;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds all plugin classes loaded from a given set of extensions.
|
||||
*
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
*/
|
||||
package ghidra.framework.plugintool.util;
|
||||
|
||||
import static java.util.function.Predicate.*;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
|
@ -25,30 +27,33 @@ import ghidra.framework.plugintool.Plugin;
|
|||
import ghidra.util.Msg;
|
||||
import ghidra.util.classfinder.ClassSearcher;
|
||||
|
||||
public class PluginClassManager {
|
||||
/**
|
||||
* This class maintains a collection of all plugin classes that are acceptable for a given tool
|
||||
* type. Simple applications with only one plugin type can use the
|
||||
* {@link DefaultPluginsConfiguration}. More complex tools can support a subset of the available
|
||||
* plugins. Those tools should create custom subclasses for each tool type, that filter out plugins
|
||||
* that are not appropriate for that tool type.
|
||||
*/
|
||||
public abstract class PluginsConfiguration {
|
||||
|
||||
private Map<PluginPackage, List<PluginDescription>> packageMap = new HashMap<>();
|
||||
private Map<PluginPackage, List<PluginDescription>> descriptionsByPackage = new HashMap<>();
|
||||
private Map<String, PluginDescription> descriptionsByName = new HashMap<>();
|
||||
|
||||
private Map<String, PluginDescription> pluginClassMap = new HashMap<>();
|
||||
|
||||
public PluginClassManager(Class<?> filterClass, Class<?> exclusionClass) {
|
||||
populatePluginDescriptionMaps(filterClass, exclusionClass);
|
||||
protected PluginsConfiguration() {
|
||||
populatePluginDescriptionMaps();
|
||||
}
|
||||
|
||||
public PluginDescription getPluginDescription(String className) {
|
||||
return pluginClassMap.get(className);
|
||||
protected abstract boolean accepts(Class<? extends Plugin> pluginClass);
|
||||
|
||||
private Predicate<Class<? extends Plugin>> createFilter() {
|
||||
Predicate<Class<? extends Plugin>> ignore = ProgramaticUseOnly.class::isAssignableFrom;
|
||||
return not(ignore).and(c -> accepts(c));
|
||||
}
|
||||
|
||||
private void populatePluginDescriptionMaps(Class<?> localFilterClass,
|
||||
Class<?> localExclusionClass) {
|
||||
private void populatePluginDescriptionMaps() {
|
||||
|
||||
Predicate<Class<? extends Plugin>> myClassFilter =
|
||||
c -> (localFilterClass == null || localFilterClass.isAssignableFrom(c)) &&
|
||||
(localExclusionClass == null || !localExclusionClass.isAssignableFrom(c)) &&
|
||||
!ProgramaticUseOnly.class.isAssignableFrom(c);
|
||||
|
||||
List<Class<? extends Plugin>> classes =
|
||||
ClassSearcher.getClasses(Plugin.class, myClassFilter);
|
||||
Predicate<Class<? extends Plugin>> classFilter = createFilter();
|
||||
List<Class<? extends Plugin>> classes = ClassSearcher.getClasses(Plugin.class, classFilter);
|
||||
|
||||
for (Class<? extends Plugin> pluginClass : classes) {
|
||||
if (!PluginUtils.isValidPluginClass(pluginClass)) {
|
||||
|
@ -57,16 +62,21 @@ public class PluginClassManager {
|
|||
}
|
||||
|
||||
PluginDescription pd = PluginDescription.getPluginDescription(pluginClass);
|
||||
pluginClassMap.put(pluginClass.getName(), pd);
|
||||
descriptionsByName.put(pluginClass.getName(), pd);
|
||||
|
||||
PluginPackage pluginPackage = pd.getPluginPackage();
|
||||
List<PluginDescription> list =
|
||||
packageMap.computeIfAbsent(pluginPackage, (k) -> new ArrayList<>());
|
||||
descriptionsByPackage.computeIfAbsent(pluginPackage, (k) -> new ArrayList<>());
|
||||
list.add(pd);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void addXmlElementsForPlugins(Element root, List<Plugin> plugins) {
|
||||
public PluginDescription getPluginDescription(String className) {
|
||||
return descriptionsByName.get(className);
|
||||
}
|
||||
|
||||
public void savePluginsToXml(Element root, List<Plugin> plugins) {
|
||||
Map<PluginPackage, List<Plugin>> pluginPackageMap = buildPluginPackageMap(plugins);
|
||||
for (PluginPackage pluginPackage : pluginPackageMap.keySet()) {
|
||||
root.addContent(getPackageElement(pluginPackage, pluginPackageMap.get(pluginPackage)));
|
||||
|
@ -76,7 +86,7 @@ public class PluginClassManager {
|
|||
private Element getPackageElement(PluginPackage pluginPackage, List<Plugin> pluginList) {
|
||||
Element packageElement = new Element("PACKAGE");
|
||||
packageElement.setAttribute("NAME", pluginPackage.getName());
|
||||
List<PluginDescription> pluginDescriptions = packageMap.get(pluginPackage);
|
||||
List<PluginDescription> pluginDescriptions = descriptionsByPackage.get(pluginPackage);
|
||||
|
||||
Set<String> includedPluginClasses = new HashSet<>();
|
||||
for (Plugin plugin : pluginList) {
|
||||
|
@ -120,7 +130,8 @@ public class PluginClassManager {
|
|||
private Map<PluginPackage, List<Plugin>> buildPluginPackageMap(List<Plugin> plugins) {
|
||||
Map<PluginPackage, List<Plugin>> pluginPackageMap = new HashMap<>();
|
||||
for (Plugin plugin : plugins) {
|
||||
PluginDescription pluginDescription = pluginClassMap.get(plugin.getClass().getName());
|
||||
PluginDescription pluginDescription =
|
||||
descriptionsByName.get(plugin.getClass().getName());
|
||||
if (pluginDescription == null) {
|
||||
continue;
|
||||
}
|
||||
|
@ -138,41 +149,42 @@ public class PluginClassManager {
|
|||
}
|
||||
|
||||
/**
|
||||
* Used to convert an old style tool XML file by adding in classes in the same packages as
|
||||
* those that were named specifically in the XML file
|
||||
* Used to convert an old style tool XML file by mapping the given class names to plugin
|
||||
* packages and then adding <b>all</b> plugins in that package. This has the effect of pulling
|
||||
* in more plugin classes than were originally specified in the tool xml.
|
||||
*
|
||||
* @param classNames the list of classNames from from the old XML file
|
||||
* @return the adjusted class names
|
||||
* @return the adjusted set of plugin class names
|
||||
*/
|
||||
public Set<String> fillInPackageClasses(List<String> classNames) {
|
||||
public Set<String> getPluginNamesByCurrentPackage(List<String> classNames) {
|
||||
Set<PluginPackage> packages = new HashSet<>();
|
||||
Set<String> adjustedClassNames = new HashSet<>();
|
||||
|
||||
for (String className : classNames) {
|
||||
PluginDescription pluginDescription = pluginClassMap.get(className);
|
||||
if (pluginDescription != null) {
|
||||
if (pluginDescription.getStatus() == PluginStatus.RELEASED) {
|
||||
packages.add(pluginDescription.getPluginPackage());
|
||||
PluginDescription pd = descriptionsByName.get(className);
|
||||
if (pd == null) {
|
||||
continue; // plugin no longer in tool
|
||||
}
|
||||
|
||||
if (pd.getStatus() == PluginStatus.RELEASED) {
|
||||
packages.add(pd.getPluginPackage());
|
||||
}
|
||||
else {
|
||||
adjustedClassNames.add(className);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (PluginPackage pluginPackage : packages) {
|
||||
List<PluginDescription> list = packageMap.get(pluginPackage);
|
||||
for (PluginDescription pluginDescription : list) {
|
||||
if (pluginDescription.getStatus() != PluginStatus.RELEASED) {
|
||||
continue;
|
||||
}
|
||||
String name = pluginDescription.getPluginClass().getName();
|
||||
adjustedClassNames.add(name);
|
||||
List<PluginDescription> packageDescriptions = descriptionsByPackage.get(pluginPackage);
|
||||
for (PluginDescription pd : packageDescriptions) {
|
||||
adjustedClassNames.add(pd.getPluginClass().getName());
|
||||
}
|
||||
}
|
||||
|
||||
return adjustedClassNames;
|
||||
}
|
||||
|
||||
public Set<String> getPluginClasses(Element element) {
|
||||
public Set<String> getPluginClassNames(Element element) {
|
||||
|
||||
Set<String> classNames = new HashSet<>();
|
||||
List<?> children = element.getChildren("PACKAGE");
|
||||
|
@ -206,7 +218,8 @@ public class PluginClassManager {
|
|||
}
|
||||
|
||||
PluginPackage pluginPackage = PluginPackage.getPluginPackage(packageName);
|
||||
List<PluginDescription> pluginDescriptionList = packageMap.get(pluginPackage);
|
||||
List<PluginDescription> pluginDescriptionList =
|
||||
descriptionsByPackage.get(pluginPackage);
|
||||
if (pluginDescriptionList == null) {
|
||||
continue;
|
||||
}
|
||||
|
@ -236,13 +249,13 @@ public class PluginClassManager {
|
|||
}
|
||||
|
||||
public List<PluginPackage> getPluginPackages() {
|
||||
List<PluginPackage> list = new ArrayList<>(packageMap.keySet());
|
||||
List<PluginPackage> list = new ArrayList<>(descriptionsByPackage.keySet());
|
||||
Collections.sort(list);
|
||||
return list;
|
||||
}
|
||||
|
||||
public List<PluginDescription> getPluginDescriptions(PluginPackage pluginPackage) {
|
||||
List<PluginDescription> list = packageMap.get(pluginPackage);
|
||||
List<PluginDescription> list = descriptionsByPackage.get(pluginPackage);
|
||||
List<PluginDescription> stableList = new ArrayList<>();
|
||||
for (PluginDescription pluginDescription : list) {
|
||||
if (pluginDescription.getStatus() == PluginStatus.UNSTABLE ||
|
||||
|
@ -256,7 +269,7 @@ public class PluginClassManager {
|
|||
|
||||
public List<PluginDescription> getUnstablePluginDescriptions() {
|
||||
List<PluginDescription> unstablePlugins = new ArrayList<>();
|
||||
for (PluginDescription pluginDescription : pluginClassMap.values()) {
|
||||
for (PluginDescription pluginDescription : descriptionsByName.values()) {
|
||||
if (pluginDescription.getStatus() == PluginStatus.UNSTABLE) {
|
||||
unstablePlugins.add(pluginDescription);
|
||||
}
|
||||
|
@ -266,7 +279,7 @@ public class PluginClassManager {
|
|||
|
||||
public List<PluginDescription> getManagedPluginDescriptions() {
|
||||
ArrayList<PluginDescription> nonHiddenPlugins = new ArrayList<>();
|
||||
for (PluginDescription pluginDescription : pluginClassMap.values()) {
|
||||
for (PluginDescription pluginDescription : descriptionsByName.values()) {
|
||||
if (pluginDescription.getStatus() == PluginStatus.HIDDEN) {
|
||||
continue;
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.framework.project.tool;
|
||||
|
||||
import ghidra.framework.main.ApplicationLevelOnlyPlugin;
|
||||
import ghidra.framework.plugintool.Plugin;
|
||||
import ghidra.framework.plugintool.util.PluginsConfiguration;
|
||||
|
||||
/**
|
||||
* A configuration that allows all general plugins and application plugins. Plugins that may only
|
||||
* exist at the application level are filtered out.
|
||||
*/
|
||||
class GhidraPluginsConfiguration extends PluginsConfiguration {
|
||||
|
||||
@Override
|
||||
protected boolean accepts(Class<? extends Plugin> c) {
|
||||
return !(ApplicationLevelOnlyPlugin.class.isAssignableFrom(c));
|
||||
}
|
||||
}
|
|
@ -28,11 +28,11 @@ import docking.action.MenuData;
|
|||
import docking.tool.ToolConstants;
|
||||
import docking.widgets.OptionDialog;
|
||||
import ghidra.app.util.FileOpenDropHandler;
|
||||
import ghidra.framework.main.ApplicationLevelOnlyPlugin;
|
||||
import ghidra.framework.model.Project;
|
||||
import ghidra.framework.model.ToolTemplate;
|
||||
import ghidra.framework.options.PreferenceState;
|
||||
import ghidra.framework.plugintool.*;
|
||||
import ghidra.framework.plugintool.PluginConfigurationModel;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.framework.plugintool.dialog.*;
|
||||
import ghidra.framework.plugintool.util.*;
|
||||
import ghidra.util.HelpLocation;
|
||||
|
@ -55,9 +55,6 @@ public class GhidraTool extends PluginTool {
|
|||
public static boolean autoSave = true;
|
||||
|
||||
private FileOpenDropHandler fileOpenDropHandler;
|
||||
|
||||
private PluginClassManager pluginClassManager;
|
||||
|
||||
private DockingAction configureToolAction;
|
||||
|
||||
/**
|
||||
|
@ -99,12 +96,8 @@ public class GhidraTool extends PluginTool {
|
|||
}
|
||||
|
||||
@Override
|
||||
public PluginClassManager getPluginClassManager() {
|
||||
if (pluginClassManager == null) {
|
||||
pluginClassManager =
|
||||
new PluginClassManager(Plugin.class, ApplicationLevelOnlyPlugin.class);
|
||||
}
|
||||
return pluginClassManager;
|
||||
protected PluginsConfiguration createPluginsConfigurations() {
|
||||
return new GhidraPluginsConfiguration();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -254,8 +247,7 @@ public class GhidraTool extends PluginTool {
|
|||
int option = OptionDialog.showYesNoDialog(getActiveWindow(), "New Plugins Found!",
|
||||
"New extension plugins detected. Would you like to configure them?");
|
||||
if (option == OptionDialog.YES_OPTION) {
|
||||
List<PluginDescription> pluginDescriptions =
|
||||
PluginUtils.getPluginDescriptions(this, newPlugins);
|
||||
List<PluginDescription> pluginDescriptions = getPluginDescriptions(this, newPlugins);
|
||||
PluginInstallerDialog pluginInstaller = new PluginInstallerDialog("New Plugins Found!",
|
||||
this, new PluginConfigurationModel(this), pluginDescriptions);
|
||||
showDialog(pluginInstaller);
|
||||
|
@ -265,6 +257,43 @@ public class GhidraTool extends PluginTool {
|
|||
addInstalledExtensions(newExtensions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds all {@link PluginDescription} objects that match a given set of plugin classes. This
|
||||
* effectively tells the caller which of the given plugins have been loaded by the class loader.
|
||||
* <p>
|
||||
* Note that this method does not take path/package information into account when finding
|
||||
* plugins; in the example above, if there is more than one plugin with the name "FooPlugin",
|
||||
* only one will be found (the one found is not guaranteed to be the first).
|
||||
*
|
||||
* @param tool the current tool
|
||||
* @param plugins the list of plugin classes to search for
|
||||
* @return list of plugin descriptions
|
||||
*/
|
||||
private List<PluginDescription> getPluginDescriptions(PluginTool tool, List<Class<?>> plugins) {
|
||||
|
||||
// First define the list of plugin descriptions to return
|
||||
List<PluginDescription> retPlugins = new ArrayList<>();
|
||||
|
||||
// Get all plugins that have been loaded
|
||||
PluginsConfiguration pluginClassManager = getPluginsConfiguration();
|
||||
List<PluginDescription> allPluginDescriptions =
|
||||
pluginClassManager.getManagedPluginDescriptions();
|
||||
|
||||
// see if an entry exists in the list of all loaded plugins
|
||||
for (Class<?> plugin : plugins) {
|
||||
String pluginName = plugin.getSimpleName();
|
||||
|
||||
Optional<PluginDescription> desc = allPluginDescriptions.stream()
|
||||
.filter(d -> (pluginName.equals(d.getName())))
|
||||
.findAny();
|
||||
if (desc.isPresent()) {
|
||||
retPlugins.add(desc.get());
|
||||
}
|
||||
}
|
||||
|
||||
return retPlugins;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes any extensions in the tool preferences that are no longer installed.
|
||||
*/
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
*/
|
||||
package ghidra.framework.plugintool;
|
||||
|
||||
import ghidra.framework.plugintool.util.PluginClassManager;
|
||||
import ghidra.framework.plugintool.util.PluginsConfiguration;
|
||||
|
||||
/**
|
||||
* A dummy version of {@link PluginTool} that tests can use when they need an instance of
|
||||
|
@ -29,7 +29,7 @@ public class DummyPluginTool extends PluginTool {
|
|||
}
|
||||
|
||||
@Override
|
||||
public PluginClassManager getPluginClassManager() {
|
||||
protected PluginsConfiguration createPluginsConfigurations() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -425,7 +425,7 @@ public class DummyTool extends PluginTool {
|
|||
}
|
||||
|
||||
@Override
|
||||
public PluginClassManager getPluginClassManager() {
|
||||
protected PluginsConfiguration createPluginsConfigurations() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue