From c454101dab9875999e93a534e7f8f24996e0ae22 Mon Sep 17 00:00:00 2001 From: Nick Rupley Date: Mon, 1 Jul 2024 19:17:09 -0400 Subject: [PATCH] Allowing Extensions view to pull max core versions from server. Also tweaking ExtensionLoader to only include max versions for a plugin if a max version is explicitly specified. If there is no max version in the JSON, then do not assume max=min. --- .../com/mirth/connect/client/ui/Frame.java | 8 +++ .../ExtensionManagerPanel.java | 56 +++++++++++++------ .../servlets/ExtensionServletInterface.java | 10 ++++ .../com/mirth/connect/client/core/Client.java | 10 ++++ .../mirth/connect/server/ExtensionLoader.java | 26 ++++----- .../controllers/ExtensionController.java | 5 ++ .../mirth/connect/client/ui/FrameBase.java | 6 +- .../server/api/servlets/ExtensionServlet.java | 5 ++ .../DefaultExtensionController.java | 5 ++ .../servlets/SwaggerExamplesServlet.java | 23 +++++++- 10 files changed, 119 insertions(+), 35 deletions(-) diff --git a/client/src/com/mirth/connect/client/ui/Frame.java b/client/src/com/mirth/connect/client/ui/Frame.java index 48d26a6fc5..9a279a05c1 100644 --- a/client/src/com/mirth/connect/client/ui/Frame.java +++ b/client/src/com/mirth/connect/client/ui/Frame.java @@ -248,6 +248,7 @@ public class Frame extends FrameBase { public LinkedHashMap displayNameToDataType; private Map loadedPlugins; private Map loadedConnectors; + private Map> extensionMaxCoreVersions; private Map safeErrorFailCountMap = new HashMap(); private Map componentTaskMap = new HashMap(); private boolean acceleratorKeyPressed = false; @@ -827,6 +828,7 @@ public void dispose() { private void loadExtensionMetaData() throws ClientException { loadedPlugins = mirthClient.getPluginMetaData(); loadedConnectors = mirthClient.getConnectorMetaData(); + extensionMaxCoreVersions = mirthClient.getExtensionMaxCoreVersions(); // Register extension JAX-RS providers with the client Set apiProviderPackages = new HashSet(); @@ -4759,6 +4761,7 @@ public void doRefreshExtensions() { } public void refreshExtensions() { + extensionsPanel.setExtensionMaxCoreVersions(getExtensionMaxCoreVersions()); extensionsPanel.setPluginData(getPluginMetaData()); extensionsPanel.setConnectorData(getConnectorMetaData()); } @@ -5008,6 +5011,11 @@ public Map getConnectorMetaData() { return this.loadedConnectors; } + @Override + public Map> getExtensionMaxCoreVersions() { + return this.extensionMaxCoreVersions; + } + public String getSelectedChannelIdFromDashboard() { return dashboardPanel.getSelectedStatuses().get(0).getChannelId(); } diff --git a/client/src/com/mirth/connect/client/ui/extensionmanager/ExtensionManagerPanel.java b/client/src/com/mirth/connect/client/ui/extensionmanager/ExtensionManagerPanel.java index 8d4159d9a6..398a2aa2e9 100644 --- a/client/src/com/mirth/connect/client/ui/extensionmanager/ExtensionManagerPanel.java +++ b/client/src/com/mirth/connect/client/ui/extensionmanager/ExtensionManagerPanel.java @@ -28,7 +28,6 @@ import org.jdesktop.swingx.decorator.HighlighterFactory; import com.mirth.connect.client.core.ClientException; -import com.mirth.connect.client.core.Version; import com.mirth.connect.client.ui.CellData; import com.mirth.connect.client.ui.Frame; import com.mirth.connect.client.ui.ImageCellRenderer; @@ -60,6 +59,7 @@ public class ExtensionManagerPanel extends javax.swing.JPanel { private final String ENABLED_STATUS = "Enabled"; private Map pluginData = null; private Map connectorData = null; + private Map> extensionMaxCoreVersions = null; private Frame parent; public ExtensionManagerPanel() { @@ -70,6 +70,10 @@ public ExtensionManagerPanel() { makeLoadedPluginsTable(); } + public void setExtensionMaxCoreVersions(Map> extensionMaxCoreVersions) { + this.extensionMaxCoreVersions = extensionMaxCoreVersions; + } + /** * Gets the selected extension index that corresponds to the saved extensions list */ @@ -231,7 +235,7 @@ private void setToolTipTexts(MirthTable table) { table.getColumnExt(PLUGIN_URL_COLUMN_NAME).setToolTipText("A website you can visit to learn more about this extension."); table.getColumnExt(PLUGIN_VERSION_COLUMN_NAME).setToolTipText("The version of this extension."); table.getColumnExt(PLUGIN_BUILD_COLUMN_NAME).setToolTipText("The specific build number of this extension, if applicable.
For \"core\" extensions that come bundled with Mirth Connect by default,
this build number will equal the build number of Mirth Connect itself."); - table.getColumnExt(MC_VERSIONS_COLUMN_NAME).setToolTipText("The version(s) of Mirth Connect that this version of this
extension is compatible with. This may be a single version,
a range from min-max, or a comma-separated list of versions."); + table.getColumnExt(MC_VERSIONS_COLUMN_NAME).setToolTipText("The version(s) of Mirth Connect that this version of this
extension is compatible with. This may be a single version,
a range from min-max, or a comma-separated list of versions.

If a \"+\" appears at the end, it means that there is not
yet any known max version specified, so this plugin should
be fully compatible with higher versions of Mirth Connect."); table.getColumnExt(CORE_COLUMN_NAME).setToolTipText("Indicates whether this extension is a \"core\" extension
that comes bundled with Mirth Connect by default."); } @@ -500,23 +504,43 @@ private String getSupportedMCVersions(MetaData metaData) { // If core library min versions are specified, derive a range of supported versions if (MapUtils.isNotEmpty(metaData.getMinCoreVersions())) { - // Assume the minimum supported MC version is the highest core library version - String minSupportedMCVersion = null; - for (Entry minCoreVersionEntry : metaData.getMinCoreVersions().entrySet()) { - if (minSupportedMCVersion == null || MigrationUtil.compareVersions(minSupportedMCVersion, minCoreVersionEntry.getValue()) < 0) { - minSupportedMCVersion = minCoreVersionEntry.getValue(); + try { + // Assume the minimum supported MC version is the highest core library version + String minSupportedMCVersion = null; + for (Entry minCoreVersionEntry : metaData.getMinCoreVersions().entrySet()) { + if (minSupportedMCVersion == null || MigrationUtil.compareVersions(minSupportedMCVersion, minCoreVersionEntry.getValue()) < 0) { + minSupportedMCVersion = minCoreVersionEntry.getValue(); + } } - } - - if (minSupportedMCVersion != null) { - supportedMCVersions = minSupportedMCVersion; - // Assume the highest supported MC version is the current version - // TODO: Get this from server-side - Version matchingMinVersion = Version.fromString(minSupportedMCVersion); - if (matchingMinVersion != null && matchingMinVersion != Version.getLatest()) { - supportedMCVersions += " - " + Version.getLatest().toString(); + if (minSupportedMCVersion != null) { + supportedMCVersions = minSupportedMCVersion; + + String maxSupportedMCVersion = null; + + // Get max version from the server-side map, if available + if (MapUtils.isNotEmpty(extensionMaxCoreVersions)) { + Map maxVersions = extensionMaxCoreVersions.get(metaData.getPath()); + if (MapUtils.isNotEmpty(maxVersions)) { + for (Entry maxCoreVersionEntry : maxVersions.entrySet()) { + if (StringUtils.isNotBlank(maxCoreVersionEntry.getValue()) && (maxSupportedMCVersion == null || MigrationUtil.compareVersions(maxSupportedMCVersion, maxCoreVersionEntry.getValue()) > 0)) { + maxSupportedMCVersion = maxCoreVersionEntry.getValue(); + } + } + } + } + + if (maxSupportedMCVersion != null) { + if (MigrationUtil.compareVersions(minSupportedMCVersion, maxSupportedMCVersion) < 0) { + supportedMCVersions += " - " + maxSupportedMCVersion; + } + } else { + supportedMCVersions += "+"; + } } + } catch (Exception e) { + // Ignore, and just use the mirthVersion from the metadata + e.printStackTrace(); } } diff --git a/core-client-api/src/com/mirth/connect/client/core/api/servlets/ExtensionServletInterface.java b/core-client-api/src/com/mirth/connect/client/core/api/servlets/ExtensionServletInterface.java index 6945b1297e..c8050e4e13 100644 --- a/core-client-api/src/com/mirth/connect/client/core/api/servlets/ExtensionServletInterface.java +++ b/core-client-api/src/com/mirth/connect/client/core/api/servlets/ExtensionServletInterface.java @@ -101,6 +101,16 @@ public void uninstallExtension(@Param("extensionPath") @RequestBody(description @ExampleObject(name = "pluginMetaData", ref = "../apiexamples/plugin_metadata_map_json") }) }) public Map getPluginMetaData() throws ClientException; + @GET + @Path("/maxcoreversions") + @Operation(summary = "Returns max core library versions for loaded extensions.") + @MirthOperation(name = "getExtensionMaxCoreVersions", display = "Get extension max core versions", auditable = false) + @ApiResponse(content = { @Content(mediaType = MediaType.APPLICATION_XML, examples = { + @ExampleObject(name = "extensionMaxCoreVersions", ref = "../apiexamples/extension_maxcoreversions_map_xml") }), + @Content(mediaType = MediaType.APPLICATION_JSON, examples = { + @ExampleObject(name = "extensionMaxCoreVersions", ref = "../apiexamples/extension_maxcoreversions_map_json") }) }) + public Map> getExtensionMaxCoreVersions() throws ClientException; + @GET @Path("/{extensionName}/enabled") @Operation(summary = "Returns the enabled status of an extension.") diff --git a/core-client/src/com/mirth/connect/client/core/Client.java b/core-client/src/com/mirth/connect/client/core/Client.java index 7e5e3c9c9b..20c6f1aad4 100644 --- a/core-client/src/com/mirth/connect/client/core/Client.java +++ b/core-client/src/com/mirth/connect/client/core/Client.java @@ -2588,6 +2588,16 @@ public Map getPluginMetaData() throws ClientException { return getServlet(ExtensionServletInterface.class).getPluginMetaData(); } + /** + * Returns max core library versions for loaded extensions. + * + * @see ExtensionServletInterface#getExtensionMaxCoreVersions + */ + @Override + public Map> getExtensionMaxCoreVersions() throws ClientException { + return getServlet(ExtensionServletInterface.class).getExtensionMaxCoreVersions(); + } + /** * Returns the enabled status of an extension. * diff --git a/core-server-plugins/src/com/mirth/connect/server/ExtensionLoader.java b/core-server-plugins/src/com/mirth/connect/server/ExtensionLoader.java index eb6f663ee8..c82ac14792 100644 --- a/core-server-plugins/src/com/mirth/connect/server/ExtensionLoader.java +++ b/core-server-plugins/src/com/mirth/connect/server/ExtensionLoader.java @@ -74,6 +74,7 @@ public static ExtensionLoader getInstance() { private Map pluginMetaDataMap = new HashMap(); private Map connectorProtocolsMap = new HashMap(); private Map invalidMetaDataMap = new HashMap(); + private Map> allExtensionMaxCoreVersions = new HashMap>(); private boolean loadedExtensions = false; private ObjectXMLSerializer serializer = ObjectXMLSerializer.getInstance(); private static Logger logger = LogManager.getLogger(ExtensionLoader.class); @@ -116,6 +117,11 @@ public Map getInvalidMetaData() { return invalidMetaDataMap; } + public Map> getExtensionMaxCoreVersions() { + loadExtensions(); + return allExtensionMaxCoreVersions; + } + @SuppressWarnings("unchecked") public Class getControllerClass(Class abstractClass) { Class overrideClass = null; @@ -183,7 +189,7 @@ public boolean isExtensionCompatible(MetaData metaData) { Map extensionMaxCoreVersions = new HashMap(); try { extensionMinCoreVersions = metaData.getMinCoreVersions(); - extensionMaxCoreVersions = getExtensionMaxCoreVersions(metaData.getPath(), metaData.getPluginVersion(), extensionMinCoreVersions); + extensionMaxCoreVersions = getExtensionMaxCoreVersions(metaData.getPath(), metaData.getPluginVersion()); } catch (Exception e) { logger.error("An error occurred while attempting to determine the extension's Core versions.", e); return false; @@ -206,13 +212,14 @@ public boolean isExtensionCompatible(MetaData metaData) { if (!MapUtils.isEmpty(extensionMaxCoreVersions)) { if (extensionMaxCoreVersions.containsKey(connectCoreVersionEntry.getKey())) { - if (!StringUtils.isEmpty(extensionMaxCoreVersions.get(connectCoreVersionEntry.getKey())) && connectCoreVersion.isGreaterThan(extensionMaxCoreVersions.get(connectCoreVersionEntry.getKey()))) { + if (StringUtils.isNotBlank(extensionMaxCoreVersions.get(connectCoreVersionEntry.getKey())) && connectCoreVersion.isGreaterThan(extensionMaxCoreVersions.get(connectCoreVersionEntry.getKey()))) { return false; } } } } + allExtensionMaxCoreVersions.put(metaData.getPath(), extensionMaxCoreVersions); return true; } else { // validate extension the old way for non-commercial extensions @@ -416,7 +423,7 @@ private static Map getConnectCoreVersions(ManifestEntry[] manife * @throws JsonProcessingException * @throws JsonMappingException */ - private Map getExtensionMaxCoreVersions(String pluginPath, String pluginVersion, Map extensionMinCoreVersions) throws JsonMappingException, JsonProcessingException { + private Map getExtensionMaxCoreVersions(String pluginPath, String pluginVersion) throws JsonMappingException, JsonProcessingException { Map extensionMaxCoreVersions = new HashMap(); if (!StringUtils.isEmpty(extensionsCoreVersionsS3File)) { @@ -433,20 +440,11 @@ private Map getExtensionMaxCoreVersions(String pluginPath, Strin while(extensionCoreVersionsS3FileIt.hasNext()) { Map.Entry extensionCoreVersionS3FileEntry = extensionCoreVersionsS3FileIt.next(); - String extensionCoreVersionS3FileEntryValue = ""; - if (extensionCoreVersionS3FileEntry.getValue().has("max") && !StringUtils.isEmpty(extensionCoreVersionS3FileEntry.getValue().get("max").textValue())) { - extensionCoreVersionS3FileEntryValue = extensionCoreVersionS3FileEntry.getValue().get("max").textValue(); - } else { - extensionCoreVersionS3FileEntryValue = extensionMinCoreVersions.get(extensionCoreVersionS3FileEntry.getKey()); + if (extensionCoreVersionS3FileEntry.getValue().has("max") && StringUtils.isNotBlank(extensionCoreVersionS3FileEntry.getValue().get("max").textValue())) { + extensionMaxCoreVersions.put(extensionCoreVersionS3FileEntry.getKey(), extensionCoreVersionS3FileEntry.getValue().get("max").textValue()); } - - extensionMaxCoreVersions.put(extensionCoreVersionS3FileEntry.getKey(), extensionCoreVersionS3FileEntryValue); } - } else { - extensionMaxCoreVersions.putAll(extensionMinCoreVersions); } - } else { - extensionMaxCoreVersions.putAll(extensionMinCoreVersions); } return extensionMaxCoreVersions; diff --git a/core-server-plugins/src/com/mirth/connect/server/controllers/ExtensionController.java b/core-server-plugins/src/com/mirth/connect/server/controllers/ExtensionController.java index a072840b06..6bcc940e0a 100644 --- a/core-server-plugins/src/com/mirth/connect/server/controllers/ExtensionController.java +++ b/core-server-plugins/src/com/mirth/connect/server/controllers/ExtensionController.java @@ -157,6 +157,11 @@ public Properties getPluginProperties(String name) throws ControllerException { public abstract Map getInvalidMetaData(); + /** + * Returns max core library versions for loaded extensions. + */ + public abstract Map> getExtensionMaxCoreVersions(); + // ************************************************************ // Connectors // ************************************************************ diff --git a/core-ui/src/com/mirth/connect/client/ui/FrameBase.java b/core-ui/src/com/mirth/connect/client/ui/FrameBase.java index 6fa8490ca6..9cf2f8e41a 100644 --- a/core-ui/src/com/mirth/connect/client/ui/FrameBase.java +++ b/core-ui/src/com/mirth/connect/client/ui/FrameBase.java @@ -115,9 +115,11 @@ public abstract class FrameBase extends JXFrame { public abstract void setVisibleTasks(JXTaskPane pane, JPopupMenu menu, int startIndex, int endIndex, boolean visible); public abstract Map getPluginMetaData(); - + public abstract Map getConnectorMetaData(); - + + public abstract Map> getExtensionMaxCoreVersions(); + /** * Enables the save button for needed page. */ diff --git a/server/src/com/mirth/connect/server/api/servlets/ExtensionServlet.java b/server/src/com/mirth/connect/server/api/servlets/ExtensionServlet.java index f05238da1f..35ff6d898d 100644 --- a/server/src/com/mirth/connect/server/api/servlets/ExtensionServlet.java +++ b/server/src/com/mirth/connect/server/api/servlets/ExtensionServlet.java @@ -97,6 +97,11 @@ public Map getPluginMetaData() { return extensionController.getPluginMetaData(); } + @Override + public Map> getExtensionMaxCoreVersions() { + return extensionController.getExtensionMaxCoreVersions(); + } + @Override public boolean isExtensionEnabled(String extensionName) { return extensionController.isExtensionEnabled(extensionName); diff --git a/server/src/com/mirth/connect/server/controllers/DefaultExtensionController.java b/server/src/com/mirth/connect/server/controllers/DefaultExtensionController.java index 30b7bfa6ad..f2ec5b218e 100644 --- a/server/src/com/mirth/connect/server/controllers/DefaultExtensionController.java +++ b/server/src/com/mirth/connect/server/controllers/DefaultExtensionController.java @@ -631,6 +631,11 @@ public Map getInvalidMetaData() { return extensionLoader.getInvalidMetaData(); } + @Override + public Map> getExtensionMaxCoreVersions() { + return extensionLoader.getExtensionMaxCoreVersions(); + } + /** * Executes the script that removes that database tables for plugins that are marked for * removal. The actual removal of the plugin directory happens in MirthLauncher.java, before diff --git a/server/src/com/mirth/connect/server/servlets/SwaggerExamplesServlet.java b/server/src/com/mirth/connect/server/servlets/SwaggerExamplesServlet.java index 65e216e82d..7bfcf5773a 100644 --- a/server/src/com/mirth/connect/server/servlets/SwaggerExamplesServlet.java +++ b/server/src/com/mirth/connect/server/servlets/SwaggerExamplesServlet.java @@ -325,6 +325,8 @@ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws Se requestedObject = getPasswordRequirementListExample(); } else if (exampleRequested.equals("plugin_metadata_map")) { requestedObject = getPluginMetaDataMapExample(); + } else if (exampleRequested.equals("extension_maxcoreversions_map")) { + requestedObject = getExtensionMaxCoreVersionsExample(); } else if (exampleRequested.equals("properties")) { requestedObject = getPropertiesExample(); } else if (exampleRequested.equals("protocols_and_cipher_suites_map")) { @@ -1198,9 +1200,24 @@ private Map getPluginMetaDataMapExample() { Map pluginMetaDataMap = new HashMap<>(); pluginMetaDataMap.put("Name", getPluginMetaDataExample()); return pluginMetaDataMap; - } - - private Properties getPropertiesExample() { + } + + private Map> getExtensionMaxCoreVersionsExample() { + Map> extensionMaxCoreVersions = new HashMap<>(); + Map versionsMap = new HashMap<>(); + versionsMap.put("mirth-core-client", Version.getLatest().toString()); + versionsMap.put("mirth-core-client-api", Version.getLatest().toString()); + versionsMap.put("mirth-core-client-base", Version.getLatest().toString()); + versionsMap.put("mirth-core-client-plugins", Version.getLatest().toString()); + versionsMap.put("mirth-core-models", Version.getLatest().toString()); + versionsMap.put("mirth-core-server-plugins", Version.getLatest().toString()); + versionsMap.put("mirth-core-ui", Version.getLatest().toString()); + versionsMap.put("mirth-core-util", Version.getLatest().toString()); + extensionMaxCoreVersions.put("Name", versionsMap); + return extensionMaxCoreVersions; + } + + private Properties getPropertiesExample() { Properties properties = new Properties(); properties.setProperty("exampleKey1", "exampleValue1"); properties.setProperty("exampleKey2", "exampleValue2");