diff options
author | Jon Bratseth <bratseth@gmail.com> | 2022-09-01 15:56:28 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-09-01 15:56:28 +0200 |
commit | 96d24924eed043c9d8df7694375828745889faa2 (patch) | |
tree | 5810bbe78d7beccdbe5751df1c88d6b8680d093e /config | |
parent | a5a7789218d9fb5a569eb8f3feec6747f9ec2ca3 (diff) | |
parent | 38bfeeadafabeeef540157e440224b03ba80ed4d (diff) |
Merge pull request #23878 from vespa-engine/bratseth/moodel-config
Bratseth/model config
Diffstat (limited to 'config')
7 files changed, 194 insertions, 190 deletions
diff --git a/config/src/main/java/com/yahoo/vespa/config/ConfigDefinition.java b/config/src/main/java/com/yahoo/vespa/config/ConfigDefinition.java index 96046e64c1a..9d9e43de130 100644 --- a/config/src/main/java/com/yahoo/vespa/config/ConfigDefinition.java +++ b/config/src/main/java/com/yahoo/vespa/config/ConfigDefinition.java @@ -28,7 +28,7 @@ public class ConfigDefinition { private final String namespace; ConfigDefinition parent = null; - // TODO Strings without default are null, could be not OK. + // TODO: Strings without default are null, could be not OK. private final Map<String, StringDef> stringDefs = new LinkedHashMap<>(); private final Map<String, BoolDef> boolDefs = new LinkedHashMap<>(); private final Map<String, IntDef> intDefs = new LinkedHashMap<>(); @@ -39,6 +39,7 @@ public class ConfigDefinition { private final Map<String, FileDef> fileDefs = new LinkedHashMap<>(); private final Map<String, PathDef> pathDefs = new LinkedHashMap<>(); private final Map<String, UrlDef> urlDefs = new LinkedHashMap<>(); + private final Map<String, ModelDef> modelDefs = new LinkedHashMap<>(); private final Map<String, StructDef> structDefs = new LinkedHashMap<>(); private final Map<String, InnerArrayDef> innerArrayDefs = new LinkedHashMap<>(); private final Map<String, ArrayDef> arrayDefs = new LinkedHashMap<>(); @@ -99,6 +100,8 @@ public class ConfigDefinition { verifyPath(id); } else if (urlDefs.containsKey(id)) { verifyUrl(id); + } else if (modelDefs.containsKey(id)) { + verifyModel(id); } else if (boolDefs.containsKey(id)) { verifyBool(id, val); } else if (intDefs.containsKey(id)) { @@ -550,6 +553,11 @@ public class ConfigDefinition { } } + /** A value which may be either an url or a path. */ + public static class ModelDef { + + } + public void addEnumDef(String id, EnumDef def) { enumDefs.put(id, def); } @@ -655,6 +663,10 @@ public class ConfigDefinition { urlDefs.put(url, new UrlDef(defVal)); } + public void addModelDef(String modelName) { + modelDefs.put(modelName, new ModelDef()); + } + public void addUrlDef(String url) { urlDefs.put(url, new UrlDef(null)); } @@ -689,6 +701,10 @@ public class ConfigDefinition { public Map<String, PathDef> getPathDefs() { return pathDefs; } + public Map<String, UrlDef> getUrlDefs() { return urlDefs; } + + public Map<String, ModelDef> getModelDefs() { return modelDefs; } + public Map<String, InnerArrayDef> getInnerArrayDefs() { return innerArrayDefs; } @@ -857,6 +873,11 @@ public class ConfigDefinition { throw new IllegalArgumentException("No such url in " + verifyWarning(id)); } + private void verifyModel(String field) { + if ( ! modelDefs.containsKey(field)) + throw new IllegalArgumentException("No such model in " + verifyWarning(field)); + } + private void verifyBool(String id) { if ( ! boolDefs.containsKey(id)) throw new IllegalArgumentException("No such bool in " + verifyWarning(id)); diff --git a/config/src/main/java/com/yahoo/vespa/config/ConfigDefinitionBuilder.java b/config/src/main/java/com/yahoo/vespa/config/ConfigDefinitionBuilder.java index f6493c3514e..da5048a99e8 100644 --- a/config/src/main/java/com/yahoo/vespa/config/ConfigDefinitionBuilder.java +++ b/config/src/main/java/com/yahoo/vespa/config/ConfigDefinitionBuilder.java @@ -69,41 +69,37 @@ public class ConfigDefinitionBuilder { addNode(def, (LeafCNode.PathLeaf) node); } else if (node instanceof LeafCNode.UrlLeaf) { addNode(def, (LeafCNode.UrlLeaf) node); + } else if (node instanceof LeafCNode.ModelLeaf) { + addNode(def, (LeafCNode.ModelLeaf) node); } else if (node instanceof LeafCNode.StringLeaf) { addNode(def, (LeafCNode.StringLeaf) node); } else if (node instanceof LeafCNode.EnumLeaf) { addNode(def, (LeafCNode.EnumLeaf) node); } else { - System.err.println("Unknown node type for node with name " + name); + System.err.println("Unknown node type for node with name '" + name + "'"); } } } else { ConfigDefinition newDef; if (node.isArray) { if (node.getChildren() != null && node.getChildren().length > 0) { - //System.out.println("\tAdding inner array node " + name); newDef = def.innerArrayDef(name); for (CNode childNode : node.getChildren()) { - //System.out.println("\tChild node " + childNode.getName()); addNode(newDef, childNode); } } } else if (node.isMap) { - //System.out.println("Adding struct map node " + name); newDef = def.structMapDef(name); if (node.getChildren() != null && node.getChildren().length > 0) { for (CNode childNode : node.getChildren()) { - //System.out.println("\tChild node " + childNode.getName()); addNode(newDef, childNode); } } } else { - //System.out.println("Adding struct node " + name); newDef = def.structDef(name); if (node.getChildren() != null && node.getChildren().length > 0) { for (CNode childNode : node.getChildren()) { - //System.out.println("\tChild node " + childNode.getName()); addNode(newDef, childNode); } } @@ -184,6 +180,10 @@ public class ConfigDefinitionBuilder { } } + private static void addNode(ConfigDefinition def, LeafCNode.ModelLeaf leaf) { + def.addModelDef(leaf.getName()); + } + private static void addNode(ConfigDefinition def, LeafCNode.EnumLeaf leaf) { if (leaf.getDefaultValue() != null) { def.addEnumDef(leaf.getName(), Arrays.asList(leaf.getLegalValues()), leaf.getDefaultValue().getValue()); @@ -202,4 +202,5 @@ public class ConfigDefinitionBuilder { sb.delete(length - 2, length); return sb.toString(); } + } diff --git a/config/src/main/java/com/yahoo/vespa/config/ConfigPayloadApplier.java b/config/src/main/java/com/yahoo/vespa/config/ConfigPayloadApplier.java index 5c0e9539f4f..259a5ef9e6b 100644 --- a/config/src/main/java/com/yahoo/vespa/config/ConfigPayloadApplier.java +++ b/config/src/main/java/com/yahoo/vespa/config/ConfigPayloadApplier.java @@ -4,13 +4,12 @@ package com.yahoo.vespa.config; import com.yahoo.config.ConfigBuilder; import com.yahoo.config.ConfigInstance; import com.yahoo.config.FileReference; +import com.yahoo.config.ModelReference; import com.yahoo.config.UrlReference; import com.yahoo.slime.ArrayTraverser; import com.yahoo.slime.Inspector; import com.yahoo.slime.ObjectTraverser; import com.yahoo.slime.Type; -import com.yahoo.text.Utf8; -import com.yahoo.yolean.Exceptions; import java.io.File; import java.lang.reflect.Constructor; @@ -22,12 +21,11 @@ import java.nio.file.Path; import java.util.HashMap; import java.util.HashSet; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.Stack; import java.util.logging.Logger; -import static java.util.logging.Level.FINE; -import static java.util.logging.Level.FINEST; import static java.util.logging.Level.INFO; /** @@ -35,7 +33,9 @@ import static java.util.logging.Level.INFO; * * TODO: This can be refactored a lot, since many of the reflection methods are duplicated * - * @author Ulf Lilleengen, hmusum, Tony Vaagenes + * @author Ulf Lilleengen + * @author hmusum + * @author Tony Vaagenes */ public class ConfigPayloadApplier<T extends ConfigInstance.Builder> { @@ -54,7 +54,6 @@ public class ConfigPayloadApplier<T extends ConfigInstance.Builder> { this.rootBuilder = builder; this.pathAcquirer = pathAcquirer; this.urlDownloader = urlDownloader; - debug("rootBuilder=" + rootBuilder); } public void applyPayload(ConfigPayload payload) { @@ -62,8 +61,7 @@ public class ConfigPayloadApplier<T extends ConfigInstance.Builder> { try { handleValue(payload.getSlime().get()); } catch (Exception e) { - throw new RuntimeException("Not able to create config builder for payload:" + payload.toString() + - ", " + Exceptions.toMessageString(e), e); + throw new RuntimeException("Not able to create config builder for payload '" + payload.toString() + "'", e); } } @@ -89,27 +87,19 @@ public class ConfigPayloadApplier<T extends ConfigInstance.Builder> { } private void handleARRAY(Inspector inspector) { - trace("Array"); - inspector.traverse(new ArrayTraverser() { - @Override - public void entry(int idx, Inspector inspector) { - handleArrayEntry(idx, inspector); - } - }); + inspector.traverse((ArrayTraverser)(int index, Inspector value) -> handleArrayEntry(index, value)); } private void handleArrayEntry(int idx, Inspector inspector) { try { - trace("entry, idx=" + idx); - trace("top of stack=" + stack.peek().toString()); String name = stack.peek().nameStack().peek(); - if (inspector.type().equals(Type.OBJECT)) { + if (inspector.type() == Type.OBJECT) { NamedBuilder builder = createBuilder(stack.peek(), name); if (builder == null) return; // Ignore non-existent struct array class stack.push(builder); } handleValue(inspector); - if (inspector.type().equals(Type.OBJECT)) { + if (inspector.type() == Type.OBJECT) { stack.peek().nameStack().pop(); } } catch (Exception e) { @@ -118,37 +108,24 @@ public class ConfigPayloadApplier<T extends ConfigInstance.Builder> { } private void handleOBJECT(Inspector inspector) { - trace("Object"); - printStack(); - - inspector.traverse(new ObjectTraverser() { - @Override - public void field(String name, Inspector inspector) { - handleObjectEntry(name, inspector); - } - }); - - trace("Should pop a builder from stack"); + inspector.traverse((String name, Inspector value) -> handleObjectEntry(name, value)); NamedBuilder builder = stack.pop(); - printStack(); // Need to set e.g struct(Struct.Builder) here - if (!stack.empty()) { - trace("builder= " + builder); + if ( ! stack.empty()) { try { invokeSetter(stack.peek().builder, builder.peekName(), builder.builder); } catch (Exception e) { throw new RuntimeException("Could not set '" + builder.peekName() + - "' for value '" + builder.builder() + "'", e); + "' for value '" + builder.builder() + "'", e); } } } private void handleObjectEntry(String name, Inspector inspector) { try { - trace("field, name=" + name); NamedBuilder parentBuilder = stack.peek(); - if (inspector.type().equals(Type.OBJECT)) { + if (inspector.type() == Type.OBJECT) { if (isMapField(parentBuilder, name)) { parentBuilder.nameStack().push(name); handleMap(inspector); @@ -159,9 +136,8 @@ public class ConfigPayloadApplier<T extends ConfigInstance.Builder> { if (builder == null) return; // Ignore non-existent struct class stack.push(builder); } - } else if (inspector.type().equals(Type.ARRAY)) { + } else if (inspector.type() == Type.ARRAY) { for (int i = 0; i < inspector.children(); i++) { - trace("Pushing " + name); parentBuilder.nameStack().push(name); } } else { // leaf @@ -174,19 +150,11 @@ public class ConfigPayloadApplier<T extends ConfigInstance.Builder> { } private void handleMap(Inspector inspector) { - inspector.traverse(new ObjectTraverser() { - @Override - public void field(String name, Inspector inspector) { - switch (inspector.type()) { - case OBJECT: - handleInnerMap(name, inspector); - break; - case ARRAY: - throw new IllegalArgumentException("Never herd of array inside maps before"); - default: - setMapLeafValue(name, getValueFromInspector(inspector)); - break; - } + inspector.traverse((String name, Inspector value) -> { + switch (value.type()) { + case OBJECT -> handleInnerMap(name, value); + case ARRAY -> throw new IllegalArgumentException("Never heard of array inside maps before"); + default -> setMapLeafValue(name, value); } }); } @@ -197,12 +165,7 @@ public class ConfigPayloadApplier<T extends ConfigInstance.Builder> { throw new RuntimeException("Missing map builder (this should never happen): " + stack.peek()); setMapLeafValue(name, builder.builder()); stack.push(builder); - inspector.traverse(new ObjectTraverser() { - @Override - public void field(String name, Inspector inspector) { - handleObjectEntry(name, inspector); - } - }); + inspector.traverse((ObjectTraverser) (key, value) -> handleObjectEntry(key, value)); stack.pop(); } @@ -210,21 +173,8 @@ public class ConfigPayloadApplier<T extends ConfigInstance.Builder> { NamedBuilder parent = stack.peek(); ConfigBuilder builder = parent.builder(); String methodName = parent.peekName(); - //trace("class to obtain method from: " + builder.getClass().getName()); try { - // Need to convert reference into actual path if 'path' type is used - if (isPathField(builder, methodName)) { - FileReference wrappedPath = resolvePath((String)value); - invokeSetter(builder, methodName, key, wrappedPath); - - // Need to convert url into actual file if 'url' type is used - } else if (isUrlField(builder, methodName)) { - UrlReference url = resolveUrl((String)value); - invokeSetter(builder, methodName, key, url); - - } else { - invokeSetter(builder, methodName, key, value); - } + invokeSetter(builder, methodName, key, resolveValue(builder, methodName, value)); } catch (InvocationTargetException | IllegalAccessException e) { throw new RuntimeException("Name: " + methodName + ", value '" + value + "'", e); } catch (NoSuchMethodException e) { @@ -246,46 +196,20 @@ public class ConfigPayloadApplier<T extends ConfigInstance.Builder> { Object builder = parentBuilder.builder(); Object newBuilder = getBuilderForStruct(name, builder.getClass().getDeclaringClass()); if (newBuilder == null) return null; - trace("New builder for " + name + "=" + newBuilder); - trace("Pushing builder for " + name + "=" + newBuilder + " onto stack"); return new NamedBuilder((ConfigBuilder) newBuilder, name); } private void handleLeafValue(Inspector value) { - trace("String "); - printStack(); NamedBuilder peek = stack.peek(); - trace("popping name stack"); String name = peek.nameStack().pop(); - printStack(); ConfigBuilder builder = peek.builder(); - trace("name=" + name + ",builder=" + builder + ",value=" + value.toString()); setValueForLeafNode(builder, name, value); } // Sets values for leaf nodes (uses private accessors that take string as argument) private void setValueForLeafNode(Object builder, String methodName, Inspector value) { try { - // Need to convert reference into actual path if 'path' type is used - if (isPathField(builder, methodName)) { - FileReference wrappedPath = resolvePath(Utf8.toString(value.asUtf8())); - invokeSetter(builder, methodName, wrappedPath); - - // Need to convert url into actual file if 'url' type is used - } else if (isUrlField(builder, methodName)) { - String url = Utf8.toString(value.asUtf8()); - if (url == null || url.length() == 0) { - invokeSetter(builder, methodName, ""); - } else { - UrlReference urlref = resolveUrl(Utf8.toString(value.asUtf8())); - invokeSetter(builder, methodName, urlref); - } - - - } else { - Object object = getValueFromInspector(value); - invokeSetter(builder, methodName, object); - } + invokeSetter(builder, methodName, resolveValue(builder, methodName, value)); } catch (InvocationTargetException | IllegalAccessException e) { throw new RuntimeException("Name: " + methodName + ", value '" + value + "'", e); } catch (NoSuchMethodException e) { @@ -293,27 +217,44 @@ public class ConfigPayloadApplier<T extends ConfigInstance.Builder> { } } + private Object resolveValue(Object builder, String methodName, Object rawValue) { + if (rawValue instanceof ConfigBuilder) // Value in a map + return rawValue; + Inspector value = (Inspector)rawValue; + if (isPathField(builder, methodName)) + return resolvePath(value.asString()); + else if (isUrlField(builder, methodName)) + return value.asString().isEmpty() ? "" : resolveUrl(value.asString()); + else if (isModelField(builder, methodName)) + return value.asString().isEmpty() ? "" : resolveModel(value.asString()); + else + return getValueFromInspector(value); + } + private FileReference resolvePath(String value) { - Path path = pathAcquirer.getPath(newFileReference(value)); - return newFileReference(path.toString()); + Path path = pathAcquirer.getPath(new FileReference(value)); + return new FileReference(path.toString()); } private UrlReference resolveUrl(String url) { - if (urlDownloader == null) { - return new UrlReference(url); // assuming config server - just return the actual url. - } + if (! canResolveUrls()) // assuming config server - keep the url + return new UrlReference(url); File file = urlDownloader.waitFor(new UrlReference(url), 60 * 60); return new UrlReference(file.getAbsolutePath()); } - private FileReference newFileReference(String fileReference) { - try { - Constructor<FileReference> constructor = FileReference.class.getDeclaredConstructor(String.class); - constructor.setAccessible(true); - return constructor.newInstance(fileReference); - } catch (Exception e) { - throw new RuntimeException("Failed invoking FileReference constructor.", e); - } + private boolean canResolveUrls() { + return urlDownloader != null && urlDownloader.isValid(); + } + + private ModelReference resolveModel(String modelStringValue) { + var model = ModelReference.valueOf(modelStringValue); + // Resolve any of url and path present, in priority order + if (model.url().isPresent() && canResolveUrls()) + model = model.withUrl(Optional.of(resolveUrl(model.url().get().value()))); + else if (model.path().isPresent()) + model = model.withPath(Optional.of(resolvePath(model.path().get().value()))); + return model; } private final Map<String, Method> methodCache = new HashMap<>(); @@ -335,7 +276,6 @@ public class ConfigPayloadApplier<T extends ConfigInstance.Builder> { } Method method = builder.getClass().getDeclaredMethod(methodName, parameterTypes); method.setAccessible(true); - trace("method=" + method + ",params=" + params); return method; } @@ -353,7 +293,7 @@ public class ConfigPayloadApplier<T extends ConfigInstance.Builder> { private Object getValueFromInspector(Inspector inspector) { switch (inspector.type()) { case STRING: - return Utf8.toString(inspector.asUtf8()); + return inspector.asString(); case LONG: return String.valueOf(inspector.asLong()); case DOUBLE: @@ -385,6 +325,12 @@ public class ConfigPayloadApplier<T extends ConfigInstance.Builder> { return isFieldType(urlFieldSet, builder, methodName, UrlReference.class); } + private final Set<String> modelFieldSet = new HashSet<>(); + private boolean isModelField(Object builder, String methodName) { + // Models are stored as ModelReference in Builder. + return isFieldType(modelFieldSet, builder, methodName, ModelReference.class); + } + private boolean isFieldType(Set<String> fieldSet, Object builder, String methodName, java.lang.reflect.Type type) { String key = fieldKey(builder, methodName); if (fieldSet.contains(key)) { @@ -419,14 +365,11 @@ public class ConfigPayloadApplier<T extends ConfigInstance.Builder> { } private String capitalize(String name) { - StringBuilder sb = new StringBuilder(); - sb.append(name.substring(0, 1).toUpperCase()).append(name.substring(1)); - return sb.toString(); + return name.substring(0, 1).toUpperCase() + name.substring(1); } private Constructor<?> lookupBuilderForStruct(String structName, String name, Class<?> currentClass) { - final String currentClassName = currentClass.getName(); - trace("structName=" + structName + ", name=" + name + ",current class=" + currentClassName); + String currentClassName = currentClass.getName(); Class<?> structClass = getInnerClass(currentClass, currentClassName + "$" + structName); if (structClass == null) { log.info("Could not find nested class '" + currentClassName + "$" + structName + @@ -449,17 +392,16 @@ public class ConfigPayloadApplier<T extends ConfigInstance.Builder> { } /** - * Finds a nested class with the given <code>name</code>name in <code>clazz</code> + * Finds a nested class with the given <code>name</code>name in <code>clazz</code>. + * * @param clazz a Class * @param name a name * @return class found, or null if no class is found */ private Class<?> getInnerClass(Class<?> clazz, String name) { for (Class<?> cls : clazz.getDeclaredClasses()) { - if (cls.getName().equals(name)) { - trace("Found class " + cls.getName()); + if (cls.getName().equals(name)) return cls; - } } return null; } @@ -472,37 +414,24 @@ public class ConfigPayloadApplier<T extends ConfigInstance.Builder> { private Object getBuilderForStruct(String name, Class<?> currentClass) { String structName = capitalize(name); String key = constructorCacheKey(structName, name, currentClass); - Constructor<?> ctor = constructorCache.get(key); - if (ctor == null) { - ctor = lookupBuilderForStruct(structName, name, currentClass); - if (ctor == null) return null; - constructorCache.put(key, ctor); + Constructor<?> constructor = constructorCache.get(key); + if (constructor == null) { + constructor = lookupBuilderForStruct(structName, name, currentClass); + if (constructor == null) return null; + constructorCache.put(key, constructor); } - Object builder; try { - builder = ctor.newInstance(); + return constructor.newInstance(); } catch (Exception e) { - throw new RuntimeException("Could not create class '" + "'" + ctor.getDeclaringClass().getName() + "'"); + throw new RuntimeException("Could not create class '" + "'" + constructor.getDeclaringClass().getName() + "'"); } - return builder; - } - - private void debug(String message) { - log.log(FINE, () -> message); - } - - private void trace(String message) { - log.log(FINEST, () -> message); - } - - private void printStack() { - trace("stack=" + stack.toString()); } /** * A class that holds a builder and a stack of names */ private static class NamedBuilder { + private final ConfigBuilder builder; private final Stack<String> names = new Stack<>(); // if empty, the builder is the root builder @@ -529,9 +458,7 @@ public class ConfigPayloadApplier<T extends ConfigInstance.Builder> { @Override public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append(builder() == null ? "null" : builder.toString()).append(" names=").append(names); - return sb.toString(); + return builder() == null ? "null" : builder.toString() + " names=" + names; } } diff --git a/config/src/main/java/com/yahoo/vespa/config/ConfigPayloadBuilder.java b/config/src/main/java/com/yahoo/vespa/config/ConfigPayloadBuilder.java index 48cdbe36745..74ee29f08ed 100644 --- a/config/src/main/java/com/yahoo/vespa/config/ConfigPayloadBuilder.java +++ b/config/src/main/java/com/yahoo/vespa/config/ConfigPayloadBuilder.java @@ -1,16 +1,21 @@ // Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.config; -import com.yahoo.slime.*; +import com.yahoo.slime.ArrayTraverser; +import com.yahoo.slime.Cursor; +import com.yahoo.slime.Inspector; +import com.yahoo.slime.ObjectTraverser; +import com.yahoo.slime.Slime; -import java.util.*; +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.Map; /** * Helper class for building Slime config payloads, while supporting referring to payloads with their indices. The * builder does not care about config field types. This is resolved by the actual config type consumer created * from the Slime tree. * - * TODO: Add toString * @author Ulf Lilleengen */ public class ConfigPayloadBuilder { @@ -33,9 +38,9 @@ public class ConfigPayloadBuilder { } /** - * Construct a payload builder with a leaf value + * Construct a payload builder with a leaf value. * - * @param value The value of this leaf. + * @param value the value of this leaf */ private ConfigPayloadBuilder(String value) { this(null, value); @@ -172,11 +177,9 @@ public class ConfigPayloadBuilder { /** * Get the value of this field, if any. * - * @return value of field, null if this is not a leaf. + * @return value of field, null if this is not a leaf */ - public String getValue() { - return value; - } + public String getValue() { return value; } public void setValue(String value) { this.value = value; @@ -209,6 +212,7 @@ public class ConfigPayloadBuilder { } public class MapBuilder { + private final Map<String, ConfigPayloadBuilder> elements = new LinkedHashMap<>(); private final ConfigDefinition configDefinition; private final String name; @@ -268,6 +272,11 @@ public class ConfigPayloadBuilder { INDEX, APPEND } + @Override + public String toString() { + return "config builder of " + getConfigDefinition(); + } + /** * Representation of a config array, which supports both INDEX and APPEND modes. */ @@ -450,26 +459,12 @@ public class ConfigPayloadBuilder { private static void decode(Slime slime, String name, Inspector inspector, ConfigPayloadBuilder builder) { switch (inspector.type()) { - case STRING: - builder.setField(name, inspector.asString()); - break; - case LONG: - builder.setField(name, String.valueOf(inspector.asLong())); - break; - case DOUBLE: - builder.setField(name, String.valueOf(inspector.asDouble())); - break; - case BOOL: - builder.setField(name, String.valueOf(inspector.asBool())); - break; - case OBJECT: - ConfigPayloadBuilder objectBuilder = builder.getObject(name); - decodeObject(slime, objectBuilder, inspector); - break; - case ARRAY: - ConfigPayloadBuilder.Array array = builder.getArray(name); - decodeArray(slime, array, inspector); - break; + case STRING -> builder.setField(name, inspector.asString()); + case LONG -> builder.setField(name, String.valueOf(inspector.asLong())); + case DOUBLE -> builder.setField(name, String.valueOf(inspector.asDouble())); + case BOOL -> builder.setField(name, String.valueOf(inspector.asBool())); + case OBJECT -> decodeObject(slime, builder.getObject(name), inspector); + case ARRAY -> decodeArray(slime, builder.getArray(name), inspector); } } @@ -479,8 +474,10 @@ public class ConfigPayloadBuilder { } private static class BuilderObjectTraverser implements ObjectTraverser { + private final ConfigPayloadBuilder builder; private final Slime slime; + public BuilderObjectTraverser(Slime slime, ConfigPayloadBuilder builder) { this.slime = slime; this.builder = builder; @@ -490,11 +487,14 @@ public class ConfigPayloadBuilder { public void field(String name, Inspector inspector) { decode(slime, name, inspector, builder); } + } private static class BuilderArrayTraverser implements ArrayTraverser { + private final Array array; private final Slime slime; + public BuilderArrayTraverser(Slime slime, Array array) { this.array = array; this.slime = slime; @@ -503,14 +503,13 @@ public class ConfigPayloadBuilder { @Override public void entry(int idx, Inspector inspector) { switch (inspector.type()) { - case STRING: - array.append(inspector.asString()); - break; - case OBJECT: - decodeObject(slime, array.append(), inspector); - break; + case STRING -> array.append(inspector.asString()); + case OBJECT -> decodeObject(slime, array.append(), inspector); } } + } + } + } diff --git a/config/src/test/java/com/yahoo/config/subscription/ConfigInstanceTest.java b/config/src/test/java/com/yahoo/config/subscription/ConfigInstanceTest.java index 873df75ce23..5104475d836 100644 --- a/config/src/test/java/com/yahoo/config/subscription/ConfigInstanceTest.java +++ b/config/src/test/java/com/yahoo/config/subscription/ConfigInstanceTest.java @@ -15,7 +15,8 @@ import static org.junit.Assert.fail; * @author gjoranv */ public class ConfigInstanceTest { - private ConfigSourceSet sourceSet = new ConfigSourceSet("config-instance-test"); + + private final ConfigSourceSet sourceSet = new ConfigSourceSet("config-instance-test"); /** * Verifies that the subscriber's configure() method is only diff --git a/config/src/test/java/com/yahoo/vespa/config/ConfigPayloadApplierTest.java b/config/src/test/java/com/yahoo/vespa/config/ConfigPayloadApplierTest.java new file mode 100644 index 00000000000..4d3b6b93b3b --- /dev/null +++ b/config/src/test/java/com/yahoo/vespa/config/ConfigPayloadApplierTest.java @@ -0,0 +1,49 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.config; + +import com.yahoo.config.FileReference; +import com.yahoo.config.ModelReference; +import com.yahoo.config.ResolvedTypesConfig; +import com.yahoo.config.UrlReference; +import org.junit.Test; + +import java.io.File; +import java.nio.file.Path; +import java.util.Optional; + +/** + * @author bratseth + */ +public class ConfigPayloadApplierTest { + + @Test + public void testConfigApplier() { + var applier = new ConfigPayloadApplier<>(new ResolvedTypesConfig.Builder(), new MockAcquirer(), new MockDownloader()); + var config = new ResolvedTypesConfig.Builder(); + config.myPath(new FileReference("mock/myPath.txt")); + config.myUrl(new UrlReference("mock/myUrl.txt")); + config.myModel(new ModelReference(Optional.empty(), + Optional.of(new UrlReference("mockPath/myPath.txt")), + Optional.of(new FileReference("mockUrl/myUrl.txt")))); + applier.applyPayload(ConfigPayload.fromInstance(config.build())); + } + + private static class MockAcquirer implements ConfigTransformer.PathAcquirer { + + @Override + public Path getPath(FileReference fileReference) { + return Path.of("mockPath", fileReference.value()); + } + + } + + private static class MockDownloader extends UrlDownloader { + + @Override + public File waitFor(UrlReference urlReference, long timeout) { + return new File("mockUrl", urlReference.value()); + } + + } + +} diff --git a/config/src/test/resources/configs/def-files/resolved-types.def b/config/src/test/resources/configs/def-files/resolved-types.def new file mode 100644 index 00000000000..184e98d51d9 --- /dev/null +++ b/config/src/test/resources/configs/def-files/resolved-types.def @@ -0,0 +1,6 @@ +# Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +namespace=config + +myPath path +myUrl url +myModel model |