public static Map<String, Map<NodeID, String>> getPluginAndOpenfireVersions() {
        final Set<String> allPluginNames = XMPPServer.getInstance().getPluginManager().getMetadataExtractedPlugins().values().stream().map(PluginMetadata::getName).collect(Collectors.toSet());
        allPluginNames.remove("admin"); // No need for this highly internal plugin to be included, as we will include the OF version
        final Map<String, Map<NodeID, String>> result = allPluginNames.stream().collect(Collectors.toMap(pluginName -> pluginName, pluginName -> new HashMap<>()));
        result.put("Openfire", new HashMap<>()); // Include openfire version

        for (ClusterNodeInfo cni : ClusterManager.getNodesInfo()) {
            final NodeID nodeID = cni.getNodeID();

            // Note; if any one node in the cluster does not have the GetClusterVersions task, running
            // CacheFactory.doSynchronousClusterTask() on all nodes will return an empty collection. For
            // that reason, run the task on each node individually.
            final GetClusteredVersions clusteredVersions = CacheFactory.doSynchronousClusterTask(
                new GetClusteredVersions(), nodeID.toByteArray());
            if (clusteredVersions == null) {
                // Something went wrong fetching the versions
                Log.warn("Plugin versions on node {} could not be verified because GetClusteredVersions task returned null.", nodeID);
            } else {
                result.get("Openfire").put(nodeID, clusteredVersions.getOpenfireVersion());
                for(Map.Entry<String, String> pluginVersion : clusteredVersions.getPluginVersions().entrySet()) {
                    final String name = pluginVersion.getKey();
                    final String version = pluginVersion.getValue();

                    result.computeIfAbsent(name, k -> (new HashMap<>()))
                        .put(nodeID, version);
                }
            }
        }

        return result;
    }
Returns the versions of plugins installed on all nodes in the cluster.

If, for some reason, the version information can not be retrieved from some remote node, that node will be
missing entirely from the result.

The openfire version is included in the result as well, under the key "Openfire".

@return A map of maps, containing pluginName -> (nodeId -> pluginVersion)
xmppserver/src/main/java/org/jivesoftware/openfire/cluster/ClusterManager.java