From 2a1ef08ab314866268c69edaf8235f6aa635bfcb Mon Sep 17 00:00:00 2001 From: Jon Bratseth Date: Sun, 29 Nov 2020 13:39:48 +0100 Subject: Revert "Merge pull request #15510 from vespa-engine/revert-15508-bratseth/apply-on-restart-take-3" This reverts commit 3c95d11418e3ebffc1260207932b7e8f3955e1a0, reversing changes made to 7a1a70055770a82bf42bff668abaf011af3f6e55. --- config-lib/abi-spec.json | 6 +- config-lib/pom.xml | 31 ++++++ .../main/java/com/yahoo/config/ConfigBuilder.java | 1 - .../main/java/com/yahoo/config/ConfigInstance.java | 107 +++++++++++++++++++++ .../src/main/java/com/yahoo/config/Node.java | 4 +- 5 files changed, 145 insertions(+), 4 deletions(-) (limited to 'config-lib') diff --git a/config-lib/abi-spec.json b/config-lib/abi-spec.json index fa352d8f6bd..a9c57c2d1a2 100644 --- a/config-lib/abi-spec.json +++ b/config-lib/abi-spec.json @@ -73,7 +73,11 @@ "public abstract boolean dispatchGetConfig(com.yahoo.config.ConfigInstance$Producer)", "public abstract java.lang.String getDefName()", "public abstract java.lang.String getDefNamespace()", - "public abstract java.lang.String getDefMd5()" + "public abstract java.lang.String getDefMd5()", + "public boolean getApplyOnRestart()", + "public void setApplyOnRestart(boolean)", + "public com.yahoo.config.ConfigInstance buildInstance(com.yahoo.config.codegen.InnerCNode)", + "public static void applyDef(com.yahoo.config.ConfigBuilder, com.yahoo.config.codegen.InnerCNode)" ], "fields": [] }, diff --git a/config-lib/pom.xml b/config-lib/pom.xml index 1002d43bc37..c9eceb10812 100644 --- a/config-lib/pom.xml +++ b/config-lib/pom.xml @@ -26,6 +26,12 @@ annotations ${project.version} + + com.yahoo.vespa + configgen + ${project.version} + provided + @@ -68,6 +74,31 @@ com.yahoo.vespa abi-check-plugin + + org.apache.maven.plugins + maven-shade-plugin + + ${project.artifactId}-jar-with-dependencies + + + + ${project.artifactId} + + com.yahoo.config.codegen + + + + + + + + package + + shade + + + + diff --git a/config-lib/src/main/java/com/yahoo/config/ConfigBuilder.java b/config-lib/src/main/java/com/yahoo/config/ConfigBuilder.java index e35e6916849..30bef223045 100644 --- a/config-lib/src/main/java/com/yahoo/config/ConfigBuilder.java +++ b/config-lib/src/main/java/com/yahoo/config/ConfigBuilder.java @@ -5,7 +5,6 @@ package com.yahoo.config; * Root interface for all config builders. * * @author gjoranv - * @since 5.1.6 */ public interface ConfigBuilder { } diff --git a/config-lib/src/main/java/com/yahoo/config/ConfigInstance.java b/config-lib/src/main/java/com/yahoo/config/ConfigInstance.java index 04405839a9b..b47bd17a5ba 100644 --- a/config-lib/src/main/java/com/yahoo/config/ConfigInstance.java +++ b/config-lib/src/main/java/com/yahoo/config/ConfigInstance.java @@ -1,9 +1,16 @@ // Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.config; +import java.lang.reflect.Field; +import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.logging.Level; + +import com.yahoo.config.codegen.CNode; +import com.yahoo.config.codegen.InnerCNode; +import com.yahoo.config.codegen.LeafCNode; /** * Represents an instance of an application config with a specific configId. @@ -13,10 +20,13 @@ import java.util.Map; */ public abstract class ConfigInstance extends InnerNode { + private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(ConfigInstance.class.getName()); + public interface Builder extends ConfigBuilder { /** * Dispatches a getConfig() call if this instance's producer is of the right type + * * @param producer a config producer * @return true if this instance's producer was the correct type, and hence a getConfig call was dispatched */ @@ -26,6 +36,103 @@ public abstract class ConfigInstance extends InnerNode { String getDefNamespace(); String getDefMd5(); + /** Returns true if this instance should be applied on restart, false if it should be applied immediately */ + default boolean getApplyOnRestart() { return false; } + + default void setApplyOnRestart(boolean applyOnRestart) { throw new java.lang.UnsupportedOperationException(); } + + default ConfigInstance buildInstance(InnerCNode targetDef) { + try { + if (targetDef != null) applyDef(this, targetDef); + Class clazz = getConfigClass(getClass()); + return clazz.getConstructor(getClass()).newInstance(this); + } catch (Exception e) { + throw new ConfigurationRuntimeException(e); + } + } + + /** + * If some fields on the builder are null now, set them from the def. Do recursively. + *

