private void dumpConfiguration()

in src/main/java/org/apache/sling/installer/factories/configuration/impl/ConfigurationSerializerWebConsolePlugin.java [110:270]


    private void dumpConfiguration(
            Configuration configuration,
            ConfigurationSerializerFactory.Format serializationFormat,
            boolean hideRedundantProperties,
            PrintWriter pw) {
        // map with key = configuration pid and value = Set<ComponentDescriptionDTO>
        Map<String, Set<ComponentDescriptionDTO>> allComponentDescriptions = new HashMap<>();
        String pid = configuration != null ? configuration.getPid() : "";
        scr.getComponentDescriptionDTOs().stream().forEach(dto -> {
            for (String configPid : dto.configurationPid) {
                // the same PID might be bound to multiple component descriptions
                allComponentDescriptions
                        .computeIfAbsent(configPid, k -> new HashSet<ComponentDescriptionDTO>())
                        .add(dto);
            }
        });

        pw.println("<script type=\"text/javascript\" src=\"" + RES_LOC + "clipboard.js\"></script>");
        pw.print("<form method='get'>");
        pw.println("<table class='content' cellpadding='0' cellspacing='0' width='100%'>");

        titleHtml(
                pw,
                "OSGi Installer Configuration Printer",
                "To emit the configuration properties just enter the configuration PID, select a <a href='https://sling.apache.org/documentation/bundles/configuration-installer-factory.html'>serialization format</a> and click 'Print'");

        tr(pw);
        tdLabel(pw, "PID");
        tdContent(pw);

        pw.printf(
                "<input type='text' name='%s' ' value='%s' class='input' size='120' minlength='3'>",
                PARAMETER_PID, escapeXml(pid));
        pw.println();
        pw.println(
                "<p>For factory configurations use the factory PID followed by a tilde and the configuration name, e.g. 'my.factory.pid~myname'</p>");
        closeTd(pw);
        closeTr(pw);

        tr(pw);

        tdLabel(pw, "Hide Properties");
        tdContent(pw);

        pw.append("<input type='checkbox' name='");
        pw.append(PARAMETER_HIDE_REDUNDANT_PROPERTIES);
        pw.append("'");
        if (hideRedundantProperties) {
            pw.print(" checked");
        }

        pw.append(" id='");
        pw.append(PARAMETER_HIDE_REDUNDANT_PROPERTIES);
        pw.append("' class='input' value='true'>").println();
        pw.append("<label for='");
        pw.append(PARAMETER_HIDE_REDUNDANT_PROPERTIES);
        pw.append("'>");
        pw.append("Redundant Properties (");
        StringBuilder sb = new StringBuilder();
        // these configs come from inherited sources
        Dictionary<String, Object> mergedProperties = ConfigTaskCreator.getDefaultProperties(infoProvider, pid);
        if (mergedProperties == null) {
            mergedProperties = new Hashtable<>();
        }
        if (mergedProperties.size() > 0) {
            sb.append(
                    "from <a href=\"https://sling.apache.org/documentation/bundles/configuration-installer-factory.html#merging-of-configurations\">Merge Schemes</a> ");
            sb.append("\"").append(String.join(", ", Activator.MERGE_SCHEMES)).append("\"");
        }
        final String pidReferencedFromComponentDescription;
        if (configuration != null) {
            pidReferencedFromComponentDescription =
                    configuration.getFactoryPid() != null ? configuration.getFactoryPid() : configuration.getPid();
            Set<ComponentDescriptionDTO> componentDescriptions =
                    allComponentDescriptions.get(pidReferencedFromComponentDescription);
            if (componentDescriptions != null) {
                if (sb.length() > 0) {
                    sb.append(" and ");
                }
                sb.append("from component description(s) of ");
                sb.append(componentDescriptions.stream()
                        .map(componentDescription -> String.format(
                                "<a href=\"components/%d/%s/%s\">component \"%s\" (bundle %d)</a>",
                                componentDescription.bundle.id,
                                componentDescription.name,
                                componentDescription.configurationPid[0],
                                componentDescription.name,
                                componentDescription.bundle.id))
                        .collect(Collectors.joining(", ")));
            }
        } else {
            pidReferencedFromComponentDescription = "";
        }
        if (sb.length() == 0) {
            sb.append("no fallback sources found");
        }
        pw.append(sb.toString()).append(")</label>").println();
        pw.println(
                "<p>Enabling it hides those properties which have the same name and value as any of their fallback sources.</p>");
        closeTd(pw);
        closeTr(pw);

        tr(pw);
        tdLabel(pw, "Serialization Format");
        tdContent(pw);
        pw.print("<select name='");
        pw.print(PARAMETER_FORMAT);
        pw.println("'>");
        option(pw, "JSON", "OSGi Configurator JSON", serializationFormat.name());
        option(pw, "CONFIG", "Apache Felix Config", serializationFormat.name());
        option(pw, "PROPERTIES", "Java Properties", serializationFormat.name());
        option(pw, "PROPERTIES_XML", "Java Properties (XML)", serializationFormat.name());
        pw.println("</select>");

        pw.println("&nbsp;&nbsp;<input type='submit' value='Print' class='submit'>");

        closeTd(pw);
        closeTr(pw);

        if (configuration != null) {
            tr(pw);
            tdLabel(pw, "Serialized Configuration Properties");
            tdContent(pw);

            Dictionary<String, Object> properties = configuration.getProperties();
            if (properties == null) {
                pw.print("<p class='ui-state-error-text'>");
                pw.print("No configuration properties for pid '" + escapeXml(pid) + "' found!");
                pw.println("</p>");
            } else {
                properties = ConfigUtil.cleanConfiguration(properties);
                if (hideRedundantProperties) {
                    removeComponentDefaultProperties(
                            allComponentDescriptions,
                            pidReferencedFromComponentDescription,
                            properties,
                            mergedProperties);
                    ConfigUtil.removeRedundantProperties(properties, mergedProperties);
                }

                try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
                    // always emit in alphabetical order of keys
                    ConfigurationSerializerFactory.create(serializationFormat)
                            .serialize(new SortedDictionary<>(properties), baos);
                    pw.println("<textarea rows=\"20\" cols=\"120\" id=\"output\" readonly>");
                    pw.print(new String(baos.toByteArray(), StandardCharsets.UTF_8));
                    pw.println("</textarea>");
                    pw.println("<button type='button' id='copy'>Copy to Clipboard</a>");
                } catch (Exception e) {
                    pw.print("<p class='ui-state-error-text'>");
                    pw.print("Error serializing pid '" + escapeXml(pid) + "': " + e.getMessage());
                    pw.println("</p>");
                    LOGGER.warn("Error serializing pid '{}'", pid, e);
                }
            }
            closeTd(pw);
            closeTr(pw);
        }
        pw.println("</table>");
        pw.print("</form>");
    }