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(" <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>");
}