+ * If the targetDef has some schema incompatibilities, they are not handled here + * (except logging in some cases), but in ConfigInstance.serialize(). + * + * @param builder a {@link com.yahoo.config.ConfigBuilder} + * @param targetDef a config definition + * @throws Exception if applying values form config definitions fails + */ + static void applyDef(ConfigBuilder builder, InnerCNode targetDef) throws Exception { + for (Map.Entry e: targetDef.children().entrySet()) { + CNode node = e.getValue(); + if (node instanceof LeafCNode) { + setLeafValueIfUnset(targetDef, builder, (LeafCNode)node); + } else if (node instanceof InnerCNode) { + // Is there a private field on the builder that matches this inner node in the def? + if (hasField(builder.getClass(), node.getName())) { + Field innerField = builder.getClass().getDeclaredField(node.getName()); + innerField.setAccessible(true); + Object innerFieldVal = innerField.get(builder); + if (innerFieldVal instanceof List) { + // inner array? Check that list elems are ConfigBuilder + List innerList = (List) innerFieldVal; + for (Object b : innerList) { + if (b instanceof ConfigBuilder) { + applyDef((ConfigBuilder) b, (InnerCNode) node); + } + } + } else if (innerFieldVal instanceof ConfigBuilder) { + // Struct perhaps + applyDef((ConfigBuilder) innerFieldVal, (InnerCNode) node); + } else { + // Likely a config value mismatch. That is handled in ConfigInstance.serialize() (error message, omit from response.) + } + } + } + } + } + + private static boolean hasField(Class aClass, String name) { + for (Field field : aClass.getDeclaredFields()) { + if (name.equals(field.getName())) { + return true; + } + } + return false; + } + + private static void setLeafValueIfUnset(InnerCNode targetDef, Object builder, LeafCNode node) throws Exception { + if (hasField(builder.getClass(), node.getName())) { + Field field = builder.getClass().getDeclaredField(node.getName()); + field.setAccessible(true); + Object val = field.get(builder); + if (val==null) { + // Not set on builder, if the leaf node has a default value, try the private setter that takes String + try { + if (node.getDefaultValue()!=null) { + Method setter = builder.getClass().getDeclaredMethod(node.getName(), String.class); + setter.setAccessible(true); + setter.invoke(builder, node.getDefaultValue().getValue()); + } + } catch (Exception e) { + log.log(Level.SEVERE, + "For config '" + targetDef.getFullName() + "': " + + "Unable to apply the default value for field '" + node.getName() + + "' to config Builder (where it wasn't set)", + e); + } + } + } + } + + @SuppressWarnings("unchecked") + private static Class getConfigClass(Class builderClass) { + Class configClass = builderClass.getEnclosingClass(); + if (configClass == null || ! ConfigInstance.class.isAssignableFrom(configClass)) { + throw new ConfigurationRuntimeException("Builder class " + builderClass + " has enclosing class " + configClass + ", which is not a ConfigInstance"); + } + return (Class) configClass; + } + } public interface Producer {} diff --git a/config-lib/src/main/java/com/yahoo/config/Node.java b/config-lib/src/main/java/com/yahoo/config/Node.java index 8d16b9727c1..ed11bdc9891 100644 --- a/config-lib/src/main/java/com/yahoo/config/Node.java +++ b/config-lib/src/main/java/com/yahoo/config/Node.java @@ -5,7 +5,6 @@ package com.yahoo.config; * The Node class is superclass for all nodes in a {@link * ConfigInstance}. Important subclasses of this node are {@link * InnerNode} and {@link LeafNode}. - * */ public abstract class Node { @@ -13,7 +12,7 @@ public abstract class Node { * Postinitialize this node. Any node needing to process its values depending on the config * id should override this method. * - * @param configId the configId of the ConfigInstance that owns (or is) this node + * @param configId the configId of the ConfigInstance that owns (or is) this node */ public void postInitialize(String configId) { return; } @@ -26,4 +25,5 @@ public abstract class Node { protected Object clone() throws CloneNotSupportedException { return super.clone(); } + } -- cgit v1.2.3