diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/DebuggerModelServicePlugin.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/DebuggerModelServicePlugin.java index 7d94e449ce..14e760eafa 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/DebuggerModelServicePlugin.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/DebuggerModelServicePlugin.java @@ -45,7 +45,7 @@ import ghidra.dbg.*; import ghidra.dbg.target.*; import ghidra.dbg.util.PathUtils; import ghidra.framework.main.AppInfo; -import ghidra.framework.main.FrontEndOnly; +import ghidra.framework.main.ApplicationLevelOnlyPlugin; import ghidra.framework.options.SaveState; import ghidra.framework.plugintool.*; import ghidra.framework.plugintool.util.PluginStatus; @@ -71,7 +71,7 @@ import ghidra.util.datastruct.ListenerSet; servicesProvided = { DebuggerModelService.class, }) public class DebuggerModelServicePlugin extends Plugin - implements DebuggerModelServiceInternal, FrontEndOnly { + implements DebuggerModelServiceInternal, ApplicationLevelOnlyPlugin { private static final String PREFIX_FACTORY = "Factory_"; diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/workflow/DebuggerWorkflowServicePlugin.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/workflow/DebuggerWorkflowServicePlugin.java index a3bb413495..a662a7d37d 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/workflow/DebuggerWorkflowServicePlugin.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/workflow/DebuggerWorkflowServicePlugin.java @@ -31,7 +31,7 @@ import ghidra.app.plugin.core.debug.event.TraceOpenedPluginEvent; import ghidra.app.plugin.core.debug.gui.DebuggerResources; import ghidra.app.services.*; import ghidra.dbg.DebuggerObjectModel; -import ghidra.framework.main.FrontEndOnly; +import ghidra.framework.main.ApplicationLevelOnlyPlugin; import ghidra.framework.main.FrontEndTool; import ghidra.framework.options.*; import ghidra.framework.plugintool.*; @@ -55,7 +55,7 @@ import ghidra.util.datastruct.CollectionChangeListener; } // ) public class DebuggerWorkflowServicePlugin extends Plugin - implements DebuggerWorkflowService, FrontEndOnly, OptionsChangeListener { + implements DebuggerWorkflowService, ApplicationLevelOnlyPlugin, OptionsChangeListener { protected class ForBotsModelsChangeListener implements CollectionChangeListener { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/archive/ArchivePlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/archive/ArchivePlugin.java index bc2b5d8387..84d0faf741 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/archive/ArchivePlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/archive/ArchivePlugin.java @@ -49,7 +49,7 @@ import ghidra.util.task.*; description = "The archive plugin provides a menu action from the project window allowing the user to archive a project or restore an archived project. " ) //@formatter:on -public class ArchivePlugin extends Plugin implements FrontEndOnly, ProjectListener { +public class ArchivePlugin extends Plugin implements ApplicationLevelOnlyPlugin, ProjectListener { private static final String PROJECT_GROUP_C_2 = "CProject2"; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/eclipse/EclipseIntegrationOptionsPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/eclipse/EclipseIntegrationOptionsPlugin.java index c818294519..811d3545ae 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/eclipse/EclipseIntegrationOptionsPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/eclipse/EclipseIntegrationOptionsPlugin.java @@ -19,7 +19,7 @@ import java.io.File; import ghidra.app.CorePluginPackage; import ghidra.app.plugin.PluginCategoryNames; -import ghidra.framework.main.FrontEndOnly; +import ghidra.framework.main.ApplicationLevelOnlyPlugin; import ghidra.framework.options.OptionType; import ghidra.framework.options.ToolOptions; import ghidra.framework.plugintool.*; @@ -38,7 +38,7 @@ import ghidra.util.HelpLocation; description = "Options Eclipse Integration" ) //@formatter:on -public class EclipseIntegrationOptionsPlugin extends Plugin implements FrontEndOnly { +public class EclipseIntegrationOptionsPlugin extends Plugin implements ApplicationLevelOnlyPlugin { public static final String PLUGIN_OPTIONS_NAME = "Eclipse Integration"; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/exporter/ExporterPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/exporter/ExporterPlugin.java index c27a2a2635..f2391104da 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/exporter/ExporterPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/exporter/ExporterPlugin.java @@ -24,7 +24,7 @@ import ghidra.app.context.NavigatableActionContext; import ghidra.app.context.NavigatableContextAction; import ghidra.app.plugin.PluginCategoryNames; import ghidra.app.services.CodeViewerService; -import ghidra.framework.main.FrontEndable; +import ghidra.framework.main.ApplicationLevelPlugin; import ghidra.framework.main.datatable.ProjectDataContext; import ghidra.framework.main.datatable.FrontendProjectTreeAction; import ghidra.framework.model.DomainFile; @@ -44,7 +44,7 @@ import ghidra.util.HelpLocation; description = "This plugin exports a program or datatype archive to an external file." ) //@formatter:on -public class ExporterPlugin extends Plugin implements FrontEndable { +public class ExporterPlugin extends Plugin implements ApplicationLevelPlugin { public ExporterPlugin(PluginTool tool) { super(tool); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/help/AboutProgramPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/help/AboutProgramPlugin.java index 9201079e8b..0527cc18be 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/help/AboutProgramPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/help/AboutProgramPlugin.java @@ -28,7 +28,7 @@ import ghidra.app.plugin.PluginCategoryNames; import ghidra.app.util.GenericHelpTopics; import ghidra.app.util.HelpTopics; import ghidra.framework.main.FrontEndTool; -import ghidra.framework.main.FrontEndable; +import ghidra.framework.main.ApplicationLevelPlugin; import ghidra.framework.main.datatable.FrontendProjectTreeAction; import ghidra.framework.main.datatable.ProjectDataContext; import ghidra.framework.model.DomainFile; @@ -50,7 +50,7 @@ import ghidra.util.HelpLocation; description = "This plugin provides an action that displays information about the currently loaded program" ) //@formatter:on -public class AboutProgramPlugin extends Plugin implements FrontEndable { +public class AboutProgramPlugin extends Plugin implements ApplicationLevelPlugin { public final static String PLUGIN_NAME = "AboutProgramPlugin"; public final static String ACTION_NAME = "About Program"; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/help/ProcessorListPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/help/ProcessorListPlugin.java index ab70d561ac..39abac0831 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/help/ProcessorListPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/help/ProcessorListPlugin.java @@ -34,7 +34,7 @@ import docking.widgets.table.GTable; import ghidra.app.CorePluginPackage; import ghidra.app.plugin.PluginCategoryNames; import ghidra.app.util.HelpTopics; -import ghidra.framework.main.FrontEndable; +import ghidra.framework.main.ApplicationLevelPlugin; import ghidra.framework.plugintool.*; import ghidra.framework.plugintool.util.PluginStatus; import ghidra.program.model.lang.*; @@ -51,7 +51,7 @@ import ghidra.util.SystemUtilities; description = "This plugin provides a Help action that displays a list of installed processor modules" ) //@formatter:on -public class ProcessorListPlugin extends Plugin implements FrontEndable { +public class ProcessorListPlugin extends Plugin implements ApplicationLevelPlugin { private DockingAction processorListAction; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/misc/RecoverySnapshotMgrPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/misc/RecoverySnapshotMgrPlugin.java index b201209a1f..b3302be4ba 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/misc/RecoverySnapshotMgrPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/misc/RecoverySnapshotMgrPlugin.java @@ -24,7 +24,7 @@ import javax.swing.Timer; import ghidra.app.CorePluginPackage; import ghidra.app.plugin.PluginCategoryNames; -import ghidra.framework.main.FrontEndOnly; +import ghidra.framework.main.ApplicationLevelOnlyPlugin; import ghidra.framework.main.FrontEndTool; import ghidra.framework.model.*; import ghidra.framework.options.OptionsChangeListener; @@ -49,7 +49,7 @@ import ghidra.util.exception.AssertException; ) //@formatter:on public class RecoverySnapshotMgrPlugin extends Plugin - implements FrontEndOnly, OptionsChangeListener, ProjectListener { + implements ApplicationLevelOnlyPlugin, OptionsChangeListener, ProjectListener { private final static String OPTIONS_TITLE = "Recovery"; private final static String SNAPSHOT_PERIOD_OPTION = "Snapshot period (minutes, 0=disabled)"; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/processors/LanguageProviderPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/processors/LanguageProviderPlugin.java index f885114700..2dbf91aba7 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/processors/LanguageProviderPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/processors/LanguageProviderPlugin.java @@ -27,7 +27,7 @@ import docking.widgets.OptionDialog; import ghidra.app.CorePluginPackage; import ghidra.app.plugin.PluginCategoryNames; import ghidra.framework.main.FrontEndTool; -import ghidra.framework.main.FrontEndable; +import ghidra.framework.main.ApplicationLevelPlugin; import ghidra.framework.main.datatable.ProjectDataContext; import ghidra.framework.model.*; import ghidra.framework.plugintool.*; @@ -52,7 +52,7 @@ import ghidra.util.task.*; description = "This plugin provides the set language feature." ) //@formatter:on -public final class LanguageProviderPlugin extends Plugin implements FrontEndable { +public final class LanguageProviderPlugin extends Plugin implements ApplicationLevelPlugin { private DockingAction setLanguageAction; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/totd/TipOfTheDayPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/totd/TipOfTheDayPlugin.java index 353faf4687..06640b9cbc 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/totd/TipOfTheDayPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/totd/TipOfTheDayPlugin.java @@ -26,7 +26,7 @@ import docking.action.MenuData; import docking.tool.ToolConstants; import ghidra.app.CorePluginPackage; import ghidra.app.plugin.PluginCategoryNames; -import ghidra.framework.main.FrontEndOnly; +import ghidra.framework.main.ApplicationLevelOnlyPlugin; import ghidra.framework.plugintool.*; import ghidra.framework.plugintool.util.PluginStatus; import ghidra.framework.preferences.Preferences; @@ -43,7 +43,7 @@ import utilities.util.FileUtilities; description = "Display a dialog containing 'Tips of the Day'." ) //@formatter:on -public class TipOfTheDayPlugin extends Plugin implements FrontEndOnly { +public class TipOfTheDayPlugin extends Plugin implements ApplicationLevelOnlyPlugin { private static final String TIP_INDEX = "TIP_INDEX"; private static final String SHOW_TIPS = "SHOW_TIPS"; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/debug/DomainFolderChangesDisplayPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/debug/DomainFolderChangesDisplayPlugin.java index de79e6fa4b..762577a456 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/debug/DomainFolderChangesDisplayPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/debug/DomainFolderChangesDisplayPlugin.java @@ -17,7 +17,7 @@ package ghidra.app.plugin.debug; import ghidra.app.DeveloperPluginPackage; import ghidra.app.plugin.PluginCategoryNames; -import ghidra.framework.main.FrontEndOnly; +import ghidra.framework.main.ApplicationLevelOnlyPlugin; import ghidra.framework.main.FrontEndService; import ghidra.framework.model.*; import ghidra.framework.plugintool.*; @@ -34,7 +34,7 @@ import ghidra.framework.plugintool.util.PluginStatus; ) //@formatter:on public class DomainFolderChangesDisplayPlugin extends Plugin - implements FrontEndOnly, ProjectListener, DomainFolderChangeListener { + implements ApplicationLevelOnlyPlugin, ProjectListener, DomainFolderChangeListener { private DomainFolderChangesDisplayComponentProvider provider; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/debug/GenerateOldLanguagePlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/debug/GenerateOldLanguagePlugin.java index 8da7f2655c..9999744a58 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/debug/GenerateOldLanguagePlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/debug/GenerateOldLanguagePlugin.java @@ -40,7 +40,7 @@ import ghidra.app.DeveloperPluginPackage; import ghidra.app.plugin.PluginCategoryNames; import ghidra.app.util.bean.SelectLanguagePanel; import ghidra.framework.Application; -import ghidra.framework.main.FrontEndable; +import ghidra.framework.main.ApplicationLevelPlugin; import ghidra.framework.plugintool.*; import ghidra.framework.plugintool.util.PluginStatus; import ghidra.program.model.address.AddressSpace; @@ -64,7 +64,7 @@ import ghidra.util.xml.GenericXMLOutputter; "language which will modify its address spaces or register definitions." ) //@formatter:on -public class GenerateOldLanguagePlugin extends Plugin implements FrontEndable { +public class GenerateOldLanguagePlugin extends Plugin implements ApplicationLevelPlugin { private static final ExtensionFileFilter OLD_LANG_FILTER = new ExtensionFileFilter("lang", "Old Language File"); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/debug/JavaHelpPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/debug/JavaHelpPlugin.java index 631238e07c..af2480d9a6 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/debug/JavaHelpPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/debug/JavaHelpPlugin.java @@ -30,7 +30,7 @@ import docking.help.*; import docking.tool.ToolConstants; import ghidra.app.DeveloperPluginPackage; import ghidra.app.plugin.PluginCategoryNames; -import ghidra.framework.main.FrontEndable; +import ghidra.framework.main.ApplicationLevelPlugin; import ghidra.framework.model.Project; import ghidra.framework.plugintool.*; import ghidra.framework.plugintool.util.PluginStatus; @@ -52,7 +52,7 @@ import ghidra.util.task.*; JavaHelpPlugin.infoName + ", is written to your home directory." ) //@formatter:on -public class JavaHelpPlugin extends Plugin implements FrontEndable { +public class JavaHelpPlugin extends Plugin implements ApplicationLevelPlugin { static final String infoName = "GhidraHelpInfo.txt"; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/gui/LookAndFeelPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/gui/LookAndFeelPlugin.java index 3101b8ec85..b71ec19dda 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/gui/LookAndFeelPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/gui/LookAndFeelPlugin.java @@ -25,7 +25,7 @@ import docking.widgets.OptionDialog; import ghidra.app.CorePluginPackage; import ghidra.app.plugin.PluginCategoryNames; import ghidra.docking.util.DockingWindowsLookAndFeelUtils; -import ghidra.framework.main.FrontEndOnly; +import ghidra.framework.main.ApplicationLevelOnlyPlugin; import ghidra.framework.main.FrontEndTool; import ghidra.framework.options.*; import ghidra.framework.plugintool.*; @@ -44,7 +44,7 @@ import ghidra.util.*; "only in the Ghidra Project Window." ) //@formatter:on -public class LookAndFeelPlugin extends Plugin implements FrontEndOnly, OptionsChangeListener { +public class LookAndFeelPlugin extends Plugin implements ApplicationLevelOnlyPlugin, OptionsChangeListener { private String selectedLookAndFeel; private boolean useInvertedColors; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/plugin/importer/ImporterPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/plugin/importer/ImporterPlugin.java index e9173b83fa..c986188f9f 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/plugin/importer/ImporterPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/plugin/importer/ImporterPlugin.java @@ -73,7 +73,7 @@ import ghidra.util.task.TaskLauncher; ) //@formatter:on public class ImporterPlugin extends Plugin - implements FileImporterService, FrontEndable, ProjectListener { + implements FileImporterService, ApplicationLevelPlugin, ProjectListener { private static final String IMPORT_MENU_GROUP = "Import"; static final String IMPORTER_PLUGIN_DESC = diff --git a/Ghidra/Features/Base/src/main/java/ghidra/plugins/fsbrowser/FileSystemBrowserPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/plugins/fsbrowser/FileSystemBrowserPlugin.java index e72218f650..feb8a01738 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/plugins/fsbrowser/FileSystemBrowserPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/plugins/fsbrowser/FileSystemBrowserPlugin.java @@ -38,7 +38,7 @@ import ghidra.app.services.*; import ghidra.app.util.opinion.LoaderService; import ghidra.formats.gfilesystem.*; import ghidra.framework.main.FrontEndService; -import ghidra.framework.main.FrontEndable; +import ghidra.framework.main.ApplicationLevelPlugin; import ghidra.framework.model.Project; import ghidra.framework.model.ProjectListener; import ghidra.framework.plugintool.*; @@ -70,7 +70,7 @@ import utilities.util.FileUtilities; eventsConsumed = { ProgramActivatedPluginEvent.class } ) //@formatter:on -public class FileSystemBrowserPlugin extends Plugin implements FrontEndable, ProjectListener, +public class FileSystemBrowserPlugin extends Plugin implements ApplicationLevelPlugin, ProjectListener, FileSystemBrowserService { /* package */ DockingAction openFilesystemAction; diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/plugintool/dialog/ManageFrontEndToolTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/plugintool/dialog/ManageFrontEndToolTest.java index fa08427e86..1b8e0b37ce 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/plugintool/dialog/ManageFrontEndToolTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/plugintool/dialog/ManageFrontEndToolTest.java @@ -67,11 +67,11 @@ public class ManageFrontEndToolTest extends AbstractGhidraHeadedIntegrationTest int count = 0; List allPluginDescriptions = pluginModel.getAllPluginDescriptions(); for (PluginDescription pluginDescription : allPluginDescriptions) { - assertTrue(FrontEndable.class.isAssignableFrom(pluginDescription.getPluginClass())); + assertTrue(ApplicationLevelPlugin.class.isAssignableFrom(pluginDescription.getPluginClass())); count++; } - List> classes = ClassSearcher.getClasses(FrontEndable.class); + List> classes = ClassSearcher.getClasses(ApplicationLevelPlugin.class); assertEquals(count, classes.size()); } diff --git a/Ghidra/Features/FileFormats/src/main/java/ghidra/plugins/fileformats/FileFormatsPlugin.java b/Ghidra/Features/FileFormats/src/main/java/ghidra/plugins/fileformats/FileFormatsPlugin.java index f34a4aee3d..4766899230 100644 --- a/Ghidra/Features/FileFormats/src/main/java/ghidra/plugins/fileformats/FileFormatsPlugin.java +++ b/Ghidra/Features/FileFormats/src/main/java/ghidra/plugins/fileformats/FileFormatsPlugin.java @@ -38,7 +38,7 @@ import ghidra.file.formats.ios.prelink.MachoPrelinkFileSystem; import ghidra.file.jad.JadProcessWrapper; import ghidra.file.jad.JarDecompiler; import ghidra.formats.gfilesystem.*; -import ghidra.framework.main.FrontEndable; +import ghidra.framework.main.ApplicationLevelPlugin; import ghidra.framework.plugintool.*; import ghidra.framework.plugintool.util.PluginStatus; import ghidra.plugins.fsbrowser.*; @@ -60,7 +60,7 @@ import ghidra.util.task.TaskMonitor; description = "This plugin provides file format related actions to the File System Browser." ) //@formatter:on -public class FileFormatsPlugin extends Plugin implements FrontEndable { +public class FileFormatsPlugin extends Plugin implements ApplicationLevelPlugin { private GhidraFileChooser chooserEclipse; private GhidraFileChooser chooserJarFolder; diff --git a/Ghidra/Framework/Project/certification.manifest b/Ghidra/Framework/Project/certification.manifest index ec923064e2..ab5289e0bc 100644 --- a/Ghidra/Framework/Project/certification.manifest +++ b/Ghidra/Framework/Project/certification.manifest @@ -20,6 +20,7 @@ src/main/java/ghidra/framework/project/tool/package.html||GHIDRA||||END| src/main/resources/images/Minus.png||GHIDRA||||END| src/main/resources/images/Plus.png||GHIDRA||||END| src/main/resources/images/allInTool.gif||GHIDRA||reviewed||END| +src/main/resources/images/applications-development-web.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END| src/main/resources/images/applications-science.png||Oxygen Icons - LGPL 3.0||||END| src/main/resources/images/bug.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END| src/main/resources/images/check.png||GHIDRA||reviewed||END| diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/debug/MemoryUsagePlugin.java b/Ghidra/Framework/Project/src/main/java/ghidra/app/plugin/debug/MemoryUsagePlugin.java similarity index 89% rename from Ghidra/Features/Base/src/main/java/ghidra/app/plugin/debug/MemoryUsagePlugin.java rename to Ghidra/Framework/Project/src/main/java/ghidra/app/plugin/debug/MemoryUsagePlugin.java index 9c11536146..8e50566fef 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/debug/MemoryUsagePlugin.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/app/plugin/debug/MemoryUsagePlugin.java @@ -15,32 +15,29 @@ */ package ghidra.app.plugin.debug; -import ghidra.app.CorePluginPackage; -import ghidra.app.plugin.PluginCategoryNames; -import ghidra.framework.main.FrontEndOnly; -import ghidra.framework.plugintool.*; -import ghidra.framework.plugintool.util.PluginStatus; -import ghidra.util.HelpLocation; import docking.ActionContext; import docking.DialogComponentProvider; import docking.action.DockingAction; import docking.action.MenuData; +import ghidra.app.plugin.PluginCategoryNames; +import ghidra.framework.main.ApplicationLevelOnlyPlugin; +import ghidra.framework.main.UtilityPluginPackage; +import ghidra.framework.plugintool.*; +import ghidra.framework.plugintool.util.PluginStatus; +import ghidra.util.HelpLocation; //@formatter:off @PluginInfo( status = PluginStatus.RELEASED, - packageName = CorePluginPackage.NAME, + packageName = UtilityPluginPackage.NAME, category = PluginCategoryNames.SUPPORT, shortDescription = "VM Memory Display", description = "Plugin for displaying the VM memory information." ) //@formatter:on -public class MemoryUsagePlugin extends Plugin implements FrontEndOnly { +public class MemoryUsagePlugin extends Plugin implements ApplicationLevelOnlyPlugin { private DialogComponentProvider dialog; - /** - * Constructor - */ public MemoryUsagePlugin(PluginTool tool) { super(tool); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/debug/ShowMemoryDialog.java b/Ghidra/Framework/Project/src/main/java/ghidra/app/plugin/debug/ShowMemoryDialog.java similarity index 100% rename from Ghidra/Features/Base/src/main/java/ghidra/app/plugin/debug/ShowMemoryDialog.java rename to Ghidra/Framework/Project/src/main/java/ghidra/app/plugin/debug/ShowMemoryDialog.java diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/FrontEndOnly.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/ApplicationLevelOnlyPlugin.java similarity index 74% rename from Ghidra/Framework/Project/src/main/java/ghidra/framework/main/FrontEndOnly.java rename to Ghidra/Framework/Project/src/main/java/ghidra/framework/main/ApplicationLevelOnlyPlugin.java index 17688386b2..57518e859e 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/FrontEndOnly.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/ApplicationLevelOnlyPlugin.java @@ -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. @@ -16,10 +15,10 @@ */ package ghidra.framework.main; - /** - * Marker interface to indicate plugin is for Front-end use only. + * Marker interface to indicate this plugin is application-level tools only (see + * {@link ApplicationLevelPlugin}). */ -public interface FrontEndOnly extends FrontEndable { - +public interface ApplicationLevelOnlyPlugin extends ApplicationLevelPlugin { + // marker interface } diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/FrontEndable.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/ApplicationLevelPlugin.java similarity index 61% rename from Ghidra/Framework/Project/src/main/java/ghidra/framework/main/FrontEndable.java rename to Ghidra/Framework/Project/src/main/java/ghidra/framework/main/ApplicationLevelPlugin.java index f6f989659c..f66941166d 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/FrontEndable.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/ApplicationLevelPlugin.java @@ -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,10 +16,12 @@ package ghidra.framework.main; /** - * Marker that allows a plugin to be added directly to the Ghidra Project - * Window by the user. - * Some plugins may get added due to dependencies by FrontEndable - * plugins. + * Marker that signals the implementing plugin can be added to the system at the application level. + *

+ * Some applications have only a single tool while other applications may have multiple tools, with + * a top-level tool that manages other sub-tools. A plugin implementing this interface can be used + * in any of these tools. */ -public interface FrontEndable { +public interface ApplicationLevelPlugin { + // marker interface } diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/FrontEndTool.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/FrontEndTool.java index 9f688a8971..340987cc21 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/FrontEndTool.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/FrontEndTool.java @@ -27,6 +27,7 @@ import java.util.Set; import javax.swing.JFrame; import javax.swing.JPanel; +import org.apache.commons.lang3.StringUtils; import org.jdom.Element; import org.jdom.JDOMException; import org.jdom.input.SAXBuilder; @@ -108,8 +109,11 @@ public class FrontEndTool extends PluginTool implements OptionsChangeListener { private final static String GHIDRA_MAIN_PANEL_DIVIDER_LOC = "GhidraMainPanelDividerLocation"; private static final String FRONT_END_TOOL_XML_NAME = "FRONTEND"; + private static final String VERSION_ATTRIBUTE_NAME = "VERSION"; private static final String FRONT_END_FILE_NAME = "FrontEndTool.xml"; private static final String CONFIGURE_GROUP = "Configure"; + private static final File TOOL_FILE = + new File(Application.getUserSettingsDirectory(), FRONT_END_FILE_NAME); private WeakSet listeners; private FrontEndPlugin plugin; @@ -123,7 +127,7 @@ public class FrontEndTool extends PluginTool implements OptionsChangeListener { /** * Construct a new Ghidra Project Window. - * + * * @param pm project manager */ public FrontEndTool(ProjectManager pm) { @@ -132,7 +136,7 @@ public class FrontEndTool extends PluginTool implements OptionsChangeListener { listeners = WeakDataStructureFactory.createCopyOnWriteWeakSet(); - addFrontEndPlugin(); + installFrontEndPlugins(); createActions(); loadToolConfigurationFromDisk(); @@ -164,7 +168,7 @@ public class FrontEndTool extends PluginTool implements OptionsChangeListener { @Override public PluginClassManager getPluginClassManager() { if (pluginClassManager == null) { - pluginClassManager = new PluginClassManager(FrontEndable.class, null); + pluginClassManager = new PluginClassManager(ApplicationLevelPlugin.class, null); } return pluginClassManager; } @@ -174,46 +178,97 @@ public class FrontEndTool extends PluginTool implements OptionsChangeListener { } private void loadToolConfigurationFromDisk() { - File saveFile = new File(Application.getUserSettingsDirectory(), FRONT_END_FILE_NAME); - if (!saveFile.exists()) { - addFrontEndablePlugins(); + + Element root = getToolFileXml(); + if (root == null) { + installDefaultApplicationLevelPlugins(); return; } - try { - InputStream is = new FileInputStream(saveFile); - SAXBuilder sax = XmlUtilities.createSecureSAXBuilder(false, false); - Element root = sax.build(is).getRootElement(); - GhidraToolTemplate template = new GhidraToolTemplate( - (Element) root.getChildren().get(0), saveFile.getAbsolutePath()); - refresh(template); + GhidraToolTemplate template = new GhidraToolTemplate((Element) root.getChildren().get(0), + TOOL_FILE.getAbsolutePath()); + refresh(template); + } + + private Element getToolFileXml() { + if (!TOOL_FILE.exists()) { + return null; } - catch (JDOMException e) { - Msg.showError(this, null, "Error", "Error in XML reading front end configuration", e); + + try (InputStream is = new FileInputStream(TOOL_FILE)) { + SAXBuilder sax = XmlUtilities.createSecureSAXBuilder(false, false); + return sax.build(is).getRootElement(); } - catch (IOException e) { + catch (IOException | JDOMException e) { Msg.showError(this, null, "Error", "Error reading front end configuration", e); } + return null; } void saveToolConfigurationToDisk() { ToolTemplate template = saveToolToToolTemplate(); Element root = new Element(FRONT_END_TOOL_XML_NAME); + + String version = Application.getApplicationVersion(); + root.setAttribute(VERSION_ATTRIBUTE_NAME, version); root.addContent(template.saveToXml()); - File saveFile = new File(Application.getUserSettingsDirectory(), FRONT_END_FILE_NAME); - try { - OutputStream os = new FileOutputStream(saveFile); + try (OutputStream os = new FileOutputStream(TOOL_FILE)) { org.jdom.Document doc = new org.jdom.Document(root); XMLOutputter xmlOut = new GenericXMLOutputter(); xmlOut.output(doc, os); - os.close(); } catch (IOException e) { Msg.showError(this, null, "Error", "Error saving front end configuration", e); } } - private void addFrontEndPlugin() { + private void installFrontEndPlugins() { + installFrontEndPlugin(); + + // manually install for old tool versions that have no knowledge of utility plugins + if (isPreUtilityGhidraVersion()) { + installUtilityPlugins(); + } + } + + private boolean isPreUtilityGhidraVersion() { + + Element root = getToolFileXml(); + String version = root.getAttributeValue(VERSION_ATTRIBUTE_NAME); + + // Note: any version implies the tool is newer than the addition of the 'version' + // attribute. In that case, the utility plugins are managed by the xml. + return StringUtils.isBlank(version); + } + + /** + * Add those plugins that implement the ApplicationLevelPlugin interface and have a + * RELEASED status and not (example || testing) category. + */ + private void installDefaultApplicationLevelPlugins() { + List classNames = new ArrayList<>(); + for (Class pluginClass : ClassSearcher.getClasses(Plugin.class, + c -> ApplicationLevelPlugin.class.isAssignableFrom(c))) { + + PluginDescription pd = PluginDescription.getPluginDescription(pluginClass); + String category = pd.getCategory(); + boolean isBadCategory = category.equals(GenericPluginCategoryNames.EXAMPLES) || + category.equals(GenericPluginCategoryNames.TESTING); + if (pd.getStatus() == PluginStatus.RELEASED && !isBadCategory) { + classNames.add(pluginClass.getName()); + } + } + + try { + addPlugins(classNames); + } + catch (PluginException e) { + Msg.showError(this, getToolFrame(), "Plugin Error", "Error restoring front-end plugins", + e); + } + } + + private void installFrontEndPlugin() { plugin = new FrontEndPlugin(this); plugin.setProjectManager(getProjectManager()); try { @@ -280,7 +335,7 @@ public class FrontEndTool extends PluginTool implements OptionsChangeListener { /** * Set the active project. - * + * * @param project may be null if there is no active project */ public void setActiveProject(Project project) { @@ -301,7 +356,7 @@ public class FrontEndTool extends PluginTool implements OptionsChangeListener { /** * Add the given project listener. - * + * * @param l listener to add */ public void addProjectListener(ProjectListener l) { @@ -310,7 +365,7 @@ public class FrontEndTool extends PluginTool implements OptionsChangeListener { /** * Remove the given project listener. - * + * * @param l listener to remove */ public void removeProjectListener(ProjectListener l) { @@ -319,53 +374,54 @@ public class FrontEndTool extends PluginTool implements OptionsChangeListener { /** * NOTE: do not call this from a non-Swing thread - * + * * @param tool the tool * @return true if the repository is null or is connected. */ boolean checkRepositoryConnected(PluginTool tool) { RepositoryAdapter repository = tool.getProject().getRepository(); - if (repository != null) { - if (!repository.verifyConnection()) { - if (OptionDialog.showYesNoDialog(tool.getToolFrame(), "Lost Connection to Server", - "The connection to the Ghidra Server has been lost.\n" + - "Do you want to reconnect now?") == OptionDialog.OPTION_ONE) { - try { - repository.connect(); - return true; - } - catch (NotConnectedException e) { - // message displayed by repository server adapter - return false; - } - catch (IOException e) { - ClientUtil.handleException(repository, e, "Repository Connection", - tool.getToolFrame()); - return false; - } - } + if (repository == null) { + return true; + } + if (repository.verifyConnection()) { + return true; + } + + if (OptionDialog.showYesNoDialog(tool.getToolFrame(), "Lost Connection to Server", + "The connection to the Ghidra Server has been lost.\n" + + "Do you want to reconnect now?") == OptionDialog.OPTION_ONE) { + try { + repository.connect(); + return true; + } + catch (NotConnectedException e) { + // message displayed by repository server adapter + return false; + } + catch (IOException e) { + ClientUtil.handleException(repository, e, "Repository Connection", + tool.getToolFrame()); return false; } } - return true; + + return false; } /** * Check in the given domain file. - * + * * @param tool tool that has the domain file opened * @param domainFile domain file to check in */ public void checkIn(PluginTool tool, DomainFile domainFile) { - ArrayList list = new ArrayList<>(); - list.add(domainFile); - checkIn(tool, list, tool.getToolFrame()); + checkIn(tool, List.of(domainFile), tool.getToolFrame()); } /** * Check in the list of domain files. - * + * * @param tool tool that has the domain files opened * @param fileList list of DomainFile objects * @param parent parent of dialog if an error occurs during checkin @@ -378,8 +434,7 @@ public class FrontEndTool extends PluginTool implements OptionsChangeListener { ArrayList changedList = new ArrayList<>(); ArrayList list = new ArrayList<>(); - for (int i = 0; i < fileList.size(); i++) { - DomainFile df = fileList.get(i); + for (DomainFile df : fileList) { if (df != null && df.canCheckin()) { if (!canCloseDomainFile(df)) { continue; @@ -417,7 +472,7 @@ public class FrontEndTool extends PluginTool implements OptionsChangeListener { * Merge the latest version in the repository with the given checked out * domain file. Upon completion of the merge, the domain file appears as * though the latest version was checked out. - * + * * @param tool tool that has the domain file opened * @param domainFile domain file where latest version will be merged into * @param taskListener listener that is notified when the merge task @@ -433,7 +488,7 @@ public class FrontEndTool extends PluginTool implements OptionsChangeListener { * Merge the latest version (in the repository) of each checked out file in * fileList. Upon completion of the merge, the domain file appears as though * the latest version was checked out. - * + * * @param tool tool that has the domain files opened * @param fileList list of files that are checked out and are to be merged * @param taskListener listener that is notified when the merge task @@ -447,8 +502,7 @@ public class FrontEndTool extends PluginTool implements OptionsChangeListener { ArrayList list = new ArrayList<>(); ArrayList changedList = new ArrayList<>(); - for (int i = 0; i < fileList.size(); i++) { - DomainFile df = fileList.get(i); + for (DomainFile df : fileList) { if (df != null && df.canMerge()) { if (!canCloseDomainFile(df)) { continue; @@ -531,8 +585,8 @@ public class FrontEndTool extends PluginTool implements OptionsChangeListener { menuData.setMenuSubGroup(CONFIGURE_GROUP + 2); installExtensionsAction.setMenuBarData(menuData); - installExtensionsAction.setHelpLocation( - new HelpLocation(GenericHelpTopics.FRONT_END, "Extensions")); + installExtensionsAction + .setHelpLocation(new HelpLocation(GenericHelpTopics.FRONT_END, "Extensions")); installExtensionsAction.setEnabled(true); addAction(installExtensionsAction); } @@ -558,8 +612,8 @@ public class FrontEndTool extends PluginTool implements OptionsChangeListener { menuData.setMenuSubGroup(CONFIGURE_GROUP + 1); configureToolAction.setMenuBarData(menuData); - configureToolAction.setHelpLocation( - new HelpLocation(GenericHelpTopics.FRONT_END, "Configure")); + configureToolAction + .setHelpLocation(new HelpLocation(GenericHelpTopics.FRONT_END, "Configure")); configureToolAction.setEnabled(true); addAction(configureToolAction); } @@ -571,11 +625,9 @@ public class FrontEndTool extends PluginTool implements OptionsChangeListener { return toolTemplate; } - ////////////////////////////////////////////////////////////////////// - /** * Get project listeners. - * + * * @return ProjectListener[] */ Iterable getListeners() { @@ -597,50 +649,14 @@ public class FrontEndTool extends PluginTool implements OptionsChangeListener { plugin.readDataState(saveState); } - //////////////////////////////////////////////////////////////////// - /** - * Add those plugins that implement the FrontEndable interface and have a - * RELEASED status and not (example || testing) category. - */ - private void addFrontEndablePlugins() { - List classNames = new ArrayList<>(); - for (Class pluginClass : ClassSearcher.getClasses(Plugin.class, - c -> FrontEndable.class.isAssignableFrom(c))) { - - PluginDescription pd = PluginDescription.getPluginDescription(pluginClass); - String category = pd.getCategory(); - boolean isBadCategory = category.equals(GenericPluginCategoryNames.EXAMPLES) || - category.equals(GenericPluginCategoryNames.TESTING); - if (pd.getStatus() == PluginStatus.RELEASED && !isBadCategory) { - classNames.add(pluginClass.getName()); - } - } - - try { - addPlugins(classNames.toArray(new String[classNames.size()])); - } - catch (PluginException e) { - Msg.showError(this, getToolFrame(), "Plugin Error", "Error restoring front-end plugins", - e); - } - } - - /** - * Refresh the plugins in the Ghidra Project Window based on what is - * contained in the given XML Element. - * - * @param tc object that contains an entry for each plugin and its - * configuration state + * Refresh the plugins in the Ghidra Project Window based on what is contained in the given XML + * Element. + * + * @param tc object that contains an entry for each plugin and its configuration state */ private void refresh(ToolTemplate tc) { listeners = WeakDataStructureFactory.createCopyOnWriteWeakSet(); - List list = getManagedPlugins(); - list.remove(plugin); - Plugin[] plugins = new Plugin[list.size()]; - plugins = list.toArray(plugins); - removePlugins(plugins); - Element root = tc.saveToXml(); Element elem = root.getChild("TOOL"); @@ -691,7 +707,7 @@ public class FrontEndTool extends PluginTool implements OptionsChangeListener { /** * Get the int value for the given string. - * + * * @param value the string value to parse * @param defaultValue return this value if a NumberFormatException is * thrown during the parseInt() method @@ -866,7 +882,7 @@ public class FrontEndTool extends PluginTool implements OptionsChangeListener { /** * Construct a new MergeTask. - * + * * @param tool tool that has the domain files open * @param list list of DomainFiles to be merged * @param taskListener listener that is notified when this task diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/UtilityPluginPackage.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/UtilityPluginPackage.java new file mode 100644 index 0000000000..17e4196024 --- /dev/null +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/UtilityPluginPackage.java @@ -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.util.PluginPackage; +import resources.ResourceManager; + +public class UtilityPluginPackage extends PluginPackage { + + public static final String NAME = "Utility"; + + public UtilityPluginPackage() { + super(NAME, ResourceManager.loadImage("images/applications-development-web.png"), + "These plugins provide basic functionality useful to all tools.", UTILITY_PRIORITY); + } +} diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/Plugin.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/Plugin.java index 16617d98bb..b96c19ebfc 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/Plugin.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/Plugin.java @@ -72,7 +72,7 @@ import ghidra.util.classfinder.ExtensionPoint; * {@link PluginTool#getOptions(String)}. (optional)
* *

  • Other Plugins are constructed, dependencies evaluated, etc.
    - * If your dependencies are not available (ie. not installed, threw an exception during their + * If your dependencies are not available (i.e., not installed, threw an exception during their * initialization, etc), your Plugin's {@link #dispose()} will be called and then your Plugin * instance will be discarded.
    *
  • Your Plugin's {@link #init()} method is called (when its dependencies are met). @@ -87,8 +87,9 @@ import ghidra.util.classfinder.ExtensionPoint; *
  • ...user uses Ghidra... *
      *
    • Your Plugin's {@link #processEvent(PluginEvent)} is called for events. - *
    • Your Plugin's Action's methods (ie. - * {@link DockingAction#actionPerformed(docking.ActionContext) actionPerformed}) are called. + *
    • Your Plugin's Action's methods (i.e., + * {@link DockingAction#actionPerformed(docking.ActionContext) actionPerformed}) are + * called. *
    • Your Plugin's published service methods are called by other Plugins. *
    • Your Plugin's listener methods are called. *
    @@ -113,12 +114,12 @@ import ghidra.util.classfinder.ExtensionPoint; * calls the {@link PluginTool#getService(Class)} method. *

    * Conversely, any services your Plugin advertises in @PluginInfo must be published via calls to - * {@link #registerServiceProvided(Class, Object) registerServiceProvided()} in your Plugin's + * {@link #registerServiceProvided(Class, Object) registerServiceProvided()} in your Plugin's * constructor. *

    - * Cyclic dependencies are not allowed and will cause the Plugin management code to fail to - * load your Plugin. (ie. PluginA requires a service that PluginB provides, which requires a service - * that PluginA provides) + * Cyclic dependencies are not allowed and will cause the Plugin management code to fail to + * load your Plugin. (i.e., PluginA requires a service that PluginB provides, which requires a + * service that PluginA provides) * *

    Plugin Service implementation

    * A Plugin may provide a service to other Plugins by advertising in its {@link PluginInfo} @@ -161,14 +162,15 @@ import ghidra.util.classfinder.ExtensionPoint; * *

    Plugin Events

    *
      - *
    • Every type of plugin event should be represented by some class extending {@link PluginEvent}. - *
    • One PluginEvent subclass may be used for more than one event type as long as there's some + *
    • Every type of plugin event should be represented by some class extending + * {@link PluginEvent}. + *
    • One PluginEvent subclass may be used for more than one event type as long as there's some * natural grouping. *
    * *

    Component Providers

    *
      - *
    • A plugin may supply a {@link ComponentProvider} that provides a visual component when + *
    • A plugin may supply a {@link ComponentProvider} that provides a visual component when * the plugin is added to the tool. *
    * @@ -176,10 +178,10 @@ import ghidra.util.classfinder.ExtensionPoint; *
      *
    • {@link OptionsChangeListener} - to receive notification when a configuration option * is changed by the user. - *
    • {@link FrontEndable} - marks this Plugin as being suitable for inclusion in the FrontEnd - * tool. - *
    • {@link FrontEndOnly} - marks this Plugin as FrontEnd only, not usable in CodeBrowser or - * other tools. + *
    • {@link ApplicationLevelPlugin} - marks this Plugin as being suitable for inclusion in the + * application-level tool. + *
    • {@link ApplicationLevelOnlyPlugin} - marks this Plugin as application-level only, not + * usable in an application's sub-tools. *
    • {@link ProgramaticUseOnly} - marks this Plugin as special and not for user configuration. *
    * @@ -251,7 +253,7 @@ public abstract class Plugin implements ExtensionPoint, PluginEventListener, Ser } /** - * Auto-registers any services directly implemented by this Plugin instance (ie. + * Auto-registers any services directly implemented by this Plugin instance (i.e., * the MyService in "class MyPlugin extends Plugin implements MyService { }" ) */ private void registerPluginImplementedServices() { @@ -377,7 +379,7 @@ public abstract class Plugin implements ExtensionPoint, PluginEventListener, Ser } /** - * Called after the constructor and before {@link #init()} to publish services to + * Called after the constructor and before {@link #init()} to publish services to * the Tool's service registry. *

    * Services registered during the constructor call will be queued in the services list. @@ -520,7 +522,7 @@ public abstract class Plugin implements ExtensionPoint, PluginEventListener, Ser /** * Check if this plugin depends on the given plugin - * + * * @param plugin the plugin * @return true if this plugin depends on the given plugin */ @@ -836,7 +838,7 @@ public abstract class Plugin implements ExtensionPoint, PluginEventListener, Ser * Close the plugin. This is when the plugin should release resources, such as those from * other services. This method should not close resources being used by others (that should * happen in dispose()). - * + * *

    This method will be called before {@link #dispose()}. */ protected void close() { diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/PluginManager.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/PluginManager.java index e5330629f8..7308f92f80 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/PluginManager.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/PluginManager.java @@ -86,7 +86,7 @@ class PluginManager { addPlugins(new Plugin[] { plugin }); } - void addPlugins(List classNames) throws PluginException { + void addPlugins(Collection classNames) throws PluginException { PluginException pe = null; List list = new ArrayList<>(classNames.size()); List badList = new ArrayList<>(); @@ -259,8 +259,8 @@ class PluginManager { void restorePluginsFromXml(Element root) throws PluginException { boolean isOld = isOldToolConfig(root); - List classNames = - isOld ? getPLuginClassNamesFromOldXml(root) : getPluginClassNamesToLoad(root); + Collection classNames = + isOld ? getPluginClassNamesFromOldXml(root) : getPluginClassNamesToLoad(root); Map map = isOld ? getPluginSavedStates(root, "PLUGIN") : getPluginSavedStates(root, "PLUGIN_STATE"); @@ -295,7 +295,7 @@ class PluginManager { return map; } - private List getPLuginClassNamesFromOldXml(Element root) { + private Set getPluginClassNamesFromOldXml(Element root) { List classNames = new ArrayList<>(); List pluginElementList = root.getChildren("PLUGIN"); Iterator iter = pluginElementList.iterator(); @@ -312,7 +312,7 @@ class PluginManager { return root.getChild("PLUGIN") != null; } - private List getPluginClassNamesToLoad(Element root) { + private Set getPluginClassNamesToLoad(Element root) { PluginClassManager pluginClassManager = tool.getPluginClassManager(); return pluginClassManager.getPluginClasses(root); } diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/PluginTool.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/PluginTool.java index 8d2b710765..20e34a5d0d 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/PluginTool.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/PluginTool.java @@ -47,8 +47,7 @@ import ghidra.framework.OperatingSystem; import ghidra.framework.Platform; import ghidra.framework.cmd.BackgroundCommand; import ghidra.framework.cmd.Command; -import ghidra.framework.main.AppInfo; -import ghidra.framework.main.UserAgreementDialog; +import ghidra.framework.main.*; import ghidra.framework.model.*; import ghidra.framework.options.*; import ghidra.framework.plugintool.dialog.ExtensionTableProvider; @@ -226,6 +225,34 @@ public abstract class PluginTool extends AbstractDockingTool { winMgr.setHomeButton(homeIcon, callback); } + /** + * Loads all application-level utility classes into this tool. This should only be called + * by tools that represent the global application tool and not for sub-tools. + */ + protected void installUtilityPlugins() { + + PluginClassManager classManager = getPluginClassManager(); + PluginPackage utilityPackage = PluginPackage.getPluginPackage(UtilityPluginPackage.NAME); + List descriptions = classManager.getPluginDescriptions(utilityPackage); + + Set classNames = new HashSet<>(); + if (descriptions == null) { + return; + } + for (PluginDescription description : descriptions) { + String pluginClass = description.getPluginClass().getName(); + classNames.add(pluginClass); + } + + try { + addPlugins(classNames); + } + catch (PluginException e) { + Msg.showError(this, null, "Error Adding Utility Plugins", + "Unexpected exception adding application utility plugins", e); + } + } + /** * Placeholder for subclasses to get a chance to install actions before plugins. * @@ -796,9 +823,7 @@ public abstract class PluginTool extends AbstractDockingTool { * class already exists in the tool */ public void addPlugin(String className) throws PluginException { - checkedRunSwingNow(() -> { - addPlugins(new String[] { className }); - }, PluginException.class); + addPlugins(List.of(className)); } /** @@ -807,37 +832,36 @@ public abstract class PluginTool extends AbstractDockingTool { * @throws PluginException if a plugin could not be constructed, or * there was problem executing its init() method, or if a plugin of this * class already exists in the tool - * @deprecated use {@link #addPlugins(List)} + * @deprecated use {@link #addPlugins(Collection)} */ @Deprecated(since = "10.2", forRemoval = true) public void addPlugins(String[] classNames) throws PluginException { - try { - pluginMgr.addPlugins(Arrays.asList(classNames)); - } - finally { - setConfigChanged(true); - } + addPlugins(Arrays.asList(classNames)); } /** * Add plugins to the tool. - * @param classNames array of plugin class names + * @param classNames collection of plugin class names * @throws PluginException if a plugin could not be constructed, or * there was problem executing its init() method, or if a plugin of this * class already exists in the tool */ - public void addPlugins(List classNames) throws PluginException { - try { - pluginMgr.addPlugins(classNames); - } - finally { - setConfigChanged(true); - } + public void addPlugins(Collection classNames) throws PluginException { + checkedRunSwingNow(() -> { + try { + pluginMgr.addPlugins(classNames); + } + finally { + setConfigChanged(true); + } + }, PluginException.class); } public void addPlugin(Plugin p) throws PluginException { - pluginMgr.addPlugin(p); - setConfigChanged(true); + checkedRunSwingNow(() -> { + pluginMgr.addPlugin(p); + setConfigChanged(true); + }, PluginException.class); } /** @@ -847,14 +871,7 @@ public abstract class PluginTool extends AbstractDockingTool { */ @Deprecated(since = "10.2", forRemoval = true) public void removePlugins(Plugin[] plugins) { - SystemUtilities.runSwingNow(() -> { - try { - pluginMgr.removePlugins(Arrays.asList(plugins)); - } - finally { - setConfigChanged(true); - } - }); + removePlugins(Arrays.asList(plugins)); } /** @@ -862,7 +879,7 @@ public abstract class PluginTool extends AbstractDockingTool { * @param plugins array of plugins to remove */ public void removePlugins(List plugins) { - SystemUtilities.runSwingNow(() -> { + Swing.runNow(() -> { try { pluginMgr.removePlugins(plugins); } diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/StandAloneApplication.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/StandAloneApplication.java index ef7041b8e8..0db4322fb1 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/StandAloneApplication.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/StandAloneApplication.java @@ -31,7 +31,7 @@ import docking.framework.*; import ghidra.framework.*; import ghidra.framework.model.ToolServices; import ghidra.util.Msg; -import ghidra.util.SystemUtilities; +import ghidra.util.Swing; import ghidra.util.classfinder.ClassSearcher; import ghidra.util.exception.CancelledException; import ghidra.util.xml.GenericXMLOutputter; @@ -56,7 +56,7 @@ public abstract class StandAloneApplication implements GenericStandAloneApplicat * {@link ApplicationProperties#APPLICATION_NAME_PROPERTY} and * {@link ApplicationProperties#APPLICATION_VERSION_PROPERTY} properties * set. - * + * * @param propertiesFilename the name of the properties file. * @throws IOException error causing application initialization failure */ @@ -76,7 +76,7 @@ public abstract class StandAloneApplication implements GenericStandAloneApplicat } /** - * reates a new application using the given application layout + * Creates a new application using the given application layout * and associated application properties. * @param applicationLayout application layout */ @@ -155,7 +155,7 @@ public abstract class StandAloneApplication implements GenericStandAloneApplicat setDockIcon(); try { - SystemUtilities.runSwingNow(() -> tool = createTool()); + Swing.runNow(() -> tool = createTool()); } catch (Exception e) { Msg.error(this, "Error creating tool, exiting...", e); @@ -201,6 +201,7 @@ public abstract class StandAloneApplication implements GenericStandAloneApplicat protected void initializeTool(StandAlonePluginTool newTool) { newTool.addExitAction(); + newTool.installUtilityPlugins(); } private Element getDefaultToolElement() { diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/util/PluginClassManager.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/util/PluginClassManager.java index 7e58d16201..a31596bd54 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/util/PluginClassManager.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/util/PluginClassManager.java @@ -33,7 +33,6 @@ public class PluginClassManager { public PluginClassManager(Class filterClass, Class exclusionClass) { populatePluginDescriptionMaps(filterClass, exclusionClass); - } public PluginDescription getPluginDescription(String className) { @@ -129,6 +128,7 @@ public class PluginClassManager { PluginPackage pluginPackage = pluginDescription.getPluginPackage(); List list = pluginPackageMap.get(pluginPackage); if (list == null) { + list = new ArrayList<>(); pluginPackageMap.put(pluginPackage, list); } @@ -143,7 +143,7 @@ public class PluginClassManager { * @param classNames the list of classNames from from the old XML file * @return the adjusted class names */ - public List fillInPackageClasses(List classNames) { + public Set fillInPackageClasses(List classNames) { Set packages = new HashSet<>(); Set adjustedClassNames = new HashSet<>(); @@ -169,15 +169,19 @@ public class PluginClassManager { } } - return new ArrayList<>(adjustedClassNames); + return adjustedClassNames; } - public List getPluginClasses(Element element) { - List classNames = new ArrayList<>(); + public Set getPluginClasses(Element element) { + Set classNames = new HashSet<>(); List children = element.getChildren("PACKAGE"); for (Object object : children) { + Element child = (Element) object; + String packageName = child.getAttributeValue("NAME"); + + // classes excluded by name in the xml Set excludedClasses = new HashSet<>(); List grandChildren = child.getChildren("EXCLUDE"); for (Object obj : grandChildren) { @@ -185,6 +189,8 @@ public class PluginClassManager { String excludedClassName = grandChild.getAttributeValue("CLASS"); excludedClasses.add(excludedClassName); } + + // classes included by name in the xml Set includedClasses = new HashSet<>(); grandChildren = child.getChildren("INCLUDE"); for (Object obj : grandChildren) { @@ -193,27 +199,34 @@ public class PluginClassManager { includedClasses.add(excludedClassName); } - String packageName = child.getAttributeValue("NAME"); PluginPackage pluginPackage = PluginPackage.getPluginPackage(packageName); List pluginDescriptionList = packageMap.get(pluginPackage); if (pluginDescriptionList == null) { continue; } + for (PluginDescription pluginDescription : pluginDescriptionList) { - String pluginClass = pluginDescription.getPluginClass().getName(); - if (pluginDescription.getStatus() == PluginStatus.RELEASED) { - if (!excludedClasses.contains(pluginClass)) { - classNames.add(pluginClass); - } - } - else { - if (includedClasses.contains(pluginClass)) { - classNames.add(pluginClass); - } + if (shouldAddPlugin(pluginDescription, includedClasses, excludedClasses)) { + classNames.add(pluginDescription.getPluginClass().getName()); } } } return classNames; + + } + + private boolean shouldAddPlugin(PluginDescription description, Set include, + Set exclude) { + + String className = description.getPluginClass().getName(); + if (include.contains(className)) { + return true; + } + if (exclude.contains(className)) { + return false; + } + return description.getStatus() == PluginStatus.RELEASED; + } public List getPluginPackages() { diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/util/PluginPackage.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/util/PluginPackage.java index a348d0bb4a..61024f8ceb 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/util/PluginPackage.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/util/PluginPackage.java @@ -25,7 +25,8 @@ import ghidra.util.classfinder.ClassSearcher; import ghidra.util.classfinder.ExtensionPoint; public abstract class PluginPackage implements ExtensionPoint, Comparable { - public static final int CORE_PRIORITY = 0; + public static final int UTILITY_PRIORITY = 0; + public static final int CORE_PRIORITY = 1; public static final int FEATURE_PRIORITY = 4; public static final int MISCELLANIOUS_PRIORITY = 6; public static final int DEVELOPER_PRIORITY = 8; diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/project/tool/GhidraTool.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/project/tool/GhidraTool.java index 693d9677d7..42c0f83605 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/project/tool/GhidraTool.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/project/tool/GhidraTool.java @@ -28,7 +28,7 @@ import docking.action.MenuData; import docking.tool.ToolConstants; import docking.widgets.OptionDialog; import ghidra.app.util.FileOpenDropHandler; -import ghidra.framework.main.FrontEndOnly; +import ghidra.framework.main.ApplicationLevelOnlyPlugin; import ghidra.framework.model.Project; import ghidra.framework.model.ToolTemplate; import ghidra.framework.options.PreferenceState; @@ -101,7 +101,7 @@ public class GhidraTool extends PluginTool { @Override public PluginClassManager getPluginClassManager() { if (pluginClassManager == null) { - pluginClassManager = new PluginClassManager(Plugin.class, FrontEndOnly.class); + pluginClassManager = new PluginClassManager(Plugin.class, ApplicationLevelOnlyPlugin.class); } return pluginClassManager; } diff --git a/Ghidra/Framework/Project/src/main/resources/images/applications-development-web.png b/Ghidra/Framework/Project/src/main/resources/images/applications-development-web.png new file mode 100644 index 0000000000..83598180c0 Binary files /dev/null and b/Ghidra/Framework/Project/src/main/resources/images/applications-development-web.png differ