diff options
Diffstat (limited to 'config-lib/src/main/java/com/yahoo/config/ChangesRequiringRestart.java')
-rw-r--r-- | config-lib/src/main/java/com/yahoo/config/ChangesRequiringRestart.java | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/config-lib/src/main/java/com/yahoo/config/ChangesRequiringRestart.java b/config-lib/src/main/java/com/yahoo/config/ChangesRequiringRestart.java new file mode 100644 index 00000000000..6c17a21c649 --- /dev/null +++ b/config-lib/src/main/java/com/yahoo/config/ChangesRequiringRestart.java @@ -0,0 +1,162 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.config; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import static java.util.stream.Collectors.joining; + +/** + * @author <a href="mailto:magnarn@yahoo-inc.com">Magnar Nedland</a> + * + * This class aggregates information about config changes that causes a restart to be required. + */ +public class ChangesRequiringRestart { + static class ReportLine { + private String name; + private final Node from; + private final Node to; + private final String comment; + + public ReportLine(String name, Node from, Node to, String comment) { + this.name = name; + this.from = from; + this.to = to; + this.comment = comment; + } + + public void addNamePrefix(String prefix) { + if (!name.isEmpty()) { + name = prefix + "." + name; + } else { + name = prefix; + } + } + + private String getCommentAndName(String indent, String namePrefix) { + return indent + (comment.isEmpty()? "" : "# " + comment.replace("\n", "\n" + indent + "# ") + "\n" + indent) + + namePrefix + name; + } + + private static String formatValue(String indent, Node n) { + String str = n.toString(); + if (str.contains("\n")) { // Struct + str = "\n" + indent + " { " + str.replace("\n", "\n" + indent + " ") + " }"; + } + return str; + } + + @Override + public String toString() { + return toString("", ""); + } + + public String toString(String indent, String namePrefix) { + if (from == null) { + return getCommentAndName(indent, namePrefix) + " was added with value " + formatValue(indent, to); + } else if (to == null) { + return getCommentAndName(indent, namePrefix) + " with value " + formatValue(indent, from) + " was removed"; + } + return getCommentAndName(indent, namePrefix) + " has changed from " + formatValue(indent, from) + " to " + formatValue(indent, to); + } + } + + private ArrayList<ReportLine> report = new ArrayList<>(); + private String componentName; + + public ChangesRequiringRestart(String componentName) { + this.componentName = componentName; + } + + public String getName() { + return componentName; + } + + public ChangesRequiringRestart compare(Node from, Node to, String name, String comment) { + if (!from.equals(to)) { + report.add(new ReportLine(name, from, to, comment)); + } + return this; + } + + public void mergeChanges(String prefix, ChangesRequiringRestart childReport) { + for (ReportLine line : childReport.getReportLines()) { + line.addNamePrefix(prefix); + report.add(line); + } + } + + /** + * Interface used to pass lambda functions from generated code to compareArray/-Map functions. + */ + public interface CompareFunc { + // Generates a report based on a config change. + ChangesRequiringRestart getChangesRequiringRestart(Node from, Node to); + } + + public ChangesRequiringRestart compareArray(List<? extends Node> from, + List<? extends Node> to, + String name, + String comment, + CompareFunc func) { + if (!from.equals(to)) { + int commonElements = Math.min(from.size(), to.size()); + for (int i = 0; i < commonElements; ++i) { + ChangesRequiringRestart childReport = func.getChangesRequiringRestart(from.get(i), to.get(i)); + String prefix = childReport.componentName + "[" + Integer.toString(i) + "]"; + mergeChanges(prefix, childReport); + } + for (int i = commonElements; i < from.size(); ++i) { + report.add(new ReportLine(name + "[" + Integer.toString(i) + "]", from.get(i), null, comment)); + } + for (int i = commonElements; i < to.size(); ++i) { + report.add(new ReportLine(name + "[" + Integer.toString(i) + "]", null, to.get(i), comment)); + } + } + return this; + } + + public ChangesRequiringRestart compareMap(Map<String, ? extends Node> from, + Map<String, ? extends Node> to, + String name, + String comment, + CompareFunc func) { + if (!from.equals(to)) { + for (String key : from.keySet()) { + if (to.containsKey(key)) { + ChangesRequiringRestart childReport = func.getChangesRequiringRestart(from.get(key), to.get(key)); + String prefix = childReport.componentName + "{" + key + "}"; + mergeChanges(prefix, childReport); + } else { + report.add(new ReportLine(name + "{" + key + "}", from.get(key), null, comment)); + } + } + for (String key : to.keySet()) { + if (!from.containsKey(key)) { + report.add(new ReportLine(name + "{" + key + "}", null, to.get(key), comment)); + } + } + } + return this; + } + + List<ReportLine> getReportLines() { + return report; + } + + @Override + public String toString() { + return toString(""); + } + + public String toString(String indent) { + return report.stream() + .map(line -> line.toString(indent, componentName + ".")) + .collect(joining("\n")); + } + + public boolean needsRestart() { + return !report.isEmpty(); + } +} |