diff options
author | Lester Solbakken <lesters@oath.com> | 2018-12-18 10:37:27 +0100 |
---|---|---|
committer | Lester Solbakken <lesters@oath.com> | 2018-12-18 10:37:27 +0100 |
commit | 7caa60913e4db267f7d7bdfe0e1de90ec12db13f (patch) | |
tree | bbb2e77e81d2823fc7c1048a39a7d38c20edfc44 | |
parent | 305d22637387d183be17a0582b1ced76f2b44982 (diff) |
Add url config type
24 files changed, 409 insertions, 36 deletions
diff --git a/config-lib/src/main/java/com/yahoo/config/LeafNodeMaps.java b/config-lib/src/main/java/com/yahoo/config/LeafNodeMaps.java index ae6040babc6..b6132a44e3c 100644 --- a/config-lib/src/main/java/com/yahoo/config/LeafNodeMaps.java +++ b/config-lib/src/main/java/com/yahoo/config/LeafNodeMaps.java @@ -1,11 +1,10 @@ // 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.nio.file.Path; import java.util.Collections; -import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; +import java.util.stream.Collectors; /** * @author gjoranv @@ -62,4 +61,11 @@ public class LeafNodeMaps { return Collections.unmodifiableMap(pathNodeMap); } + public static Map<String, UrlNode> asUrlNodeMap(Map<String, UrlReference> urlReferenceMap) { + return Collections.unmodifiableMap( + urlReferenceMap.entrySet().stream().collect( + Collectors.toMap(Map.Entry::getKey, e -> new UrlNode(e.getValue())) + )); + } + } diff --git a/config-lib/src/main/java/com/yahoo/config/LeafNodeVector.java b/config-lib/src/main/java/com/yahoo/config/LeafNodeVector.java index 9bbd9b594f8..259afefdd69 100644 --- a/config-lib/src/main/java/com/yahoo/config/LeafNodeVector.java +++ b/config-lib/src/main/java/com/yahoo/config/LeafNodeVector.java @@ -1,6 +1,7 @@ // 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.io.File; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; @@ -68,7 +69,15 @@ public class LeafNodeVector<REAL, NODE extends LeafNode<REAL>> extends NodeVecto List<Path> paths = new ArrayList<>(); for (FileReference fileReference : values) paths.add(Paths.get(fileReference.value())); - return new LeafNodeVector<>(paths, new PathNode()); } + + public static LeafNodeVector<File, UrlNode> createUrlNodeVector(Collection<UrlReference> values) { + List<File> files = new ArrayList<>(); + for (UrlReference urlReference : values) + files.add(new File(urlReference.value())); + return new LeafNodeVector<>(files, new UrlNode()); + } + + } diff --git a/config-lib/src/main/java/com/yahoo/config/UrlNode.java b/config-lib/src/main/java/com/yahoo/config/UrlNode.java new file mode 100644 index 00000000000..0ed70ce0f50 --- /dev/null +++ b/config-lib/src/main/java/com/yahoo/config/UrlNode.java @@ -0,0 +1,65 @@ +// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.config; + +import edu.umd.cs.findbugs.annotations.NonNull; + +import java.io.File; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * Represents a 'url' in a {@link ConfigInstance}, which will be downloaded + * and made available as a {@link File}. Stored in the config builder as a + * {@link UrlReference} to identify fields of this type for special handling + * in the ConfigPayloadApplier. + * + * @author lesters + */ +public class UrlNode extends LeafNode<File> { + + private final UrlReference url; + + public UrlNode() { + url = null; + } + + public UrlNode(UrlReference url) { + super(true); + this.url = url; + this.value = new File(url.value()); + } + + public File value() { + return value; + } + + @Override + public String toString() { + return (value == null) ? "(null)" : '"' + getValue() + '"'; + } + + @Override + public String getValue() { + return value.toString(); + } + + @Override + protected boolean doSetValue(@NonNull String value) { + throw new UnsupportedOperationException("doSetValue should not be necessary since the library anymore!"); + } + + public UrlReference getUrlReference() { + return url; + } + + public static List<UrlReference> toUrlReferences(List<UrlNode> urlNodes) { + return urlNodes.stream().map(UrlNode::getUrlReference).collect(Collectors.toList()); + } + + public static Map<String, UrlReference> toUrlReferenceMap(Map<String, UrlNode> urlNodeMap) { + return urlNodeMap.entrySet().stream().collect( + Collectors.toMap(Map.Entry::getKey, e -> e.getValue().getUrlReference())); + } + +} diff --git a/config-lib/src/main/java/com/yahoo/config/UrlReference.java b/config-lib/src/main/java/com/yahoo/config/UrlReference.java new file mode 100755 index 00000000000..0ec4fd8f8b8 --- /dev/null +++ b/config-lib/src/main/java/com/yahoo/config/UrlReference.java @@ -0,0 +1,40 @@ +// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.config; + +import java.util.Objects; + +/** + * Similar to {@link FileReference}, holds either a URL or a file path to the + * downloaded file depending on state. + * + * @author lesters + */ +public final class UrlReference { + + private final String value; + + public UrlReference(String value) { + this.value = Objects.requireNonNull(value); + } + + public String value() { + return value; + } + + @Override + public int hashCode() { + return value.hashCode(); + } + + @Override + public boolean equals(Object other) { + return other instanceof UrlReference && + value.equals(((UrlReference)other).value); + } + + @Override + public String toString() { + return "url '" + value + "'"; + } + +} diff --git a/config-lib/src/test/java/com/yahoo/config/ConfigInstanceBuilderTest.java b/config-lib/src/test/java/com/yahoo/config/ConfigInstanceBuilderTest.java index cc3515f95db..dc365cc60e7 100644 --- a/config-lib/src/test/java/com/yahoo/config/ConfigInstanceBuilderTest.java +++ b/config-lib/src/test/java/com/yahoo/config/ConfigInstanceBuilderTest.java @@ -159,6 +159,7 @@ public class ConfigInstanceBuilderTest refwithdef(":parent:"). fileVal("etc"). pathVal(FileReference.mockFileReferenceForUnitTesting(new File("pom.xml"))). + urlVal(new UrlReference("http://docs.vespa.ai")). boolarr(false). longarr(9223372036854775807L). longarr(-9223372036854775808L). @@ -173,6 +174,8 @@ public class ConfigInstanceBuilderTest stringMap("one", "first"). filemap("f1", "/var"). filemap("f2", "/store"). + urlMap("u1", new UrlReference("http://docs.vespa.ai/1")). + urlMap("u2", new UrlReference("http://docs.vespa.ai/2")). basicStruct(new BasicStruct.Builder(). foo("basicFoo"). @@ -198,6 +201,7 @@ public class ConfigInstanceBuilderTest enumval(Myarray.Enumval.INNER). refval(":parent:"). fileVal("file0"). + urlVal(new UrlReference("http://docs.vespa.ai/1")). anotherarray(new Myarray.Anotherarray.Builder(). foo(7)). myStruct(new Myarray.MyStruct.Builder(). @@ -209,6 +213,7 @@ public class ConfigInstanceBuilderTest enumval(Myarray.Enumval.INNER). refval(":parent:"). fileVal("file1"). + urlVal(new UrlReference("http://docs.vespa.ai/2")). anotherarray(new Myarray.Anotherarray.Builder(). foo(1). foo(2)). @@ -344,7 +349,7 @@ public class ConfigInstanceBuilderTest funcBuilder.intMap.put("three", 3); funcBuilder.myarray.get(1).intval(17); funcBuilder.myarray.get(0).anotherarray.get(0).foo(32); - funcBuilder.myarray.add(new Myarray.Builder().refval("refval").fileVal("fileval").myStruct(new Myarray.MyStruct.Builder().a(4))); + funcBuilder.myarray.add(new Myarray.Builder().refval("refval").fileVal("fileval").urlVal(new UrlReference("urlval")).myStruct(new Myarray.MyStruct.Builder().a(4))); funcBuilder.myStructMap.put("new", new MyStructMap.Builder().myString("string").myInt(13)); funcBuilder.basicStruct(new BasicStruct.Builder().bar(1234)); FunctionTestConfig function2 = new FunctionTestConfig(funcBuilder); diff --git a/config-lib/src/test/java/com/yahoo/config/ConfigInstanceEqualsTest.java b/config-lib/src/test/java/com/yahoo/config/ConfigInstanceEqualsTest.java index ca8b9aea2fe..06db64fb20c 100644 --- a/config-lib/src/test/java/com/yahoo/config/ConfigInstanceEqualsTest.java +++ b/config-lib/src/test/java/com/yahoo/config/ConfigInstanceEqualsTest.java @@ -131,6 +131,7 @@ public class ConfigInstanceEqualsTest { refval(":parent:"). fileVal("etc"). pathVal(FileReference.mockFileReferenceForUnitTesting(new File("pom.xml"))). + urlVal(new UrlReference("http://docs.vespa.ai")). boolarr(false). longarr(9223372036854775807L). longarr(-9223372036854775808L). @@ -140,6 +141,7 @@ public class ConfigInstanceEqualsTest { enumarr(Enumarr.VALUES). refarr(Arrays.asList(":parent:", ":parent", "parent:")). // test collection based setter fileArr("bin"). + urlArr(new UrlReference("http://docs.vespa.ai")). basicStruct(new BasicStruct.Builder(). foo("basicFoo"). @@ -162,6 +164,7 @@ public class ConfigInstanceEqualsTest { enumval(Myarray.Enumval.INNER). refval(":parent:"). fileVal("file0"). + urlVal(new UrlReference("http://docs.vespa.ai/1")). anotherarray(new Myarray.Anotherarray.Builder(). foo(7)). myStruct(new Myarray.MyStruct.Builder(). @@ -173,6 +176,7 @@ public class ConfigInstanceEqualsTest { enumval(Myarray.Enumval.INNER). refval(":parent:"). fileVal("file1"). + urlVal(new UrlReference("http://docs.vespa.ai/2")). anotherarray(new Myarray.Anotherarray.Builder(). foo(1). foo(2)). diff --git a/config-lib/src/test/java/com/yahoo/config/UrlNodeTest.java b/config-lib/src/test/java/com/yahoo/config/UrlNodeTest.java new file mode 100644 index 00000000000..d8d6cc0f1f1 --- /dev/null +++ b/config-lib/src/test/java/com/yahoo/config/UrlNodeTest.java @@ -0,0 +1,26 @@ +// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.config; + +import org.junit.Test; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +/** + * @author lesters + */ +public class UrlNodeTest { + + @Test + public void testSetValue() { + UrlNode url = new UrlNode(); + assertThat(url.toString(), is("(null)")); + + url = new UrlNode(new UrlReference("https://docs.vespa.ai/")); + assertThat(url.getUrlReference().value(), is("https://docs.vespa.ai/")); + + url = new UrlNode(new UrlReference("pom.xml")); + assertThat(url.getValue(), is("pom.xml")); + } + +} diff --git a/config-lib/src/test/resources/configdefinitions/function-test.def b/config-lib/src/test/resources/configdefinitions/function-test.def index 04d040a910b..73681d95544 100644 --- a/config-lib/src/test/resources/configdefinitions/function-test.def +++ b/config-lib/src/test/resources/configdefinitions/function-test.def @@ -44,6 +44,7 @@ refval reference restart refwithdef reference default=":parent:" restart fileVal file restart pathVal path restart +urlVal url boolarr[] bool restart intarr[] int restart @@ -54,12 +55,14 @@ enumarr[] enum { ARRAY, VALUES } restart refarr[] reference restart fileArr[] file restart pathArr[] path restart +urlArr[] url #This is a map of ints. intMap{} int restart stringMap{} string restart filemap{} file restart pathMap{} path restart +urlMap{} url # A basic struct basicStruct.foo string default="basic" restart @@ -80,6 +83,7 @@ myarray[].stringval[] string restart myarray[].enumval enum { INNER, ENUM, TYPE } default=TYPE restart myarray[].refval reference # Value in array without default restart myarray[].fileVal file restart +myarray[].urlVal url myarray[].anotherarray[].foo int default=-4 restart myarray[].myStruct.a int restart myarray[].myStruct.b int default=2 restart diff --git a/config-model/src/test/java/com/yahoo/vespa/model/InstanceResolverTest.java b/config-model/src/test/java/com/yahoo/vespa/model/InstanceResolverTest.java index a9a6621c751..0f58c5e3a2a 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/InstanceResolverTest.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/InstanceResolverTest.java @@ -1,6 +1,7 @@ // Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.model; +import com.yahoo.config.UrlReference; import com.yahoo.test.FunctionTestConfig; import com.yahoo.test.FunctionTestConfig.*; import com.yahoo.test.SimpletypesConfig; @@ -47,6 +48,10 @@ public class InstanceResolverTest { assertTrue(c.rootStruct().innerArr(0).boolVal()); assertEquals(c.rootStruct().innerArr(0).stringVal(), "deep"); assertEquals(c.myarray(0).intval(), -123424); + assertEquals(c.urlVal().toString(), "url"); + assertEquals(c.urlArr(0).toString(), "url"); + assertEquals(c.myarray(0).urlVal().toString(), "url1"); + assertEquals(c.myarray(1).urlVal().toString(), "url2"); } /** @@ -88,6 +93,7 @@ public class InstanceResolverTest { refval(":parent:"). refwithdef(":parent:"). fileVal("etc"). + urlVal(new UrlReference("url")). boolarr(false). longarr(9223372036854775807L). longarr(-9223372036854775808L). @@ -97,6 +103,7 @@ public class InstanceResolverTest { enumarr(Enumarr.VALUES). refarr(Arrays.asList(":parent:", ":parent", "parent:")). // test collection based setter fileArr("bin"). + urlArr(new UrlReference("url")). basicStruct(new BasicStruct.Builder(). //foo("basicFoo"). @@ -119,6 +126,7 @@ public class InstanceResolverTest { enumval(Myarray.Enumval.INNER). refval(":parent:"). fileVal("file0"). + urlVal(new UrlReference("url1")). anotherarray(new Myarray.Anotherarray.Builder(). foo(7)). myStruct(new Myarray.MyStruct.Builder(). @@ -130,6 +138,7 @@ public class InstanceResolverTest { enumval(Myarray.Enumval.INNER). refval(":parent:"). fileVal("file1"). + urlVal(new UrlReference("url2")). anotherarray(new Myarray.Anotherarray.Builder(). foo(1). foo(2)). diff --git a/config-model/src/test/resources/configdefinitions/function-test.def b/config-model/src/test/resources/configdefinitions/function-test.def index 86a110c3413..4208f7ab906 100644 --- a/config-model/src/test/resources/configdefinitions/function-test.def +++ b/config-model/src/test/resources/configdefinitions/function-test.def @@ -40,6 +40,7 @@ onechoice enum { ONLYFOO } default=ONLYFOO refval reference refwithdef reference default=":parent:" fileVal file +urlVal url boolarr[] bool intarr[] int @@ -49,6 +50,7 @@ stringarr[] string enumarr[] enum { ARRAY, VALUES } refarr[] reference fileArr[] file +urlArr[] url # A basic struct basicStruct.foo string default="basic" @@ -68,6 +70,7 @@ myarray[].stringval[] string myarray[].enumval enum { INNER, ENUM, TYPE } default=TYPE myarray[].refval reference # Value in array without default myarray[].fileVal file +myarray[].urlVal url myarray[].anotherarray[].foo int default=-4 myarray[].myStruct.a int myarray[].myStruct.b int default=2 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 4c4a1b69082..b969220ee05 100644 --- a/config/src/main/java/com/yahoo/vespa/config/ConfigDefinition.java +++ b/config/src/main/java/com/yahoo/vespa/config/ConfigDefinition.java @@ -34,6 +34,7 @@ public class ConfigDefinition implements Comparable<ConfigDefinition> { private Map<String, RefDef> referenceDefs = new LinkedHashMap<String, RefDef>(); private Map<String, FileDef> fileDefs = new LinkedHashMap<String, FileDef>(); private Map<String, PathDef> pathDefs = new LinkedHashMap<>(); + private Map<String, UrlDef> urlDefs = new LinkedHashMap<>(); private Map<String, StructDef> structDefs = new LinkedHashMap<String, StructDef>(); private Map<String, InnerArrayDef> innerArrayDefs = new LinkedHashMap<String, InnerArrayDef>(); private Map<String, ArrayDef> arrayDefs = new LinkedHashMap<String, ArrayDef>(); @@ -100,6 +101,8 @@ public class ConfigDefinition implements Comparable<ConfigDefinition> { verifyFile(id); } else if (pathDefs.containsKey(id)) { verifyPath(id); + } else if (urlDefs.containsKey(id)) { + verifyUrl(id); } else if (boolDefs.containsKey(id)) { verifyBool(id, val); } else if (intDefs.containsKey(id)) { @@ -605,6 +608,19 @@ public class ConfigDefinition implements Comparable<ConfigDefinition> { } } + public static class UrlDef implements DefaultValued<String>{ + private String defVal; + + public UrlDef(String defVal) { + this.defVal = defVal; + } + + @Override + public String getDefVal() { + return defVal; + } + } + public void addEnumDef(String id, EnumDef def) { enumDefs.put(id, def); } @@ -706,6 +722,14 @@ public class ConfigDefinition implements Comparable<ConfigDefinition> { pathDefs.put(refId, new PathDef(null)); } + public void addUrlDef(String url, String defVal) { + urlDefs.put(url, new UrlDef(defVal)); + } + + public void addUrlDef(String url) { + urlDefs.put(url, new UrlDef(null)); + } + public Map<String, StringDef> getStringDefs() { return stringDefs; } @@ -969,6 +993,14 @@ public class ConfigDefinition implements Comparable<ConfigDefinition> { return true; } + private boolean verifyUrl(String id) { + if (!urlDefs.containsKey(id)) { + defFail("No such url in " + verifyWarning(id)); + return false; + } + return true; + } + private boolean verifyBool(String id) { if (!boolDefs.containsKey(id)) { defFail("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 c4a8bf8f864..0121e47b9ae 100644 --- a/config/src/main/java/com/yahoo/vespa/config/ConfigDefinitionBuilder.java +++ b/config/src/main/java/com/yahoo/vespa/config/ConfigDefinitionBuilder.java @@ -48,8 +48,8 @@ public class ConfigDefinitionBuilder { new ConfigDefinition.TypeSpec(name, ((LeafCNode) node).getType(), null, enumValues, null, null)); } else if (node.isMap) { - //System.out.println("Adding leaf map node " + name); - def.leafMapDef(name).setTypeSpec(new ConfigDefinition.TypeSpec(name, ((LeafCNode) node).getType(), null, null, null, null)); + //System.out.println("Adding leaf map node " + name); + def.leafMapDef(name).setTypeSpec(new ConfigDefinition.TypeSpec(name, ((LeafCNode) node).getType(), null, null, null, null)); } else { //System.out.println("Adding basic node " + name); if (node instanceof LeafCNode.IntegerLeaf) { @@ -67,7 +67,9 @@ public class ConfigDefinitionBuilder { addNode(def, (LeafCNode.FileLeaf) node); } else if (node instanceof LeafCNode.PathLeaf) { addNode(def, (LeafCNode.PathLeaf) node); - }else if (node instanceof LeafCNode.StringLeaf) { + } else if (node instanceof LeafCNode.UrlLeaf) { + addNode(def, (LeafCNode.UrlLeaf) node); + } else if (node instanceof LeafCNode.StringLeaf) { addNode(def, (LeafCNode.StringLeaf) node); } else if (node instanceof LeafCNode.EnumLeaf) { addNode(def, (LeafCNode.EnumLeaf) node); @@ -87,9 +89,9 @@ public class ConfigDefinitionBuilder { } } } else if (node.isMap) { - //System.out.println("Adding struct map node " + name); - newDef = def.structMapDef(name); - if (node.getChildren() != null && node.getChildren().length > 0) { + //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); @@ -174,6 +176,14 @@ public class ConfigDefinitionBuilder { } } + static void addNode(ConfigDefinition def, LeafCNode.UrlLeaf leaf) { + if (leaf.getDefaultValue() != null) { + def.addUrlDef(leaf.getName(), leaf.getDefaultValue().getValue()); + } else { + def.addUrlDef(leaf.getName(), null); + } + } + static void addNode(ConfigDefinition def, LeafCNode.EnumLeaf leaf) { if (leaf.getDefaultValue() != null) { def.addEnumDef(leaf.getName(), Arrays.asList(leaf.getLegalValues()), leaf.getDefaultValue().getValue()); 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 d406dfe2d77..8a12405d505 100644 --- a/config/src/main/java/com/yahoo/vespa/config/ConfigPayloadApplier.java +++ b/config/src/main/java/com/yahoo/vespa/config/ConfigPayloadApplier.java @@ -4,6 +4,7 @@ package com.yahoo.vespa.config; import com.yahoo.config.ConfigBuilder; import com.yahoo.config.ConfigInstance; import com.yahoo.config.FileReference; +import com.yahoo.config.UrlReference; import com.yahoo.log.LogLevel; import com.yahoo.yolean.Exceptions; import com.yahoo.slime.ArrayTraverser; @@ -254,6 +255,11 @@ public class ConfigPayloadApplier<T extends ConfigInstance.Builder> { 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)) { + throw new UnsupportedOperationException("'url' type is not yet implemented"); + } else { Object object = getValueFromInspector(value); invokeSetter(builder, methodName, object); @@ -337,42 +343,50 @@ public class ConfigPayloadApplier<T extends ConfigInstance.Builder> { * Checks whether or not this field is of type 'path', in which * case some special handling might be needed. Caches the result. */ - private Set<String> pathFieldSet = new HashSet<>(); private boolean isPathField(Object builder, String methodName) { - String key = pathFieldKey(builder, methodName); - if (pathFieldSet.contains(key)) { + // Paths are stored as FileReference in Builder. + return isFieldType(builder, methodName, FileReference.class); + } + + private boolean isUrlField(Object builder, String methodName) { + // Urls are stored as UrlReference in Builder. + return isFieldType(builder, methodName, UrlReference.class); + } + + private Set<String> fieldSet = new HashSet<>(); + private boolean isFieldType(Object builder, String methodName, java.lang.reflect.Type type) { + String key = fieldKey(builder, methodName); + if (fieldSet.contains(key)) { return true; } - boolean isPath = false; + boolean isType = false; try { Field field = builder.getClass().getDeclaredField(methodName); - //Paths are stored as FileReference in Builder. java.lang.reflect.Type fieldType = field.getGenericType(); - if (fieldType instanceof Class<?> && fieldType == FileReference.class) { - isPath = true; + if (fieldType instanceof Class<?> && fieldType == type) { + isType = true; } else if (fieldType instanceof ParameterizedType) { - isPath = isParameterizedWithPath((ParameterizedType) fieldType); + isType = isParameterizedWith((ParameterizedType) fieldType, type); } } catch (NoSuchFieldException e) { } - if (isPath) { - pathFieldSet.add(key); + if (isType) { + fieldSet.add(key); } - return isPath; + return isType; } - private static String pathFieldKey(Object builder, String methodName) { + private static String fieldKey(Object builder, String methodName) { return builder.getClass().getName() + "." + methodName; } - private boolean isParameterizedWithPath(ParameterizedType fieldType) { + private boolean isParameterizedWith(ParameterizedType fieldType, java.lang.reflect.Type type) { int numTypeArgs = fieldType.getActualTypeArguments().length; if (numTypeArgs > 0) - return fieldType.getActualTypeArguments()[numTypeArgs - 1] == FileReference.class; + return fieldType.getActualTypeArguments()[numTypeArgs - 1] == type; return false; } - private String capitalize(String name) { StringBuilder sb = new StringBuilder(); sb.append(name.substring(0, 1).toUpperCase()).append(name.substring(1)); diff --git a/configgen/src/main/java/com/yahoo/config/codegen/BuilderGenerator.java b/configgen/src/main/java/com/yahoo/config/codegen/BuilderGenerator.java index 7789a2b2cfb..b3c4d0c5ff8 100644 --- a/configgen/src/main/java/com/yahoo/config/codegen/BuilderGenerator.java +++ b/configgen/src/main/java/com/yahoo/config/codegen/BuilderGenerator.java @@ -3,6 +3,7 @@ package com.yahoo.config.codegen; import com.yahoo.config.codegen.LeafCNode.FileLeaf; import com.yahoo.config.codegen.LeafCNode.PathLeaf; +import com.yahoo.config.codegen.LeafCNode.UrlLeaf; import java.util.ArrayList; import java.util.List; @@ -169,7 +170,7 @@ public class BuilderGenerator { } private static String privateLeafNodeSetter(LeafCNode n) { - if ("String".equals(builderType(n)) || "FileReference".equals(builderType(n))) { + if ("String".equals(builderType(n)) || "FileReference".equals(builderType(n)) || "UrlReference".equals(builderType(n))) { return ""; } else { return "\n\n" + // @@ -197,7 +198,7 @@ public class BuilderGenerator { } private static String privateLeafMapSetter(CNode n) { - if ("String".equals(builderType(n)) || "FileReference".equals(builderType(n))) { + if ("String".equals(builderType(n)) || "FileReference".equals(builderType(n)) || "UrlReference".equals(builderType(n))) { return ""; } else { return "\n\n" + // @@ -219,7 +220,7 @@ public class BuilderGenerator { : ""; String bType = builderType(n); - String stringSetter = "String".equals(bType) || "FileReference".equals(bType) ? "" + String stringSetter = "String".equals(bType) || "FileReference".equals(bType) || "UrlReference".equals(bType) ? "" : String.format("\nprivate Builder %s(String %svalue) {\n" + // " return %s(%s.valueOf(%svalue));\n" + // "}", name, INTERNAL_PREFIX, name, boxedDataType(n), INTERNAL_PREFIX); @@ -251,6 +252,12 @@ public class BuilderGenerator { return name + "(" + nodeClass(child) + ".toFileReferenceMap(config." + name + "));"; } else if (child instanceof PathLeaf) { return name + "(config." + name + ".getFileReference());"; + } else if (child instanceof UrlLeaf && isArray) { + return name + "(" + nodeClass(child) + ".toUrlReferences(config." + name + "));"; + } else if (child instanceof UrlLeaf && isMap) { + return name + "(" + nodeClass(child) + ".toUrlReferenceMap(config." + name + "));"; + } else if (child instanceof UrlLeaf) { + return name + "(config." + name + ".getUrlReference());"; } else if (child instanceof LeafCNode) { return name + "(config." + name + "());"; } else if (child instanceof InnerCNode && isArray) { @@ -340,6 +347,8 @@ public class BuilderGenerator { return "String"; } else if (node instanceof PathLeaf) { return "FileReference"; + } else if (node instanceof UrlLeaf) { + return "UrlReference"; } else if (node instanceof LeafCNode && (node.isArray || node.isMap)) { return boxedDataType(node); } else { @@ -352,6 +361,8 @@ public class BuilderGenerator { return "String"; } else if (node instanceof PathLeaf) { return "FileReference"; + } else if (node instanceof UrlLeaf) { + return "UrlReference"; } else { return boxedDataType(node); } diff --git a/configgen/src/main/java/com/yahoo/config/codegen/ConfigGenerator.java b/configgen/src/main/java/com/yahoo/config/codegen/ConfigGenerator.java index f7c6267a6bb..4da546a7179 100644 --- a/configgen/src/main/java/com/yahoo/config/codegen/ConfigGenerator.java +++ b/configgen/src/main/java/com/yahoo/config/codegen/ConfigGenerator.java @@ -10,6 +10,7 @@ import com.yahoo.config.codegen.LeafCNode.LongLeaf; import com.yahoo.config.codegen.LeafCNode.PathLeaf; import com.yahoo.config.codegen.LeafCNode.ReferenceLeaf; import com.yahoo.config.codegen.LeafCNode.StringLeaf; +import com.yahoo.config.codegen.LeafCNode.UrlLeaf; import java.util.LinkedList; import java.util.List; @@ -163,12 +164,16 @@ public class ConfigGenerator { return name + " = LeafNodeVector.createFileNodeVector(builder." + name + ");"; } else if (child instanceof PathLeaf && isArray) { return name + " = LeafNodeVector.createPathNodeVector(builder." + name + ");"; + } else if (child instanceof UrlLeaf && isArray) { + return name + " = LeafNodeVector.createUrlNodeVector(builder." + name + ");"; } else if (child instanceof LeafCNode && isArray) { return name + " = new LeafNodeVector<>(builder." + name + ", new " + className + "());"; } else if (child instanceof FileLeaf && isMap) { return name + " = LeafNodeMaps.asFileNodeMap(builder." + name + ");"; } else if (child instanceof PathLeaf && isMap) { return name + " = LeafNodeMaps.asPathNodeMap(builder." + name + ");"; + } else if (child instanceof UrlLeaf && isMap) { + return name + " = LeafNodeMaps.asUrlNodeMap(builder." + name + ");"; } else if (child instanceof LeafCNode && isMap) { return name + " = LeafNodeMaps.asNodeMap(builder." + name + ", new " + className + "());"; } else if (child instanceof InnerCNode && isArray) { @@ -178,7 +183,7 @@ public class ConfigGenerator { } else if (child instanceof InnerCNode) { return name + " = new " + className + "(builder." + name + ", throwIfUninitialized);"; } else if (child instanceof LeafCNode) { - return name + " = (builder." + name + " == null) ?\n" +// + return name + " = (builder." + name + " == null) ?\n" + " new " + className + "(" + scalarDefault((LeafCNode) child) + ") : new " + className + "(builder." + name + ");"; } else { throw new IllegalStateException("Cannot create assignment for node"); // should not happen @@ -391,6 +396,8 @@ public class ConfigGenerator { return "FileNode"; } else if (node instanceof PathLeaf) { return "PathNode"; + } else if (node instanceof UrlLeaf) { + return "UrlNode"; } else if (node instanceof IntegerLeaf) { return "IntegerNode"; } else if (node instanceof LongLeaf) { @@ -417,6 +424,8 @@ public class ConfigGenerator { return "FileReference"; } else if (node instanceof PathLeaf) { return "Path"; + } else if (node instanceof UrlLeaf) { + return "File"; } else if (node instanceof IntegerLeaf) { return "int"; } else if (node instanceof LongLeaf) { diff --git a/configgen/src/main/java/com/yahoo/config/codegen/JavaClassBuilder.java b/configgen/src/main/java/com/yahoo/config/codegen/JavaClassBuilder.java index e30b59b642a..5c447191614 100644 --- a/configgen/src/main/java/com/yahoo/config/codegen/JavaClassBuilder.java +++ b/configgen/src/main/java/com/yahoo/config/codegen/JavaClassBuilder.java @@ -71,6 +71,7 @@ public class JavaClassBuilder implements ClassBuilder { "package " + javaPackage + ";\n" + // "\n" + // "import java.util.*;\n" + // + "import java.io.File;\n" + // "import java.nio.file.Path;\n" + // "import edu.umd.cs.findbugs.annotations.NonNull;\n" + // getImportFrameworkClasses(root.getNamespace()); diff --git a/configgen/src/main/java/com/yahoo/config/codegen/LeafCNode.java b/configgen/src/main/java/com/yahoo/config/codegen/LeafCNode.java index 7623987656a..e8dd4221f0e 100644 --- a/configgen/src/main/java/com/yahoo/config/codegen/LeafCNode.java +++ b/configgen/src/main/java/com/yahoo/config/codegen/LeafCNode.java @@ -27,6 +27,7 @@ public abstract class LeafCNode extends CNode { case "file": return new FileLeaf(parent, name); case "path": return new PathLeaf(parent, name); case "enum": return new EnumLeaf(parent, name, type.enumArray); + case "url" : return new UrlLeaf(parent, name); default: return null; } } catch (NumberFormatException e) { @@ -217,6 +218,17 @@ public abstract class LeafCNode extends CNode { } } + public static class UrlLeaf extends NoClassNoDefaultLeafCNode { + UrlLeaf(InnerCNode parent, String name) { + super(parent, name); + } + + @Override + public String getType() { + return "url"; + } + } + public static class EnumLeaf extends LeafCNode { private final String[] legalValues; diff --git a/configgen/src/test/java/com/yahoo/config/codegen/DefLineParsingTest.java b/configgen/src/test/java/com/yahoo/config/codegen/DefLineParsingTest.java index 99699d888dc..a267c2bc535 100644 --- a/configgen/src/test/java/com/yahoo/config/codegen/DefLineParsingTest.java +++ b/configgen/src/test/java/com/yahoo/config/codegen/DefLineParsingTest.java @@ -102,6 +102,26 @@ public class DefLineParsingTest { } @Test + public void testParseUrls() { + DefLine l = new DefLine("urlVal url"); + + assertEquals("urlVal", l.getName()); + assertNull(l.getDefault()); + assertEquals("url", l.getType().getName()); + } + + @Test + public void testParseDefaultUrls() { + DefLine l = new DefLine("urlVal url default=\"http://docs.vespa.ai\""); + + assertEquals("urlVal", l.getName()); + assertEquals("http://docs.vespa.ai", l.getDefault().getValue()); + assertEquals("\"http://docs.vespa.ai\"", l.getDefault().getStringRepresentation()); + assertEquals("url", l.getType().getName()); + } + + + @Test public void testParseDefaultInt() { DefLine l = new DefLine("foo int default=1000"); diff --git a/configgen/src/test/java/com/yahoo/config/codegen/DefParserTest.java b/configgen/src/test/java/com/yahoo/config/codegen/DefParserTest.java index e36641bb626..98c30aa09cf 100644 --- a/configgen/src/test/java/com/yahoo/config/codegen/DefParserTest.java +++ b/configgen/src/test/java/com/yahoo/config/codegen/DefParserTest.java @@ -28,7 +28,7 @@ public class DefParserTest { CNode root = new DefParser("test", new FileReader(defFile)).getTree(); assertNotNull(root); CNode[] children = root.getChildren(); - assertThat(children.length, is(31)); + assertThat(children.length, is(34)); int numGrandChildren = 0; int numGreatGrandChildren = 0; @@ -70,7 +70,7 @@ public class DefParserTest { public void testMd5Sum() throws IOException { File defFile = new File(DEF_NAME); CNode root = new DefParser("test", new FileReader(defFile)).getTree(); - assertThat(root.defMd5, is("eb2d24dbbcf054b21be729e2cfaafd93")); + assertThat(root.defMd5, is("f901bdc5c96e7005130399c63f247823")); } @Test diff --git a/configgen/src/test/java/com/yahoo/config/codegen/JavaClassBuilderTest.java b/configgen/src/test/java/com/yahoo/config/codegen/JavaClassBuilderTest.java index 381d587e3c3..11da88a12fa 100644 --- a/configgen/src/test/java/com/yahoo/config/codegen/JavaClassBuilderTest.java +++ b/configgen/src/test/java/com/yahoo/config/codegen/JavaClassBuilderTest.java @@ -35,6 +35,8 @@ public class JavaClassBuilderTest { "namespace=test\n" + // "p path\n" + // "pathArr[] path\n" + // + "u url\n" + // + "urlArr[] url\n" + // "f file\n" + // "fileArr[] file\n" + // "i int default=0\n" + // @@ -116,7 +118,7 @@ public class JavaClassBuilderTest { for (int i = 0; i < referenceClassLines.size(); i++) { if (configClassLines.length <= i) - fail("Missing lines i generated comnfig class. First missing line:\n" + referenceClassLines.get(i)); + fail("Missing lines i generated config class. First missing line:\n" + referenceClassLines.get(i)); assertEquals("Line " + i, referenceClassLines.get(i), configClassLines[i]); } } diff --git a/configgen/src/test/java/com/yahoo/config/codegen/NormalizedDefinitionTest.java b/configgen/src/test/java/com/yahoo/config/codegen/NormalizedDefinitionTest.java index cbb0d9c4082..9cda4cfbb1c 100644 --- a/configgen/src/test/java/com/yahoo/config/codegen/NormalizedDefinitionTest.java +++ b/configgen/src/test/java/com/yahoo/config/codegen/NormalizedDefinitionTest.java @@ -68,7 +68,7 @@ public class NormalizedDefinitionTest { } assertNotNull(out); - assertThat(out.size(), is(69)); + assertThat(out.size(), is(72)); assertNotNull(fileReader); fileReader.close(); diff --git a/configgen/src/test/resources/allfeatures.def b/configgen/src/test/resources/allfeatures.def index e13e14c9e36..fb627f614d6 100644 --- a/configgen/src/test/resources/allfeatures.def +++ b/configgen/src/test/resources/allfeatures.def @@ -39,6 +39,7 @@ refVal reference refwithdef reference default=":parent:" fileVal file pathVal path +urlVal url boolarr[] bool intarr[] int @@ -49,9 +50,11 @@ enumarr[] enum { ARRAY, VALUES } refarr[] reference filearr[] file pathArr[] path +urlArr[] url intMap{} int pathMap{} file +urlMap{} url # A basic struct basic_struct.foo string default="foo" diff --git a/configgen/src/test/resources/allfeatures.reference b/configgen/src/test/resources/allfeatures.reference index 1916e37c1cc..f075daecd04 100644 --- a/configgen/src/test/resources/allfeatures.reference +++ b/configgen/src/test/resources/allfeatures.reference @@ -6,6 +6,7 @@ package com.yahoo.configgen; import java.util.*; +import java.io.File; import java.nio.file.Path; import edu.umd.cs.findbugs.annotations.NonNull; import com.yahoo.config.*; @@ -35,7 +36,7 @@ import com.yahoo.config.*; */ public final class AllfeaturesConfig extends ConfigInstance { - public final static String CONFIG_DEF_MD5 = "eb2d24dbbcf054b21be729e2cfaafd93"; + public final static String CONFIG_DEF_MD5 = "f901bdc5c96e7005130399c63f247823"; public final static String CONFIG_DEF_NAME = "allfeatures"; public final static String CONFIG_DEF_NAMESPACE = "configgen"; public final static String CONFIG_DEF_VERSION = ""; @@ -57,6 +58,7 @@ public final class AllfeaturesConfig extends ConfigInstance { "refwithdef reference default=\":parent:\"", "fileVal file", "pathVal path", + "urlVal url", "boolarr[] bool", "intarr[] int", "longarr[] long", @@ -66,8 +68,10 @@ public final class AllfeaturesConfig extends ConfigInstance { "refarr[] reference", "filearr[] file", "pathArr[] path", + "urlArr[] url", "intMap{} int", "pathMap{} file", + "urlMap{} url", "basic_struct.foo string default=\"foo\"", "basic_struct.bar int default=0", "struct_of_struct.inner0.name string default=\"inner0\"", @@ -105,7 +109,8 @@ public final class AllfeaturesConfig extends ConfigInstance { "enumVal", "refVal", "fileVal", - "pathVal" + "pathVal", + "urlVal" )); private Boolean boolVal = null; @@ -124,6 +129,7 @@ public final class AllfeaturesConfig extends ConfigInstance { private String refwithdef = null; private String fileVal = null; private FileReference pathVal = null; + private UrlReference urlVal = null; public List<Boolean> boolarr = new ArrayList<>(); public List<Integer> intarr = new ArrayList<>(); public List<Long> longarr = new ArrayList<>(); @@ -133,8 +139,10 @@ public final class AllfeaturesConfig extends ConfigInstance { public List<String> refarr = new ArrayList<>(); public List<String> filearr = new ArrayList<>(); public List<FileReference> pathArr = new ArrayList<>(); + public List<UrlReference> urlArr = new ArrayList<>(); public Map<String, Integer> intMap = new LinkedHashMap<>(); public Map<String, String> pathMap = new LinkedHashMap<>(); + public Map<String, UrlReference> urlMap = new LinkedHashMap<>(); public Basic_struct.Builder basic_struct = new Basic_struct.Builder(); public Struct_of_struct.Builder struct_of_struct = new Struct_of_struct.Builder(); public List<MyArray.Builder> myArray = new ArrayList<>(); @@ -159,6 +167,7 @@ public final class AllfeaturesConfig extends ConfigInstance { refwithdef(config.refwithdef()); fileVal(config.fileVal().value()); pathVal(config.pathVal.getFileReference()); + urlVal(config.urlVal.getUrlReference()); boolarr(config.boolarr()); intarr(config.intarr()); longarr(config.longarr()); @@ -168,8 +177,10 @@ public final class AllfeaturesConfig extends ConfigInstance { refarr(config.refarr()); filearr(FileReference.toValues(config.filearr())); pathArr(PathNode.toFileReferences(config.pathArr)); + urlArr(UrlNode.toUrlReferences(config.urlArr)); intMap(config.intMap()); pathMap(FileReference.toValueMap(config.pathMap())); + urlMap(UrlNode.toUrlReferenceMap(config.urlMap)); basic_struct(new Basic_struct.Builder(config.basic_struct())); struct_of_struct(new Struct_of_struct.Builder(config.struct_of_struct())); for (MyArray m : config.myArray()) { @@ -213,6 +224,8 @@ public final class AllfeaturesConfig extends ConfigInstance { fileVal(__superior.fileVal); if (__superior.pathVal != null) pathVal(__superior.pathVal); + if (__superior.urlVal != null) + urlVal(__superior.urlVal); if (!__superior.boolarr.isEmpty()) boolarr.addAll(__superior.boolarr); if (!__superior.intarr.isEmpty()) @@ -231,8 +244,11 @@ public final class AllfeaturesConfig extends ConfigInstance { filearr.addAll(__superior.filearr); if (!__superior.pathArr.isEmpty()) pathArr.addAll(__superior.pathArr); + if (!__superior.urlArr.isEmpty()) + urlArr.addAll(__superior.urlArr); intMap(__superior.intMap); pathMap(__superior.pathMap); + urlMap(__superior.urlMap); basic_struct(basic_struct.override(__superior.basic_struct)); struct_of_struct(struct_of_struct.override(__superior.struct_of_struct)); if (!__superior.myArray.isEmpty()) @@ -384,6 +400,14 @@ public final class AllfeaturesConfig extends ConfigInstance { } + public Builder urlVal(UrlReference __value) { + if (__value == null) throw new IllegalArgumentException("Null value is not allowed."); + urlVal = __value; + __uninitialized.remove("urlVal"); + return this; + } + + public Builder boolarr(Boolean __value) { boolarr.add(__value); return this; @@ -494,6 +518,16 @@ public final class AllfeaturesConfig extends ConfigInstance { return this; } + public Builder urlArr(UrlReference __value) { + urlArr.add(__value); + return this; + } + + public Builder urlArr(Collection<UrlReference> __values) { + urlArr.addAll(__values); + return this; + } + public Builder intMap(String __key, Integer __value) { intMap.put(__key, __value); return this; @@ -518,6 +552,16 @@ public final class AllfeaturesConfig extends ConfigInstance { return this; } + public Builder urlMap(String __key, UrlReference __value) { + urlMap.put(__key, __value); + return this; + } + + public Builder urlMap(Map<String, UrlReference> __values) { + urlMap.putAll(__values); + return this; + } + public Builder basic_struct(Basic_struct.Builder __builder) { basic_struct = __builder; return this; @@ -600,6 +644,7 @@ public final class AllfeaturesConfig extends ConfigInstance { private final ReferenceNode refwithdef; private final FileNode fileVal; private final PathNode pathVal; + private final UrlNode urlVal; private final LeafNodeVector<Boolean, BooleanNode> boolarr; private final LeafNodeVector<Integer, IntegerNode> intarr; private final LeafNodeVector<Long, LongNode> longarr; @@ -609,8 +654,10 @@ public final class AllfeaturesConfig extends ConfigInstance { private final LeafNodeVector<String, ReferenceNode> refarr; private final LeafNodeVector<FileReference, FileNode> filearr; private final LeafNodeVector<Path, PathNode> pathArr; + private final LeafNodeVector<File, UrlNode> urlArr; private final Map<String, IntegerNode> intMap; private final Map<String, FileNode> pathMap; + private final Map<String, UrlNode> urlMap; private final Basic_struct basic_struct; private final Struct_of_struct struct_of_struct; private final InnerNodeVector<MyArray> myArray; @@ -657,6 +704,8 @@ public final class AllfeaturesConfig extends ConfigInstance { new FileNode() : new FileNode(builder.fileVal); pathVal = (builder.pathVal == null) ? new PathNode() : new PathNode(builder.pathVal); + urlVal = (builder.urlVal == null) ? + new UrlNode() : new UrlNode(builder.urlVal); boolarr = new LeafNodeVector<>(builder.boolarr, new BooleanNode()); intarr = new LeafNodeVector<>(builder.intarr, new IntegerNode()); longarr = new LeafNodeVector<>(builder.longarr, new LongNode()); @@ -666,8 +715,10 @@ public final class AllfeaturesConfig extends ConfigInstance { refarr = new LeafNodeVector<>(builder.refarr, new ReferenceNode()); filearr = LeafNodeVector.createFileNodeVector(builder.filearr); pathArr = LeafNodeVector.createPathNodeVector(builder.pathArr); + urlArr = LeafNodeVector.createUrlNodeVector(builder.urlArr); intMap = LeafNodeMaps.asNodeMap(builder.intMap, new IntegerNode()); pathMap = LeafNodeMaps.asFileNodeMap(builder.pathMap); + urlMap = LeafNodeMaps.asUrlNodeMap(builder.urlMap); basic_struct = new Basic_struct(builder.basic_struct, throwIfUninitialized); struct_of_struct = new Struct_of_struct(builder.struct_of_struct, throwIfUninitialized); myArray = MyArray.createVector(builder.myArray); @@ -787,6 +838,13 @@ public final class AllfeaturesConfig extends ConfigInstance { } /** + * @return allfeatures.urlVal + */ + public File urlVal() { + return urlVal.value(); + } + + /** * @return allfeatures.boolarr[] */ public List<Boolean> boolarr() { @@ -922,6 +980,21 @@ public final class AllfeaturesConfig extends ConfigInstance { } /** + * @return allfeatures.urlArr[] + */ + public List<File> urlArr() { + return urlArr.asList(); + } + + /** + * @param i the index of the value to return + * @return allfeatures.urlArr[] + */ + public File urlArr(int i) { + return urlArr.get(i).value(); + } + + /** * @return allfeatures.intMap{} */ public Map<String, Integer> intMap() { @@ -952,6 +1025,21 @@ public final class AllfeaturesConfig extends ConfigInstance { } /** + * @return allfeatures.urlMap{} + */ + public Map<String, File> urlMap() { + return LeafNodeMaps.asValueMap(urlMap); + } + + /** + * @param key the key of the value to return + * @return allfeatures.urlMap{} + */ + public File urlMap(String key) { + return urlMap.get(key).value(); + } + + /** * @return allfeatures.basic_struct */ public Basic_struct basic_struct() { diff --git a/vespajlib/src/main/java/com/yahoo/net/URI.java b/vespajlib/src/main/java/com/yahoo/net/URI.java index 2497154fffe..491fab5205e 100644 --- a/vespajlib/src/main/java/com/yahoo/net/URI.java +++ b/vespajlib/src/main/java/com/yahoo/net/URI.java @@ -179,7 +179,7 @@ public class URI implements Cloneable, java.io.Serializable, Comparable<URI> { /** * Normalizes this hierarchical uri according to FRC 2396 and the Overture - * standard. Before normalizing, some simple heuritics are use to make + * standard. Before normalizing, some simple heuristics are use to make * the uri complete if needed. After normalizing, the scheme, * host, port and rest of this uri is set if defined. * |