summaryrefslogtreecommitdiffstats
path: root/config-model/src/main/java/com/yahoo/config
diff options
context:
space:
mode:
Diffstat (limited to 'config-model/src/main/java/com/yahoo/config')
-rw-r--r--config-model/src/main/java/com/yahoo/config/model/ApplicationConfigProducerRoot.java11
-rw-r--r--config-model/src/main/java/com/yahoo/config/model/ConfigModelContext.java14
-rw-r--r--config-model/src/main/java/com/yahoo/config/model/ConfigModelRepo.java6
-rw-r--r--config-model/src/main/java/com/yahoo/config/model/admin/AdminModel.java6
-rw-r--r--config-model/src/main/java/com/yahoo/config/model/builder/xml/ConfigModelBuilder.java4
-rw-r--r--config-model/src/main/java/com/yahoo/config/model/producer/AbstractConfigProducerRoot.java2
-rw-r--r--config-model/src/main/java/com/yahoo/config/model/producer/AnyConfigProducer.java (renamed from config-model/src/main/java/com/yahoo/config/model/producer/AbstractConfigProducer.java)169
-rw-r--r--config-model/src/main/java/com/yahoo/config/model/producer/TreeConfigProducer.java199
-rw-r--r--config-model/src/main/java/com/yahoo/config/model/producer/UserConfigRepo.java2
-rw-r--r--config-model/src/main/java/com/yahoo/config/model/test/MockRoot.java7
10 files changed, 257 insertions, 163 deletions
diff --git a/config-model/src/main/java/com/yahoo/config/model/ApplicationConfigProducerRoot.java b/config-model/src/main/java/com/yahoo/config/model/ApplicationConfigProducerRoot.java
index 6a474b84161..052bb7e968a 100644
--- a/config-model/src/main/java/com/yahoo/config/model/ApplicationConfigProducerRoot.java
+++ b/config-model/src/main/java/com/yahoo/config/model/ApplicationConfigProducerRoot.java
@@ -13,7 +13,8 @@ import com.yahoo.cloud.config.log.LogdConfig;
import com.yahoo.component.Version;
import com.yahoo.config.model.api.ModelContext;
import com.yahoo.config.model.deploy.DeployState;
-import com.yahoo.config.model.producer.AbstractConfigProducer;
+import com.yahoo.config.model.producer.AnyConfigProducer;
+import com.yahoo.config.model.producer.TreeConfigProducer;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.document.config.DocumenttypesConfig;
import com.yahoo.document.config.DocumentmanagerConfig;
@@ -49,7 +50,7 @@ import java.util.Set;
*
* @author gjoranv
*/
-public class ApplicationConfigProducerRoot extends AbstractConfigProducer<AbstractConfigProducer<?>> implements CommonConfigsProducer {
+public class ApplicationConfigProducerRoot extends TreeConfigProducer<TreeConfigProducer<?>> implements CommonConfigsProducer {
private final DocumentModel documentModel;
private Routing routing = null;
@@ -68,7 +69,7 @@ public class ApplicationConfigProducerRoot extends AbstractConfigProducer<Abstra
* @param name the name, used as configId
* @param documentModel DocumentModel to serve global document config from.
*/
- public ApplicationConfigProducerRoot(AbstractConfigProducer parent, String name, DocumentModel documentModel, Version vespaVersion, ApplicationId applicationId) {
+ public ApplicationConfigProducerRoot(TreeConfigProducer parent, String name, DocumentModel documentModel, Version vespaVersion, ApplicationId applicationId) {
super(parent, name);
this.documentModel = documentModel;
this.vespaVersion = vespaVersion;
@@ -120,8 +121,8 @@ public class ApplicationConfigProducerRoot extends AbstractConfigProducer<Abstra
*
* @param descendant The configProducer descendant to add
*/
- // TODO: Make protected if this moves to the same package as AbstractConfigProducer
- public void addDescendant(AbstractConfigProducer descendant) {
+ // TODO: Make protected if this moves to the same package as TreeConfigProducer
+ public void addDescendant(AnyConfigProducer descendant) {
id2producer.put(descendant.getConfigId(), descendant);
}
diff --git a/config-model/src/main/java/com/yahoo/config/model/ConfigModelContext.java b/config-model/src/main/java/com/yahoo/config/model/ConfigModelContext.java
index d0b0a6ea451..4692c2c1fba 100644
--- a/config-model/src/main/java/com/yahoo/config/model/ConfigModelContext.java
+++ b/config-model/src/main/java/com/yahoo/config/model/ConfigModelContext.java
@@ -5,7 +5,7 @@ import com.yahoo.config.application.api.ApplicationPackage;
import com.yahoo.config.application.api.DeployLogger;
import com.yahoo.config.model.api.ModelContext;
import com.yahoo.config.model.deploy.DeployState;
-import com.yahoo.config.model.producer.AbstractConfigProducer;
+import com.yahoo.config.model.producer.TreeConfigProducer;
import com.yahoo.vespa.model.VespaModel;
import java.util.stream.Stream;
@@ -18,7 +18,7 @@ import java.util.stream.Stream;
*/
public final class ConfigModelContext {
- private final AbstractConfigProducer<?> parent;
+ private final TreeConfigProducer<?> parent;
private final String producerId;
private final DeployState deployState;
private final VespaModel vespaModel;
@@ -29,7 +29,7 @@ public final class ConfigModelContext {
DeployState deployState,
VespaModel vespaModel,
ConfigModelRepoAdder configModelRepoAdder,
- AbstractConfigProducer<?> parent,
+ TreeConfigProducer<?> parent,
String producerId) {
this.applicationType = applicationType;
this.deployState = deployState;
@@ -41,7 +41,7 @@ public final class ConfigModelContext {
public ApplicationPackage getApplicationPackage() { return deployState.getApplicationPackage(); }
public String getProducerId() { return producerId; }
- public AbstractConfigProducer<?> getParentProducer() { return parent; }
+ public TreeConfigProducer<?> getParentProducer() { return parent; }
public DeployLogger getDeployLogger() { return deployState.getDeployLogger(); }
public DeployState getDeployState() { return deployState; }
public ApplicationType getApplicationType() { return applicationType; }
@@ -53,7 +53,7 @@ public final class ConfigModelContext {
public ConfigModelRepoAdder getConfigModelRepoAdder() { return configModelRepoAdder; }
/** Create a new context with a different parent */
- public ConfigModelContext withParent(AbstractConfigProducer<?> newParent) {
+ public ConfigModelContext withParent(TreeConfigProducer<?> newParent) {
return ConfigModelContext.create(deployState, vespaModel, configModelRepoAdder, newParent, producerId);
}
@@ -77,7 +77,7 @@ public final class ConfigModelContext {
public static ConfigModelContext create(DeployState deployState,
VespaModel vespaModel,
ConfigModelRepoAdder configModelRepoAdder,
- AbstractConfigProducer<?> parent,
+ TreeConfigProducer<?> parent,
String producerId) {
return new ConfigModelContext(ApplicationType.DEFAULT, deployState, vespaModel, configModelRepoAdder, parent, producerId);
}
@@ -95,7 +95,7 @@ public final class ConfigModelContext {
DeployState deployState,
VespaModel vespaModel,
ConfigModelRepoAdder configModelRepoAdder,
- AbstractConfigProducer<?> parent,
+ TreeConfigProducer<?> parent,
String producerId) {
return new ConfigModelContext(applicationType, deployState, vespaModel, configModelRepoAdder, parent, producerId);
}
diff --git a/config-model/src/main/java/com/yahoo/config/model/ConfigModelRepo.java b/config-model/src/main/java/com/yahoo/config/model/ConfigModelRepo.java
index 756646beddb..fc04ab6acc3 100644
--- a/config-model/src/main/java/com/yahoo/config/model/ConfigModelRepo.java
+++ b/config-model/src/main/java/com/yahoo/config/model/ConfigModelRepo.java
@@ -9,7 +9,7 @@ import com.yahoo.config.model.builder.xml.XmlHelper;
import com.yahoo.config.model.deploy.DeployState;
import com.yahoo.config.model.graph.ModelGraphBuilder;
import com.yahoo.config.model.graph.ModelNode;
-import com.yahoo.config.model.producer.AbstractConfigProducer;
+import com.yahoo.config.model.producer.TreeConfigProducer;
import com.yahoo.config.model.provision.HostsXmlProvisioner;
import com.yahoo.text.XML;
import com.yahoo.vespa.model.VespaModel;
@@ -172,7 +172,7 @@ public class ConfigModelRepo implements ConfigModelRepoAdder, Serializable, Iter
ApplicationType applicationType,
DeployState deployState,
VespaModel vespaModel,
- AbstractConfigProducer parent,
+ TreeConfigProducer parent,
List<Element> elements) {
for (Element servicesElement : elements) {
ConfigModel model = buildModel(node, applicationType, deployState, vespaModel, parent, servicesElement);
@@ -185,7 +185,7 @@ public class ConfigModelRepo implements ConfigModelRepoAdder, Serializable, Iter
ApplicationType applicationType,
DeployState deployState,
VespaModel vespaModel,
- AbstractConfigProducer parent,
+ TreeConfigProducer parent,
Element servicesElement) {
ConfigModelBuilder builder = node.builder;
ConfigModelContext context = ConfigModelContext.create(applicationType, deployState, vespaModel, this, parent, getIdString(servicesElement));
diff --git a/config-model/src/main/java/com/yahoo/config/model/admin/AdminModel.java b/config-model/src/main/java/com/yahoo/config/model/admin/AdminModel.java
index 7fe7c4b9f68..d4fb96e3f19 100644
--- a/config-model/src/main/java/com/yahoo/config/model/admin/AdminModel.java
+++ b/config-model/src/main/java/com/yahoo/config/model/admin/AdminModel.java
@@ -9,7 +9,7 @@ import com.yahoo.config.model.api.ModelContext;
import com.yahoo.config.model.builder.xml.ConfigModelBuilder;
import com.yahoo.config.model.builder.xml.ConfigModelId;
import com.yahoo.config.model.deploy.DeployState;
-import com.yahoo.config.model.producer.AbstractConfigProducer;
+import com.yahoo.config.model.producer.TreeConfigProducer;
import com.yahoo.vespa.model.admin.Admin;
import com.yahoo.vespa.model.builder.xml.dom.DomAdminV2Builder;
import com.yahoo.vespa.model.builder.xml.dom.DomAdminV4Builder;
@@ -80,7 +80,7 @@ public class AdminModel extends ConfigModel {
new BuilderV4().doBuild(model, adminElement, modelContext);
return;
}
- AbstractConfigProducer<?> parent = modelContext.getParentProducer();
+ TreeConfigProducer<?> parent = modelContext.getParentProducer();
ModelContext.Properties properties = modelContext.getDeployState().getProperties();
DomAdminV2Builder domBuilder = new DomAdminV2Builder(modelContext.getApplicationType(),
properties.multitenant(),
@@ -109,7 +109,7 @@ public class AdminModel extends ConfigModel {
@Override
public void doBuild(AdminModel model, Element adminElement, ConfigModelContext modelContext) {
- AbstractConfigProducer<?> parent = modelContext.getParentProducer();
+ TreeConfigProducer<?> parent = modelContext.getParentProducer();
ModelContext.Properties properties = modelContext.getDeployState().getProperties();
DomAdminV4Builder domBuilder = new DomAdminV4Builder(modelContext,
properties.multitenant(),
diff --git a/config-model/src/main/java/com/yahoo/config/model/builder/xml/ConfigModelBuilder.java b/config-model/src/main/java/com/yahoo/config/model/builder/xml/ConfigModelBuilder.java
index 656f78ba2a9..c968006a5b6 100644
--- a/config-model/src/main/java/com/yahoo/config/model/builder/xml/ConfigModelBuilder.java
+++ b/config-model/src/main/java/com/yahoo/config/model/builder/xml/ConfigModelBuilder.java
@@ -8,7 +8,7 @@ import com.yahoo.config.model.ConfigModelInstanceFactory;
import com.yahoo.config.model.ConfigModelRepo;
import com.yahoo.config.model.api.ConfigModelPlugin;
import com.yahoo.config.model.deploy.DeployState;
-import com.yahoo.config.model.producer.AbstractConfigProducer;
+import com.yahoo.config.model.producer.TreeConfigProducer;
import com.yahoo.vespa.model.VespaModel;
import org.w3c.dom.Element;
@@ -55,7 +55,7 @@ public abstract class ConfigModelBuilder<MODEL extends ConfigModel> extends Abst
* @param spec the XML element this is constructed from
*/
public final MODEL build(DeployState deployState, VespaModel vespaModel, ConfigModelRepo configModelRepo,
- AbstractConfigProducer<?> parent, Element spec) {
+ TreeConfigProducer<?> parent, Element spec) {
ConfigModelContext context = ConfigModelContext.create(deployState, vespaModel, configModelRepo, parent, getIdString(spec));
return build(new DefaultModelInstanceFactory(), spec, context);
}
diff --git a/config-model/src/main/java/com/yahoo/config/model/producer/AbstractConfigProducerRoot.java b/config-model/src/main/java/com/yahoo/config/model/producer/AbstractConfigProducerRoot.java
index d6c03a0f668..6dd94028e9c 100644
--- a/config-model/src/main/java/com/yahoo/config/model/producer/AbstractConfigProducerRoot.java
+++ b/config-model/src/main/java/com/yahoo/config/model/producer/AbstractConfigProducerRoot.java
@@ -15,7 +15,7 @@ import java.util.Optional;
*
* @author Tony Vaagenes
*/
-public abstract class AbstractConfigProducerRoot extends AbstractConfigProducer<AbstractConfigProducer<?>>
+public abstract class AbstractConfigProducerRoot extends TreeConfigProducer<TreeConfigProducer<?>>
implements ConfigProducerRoot {
/** The ConfigProducers contained in this model indexed by config id */
diff --git a/config-model/src/main/java/com/yahoo/config/model/producer/AbstractConfigProducer.java b/config-model/src/main/java/com/yahoo/config/model/producer/AnyConfigProducer.java
index b86230c97e6..2cfe1590ad9 100644
--- a/config-model/src/main/java/com/yahoo/config/model/producer/AbstractConfigProducer.java
+++ b/config-model/src/main/java/com/yahoo/config/model/producer/AnyConfigProducer.java
@@ -34,34 +34,32 @@ import java.util.logging.Logger;
*
* @author gjoranv
*/
-public abstract class AbstractConfigProducer<CHILD extends AbstractConfigProducer<?>>
+public abstract class AnyConfigProducer
implements ConfigProducer, ConfigInstance.Producer, Serializable {
private static final long serialVersionUID = 1L;
- public static final Logger log = Logger.getLogger(AbstractConfigProducer.class.getPackage().toString());
+ public static final Logger log = Logger.getLogger(AnyConfigProducer.class.getPackage().toString());
private final String subId;
private String configId = null;
private final List<Service> descendantServices = new ArrayList<>();
- private AbstractConfigProducer parent = null;
+ private TreeConfigProducer parent = null;
private UserConfigRepo userConfigs = new UserConfigRepo();
- private final FreezableMap<String, CHILD> childrenBySubId = new FreezableMap<>(LinkedHashMap.class);
-
protected static boolean stateIsHosted(DeployState deployState) {
return (deployState != null) && deployState.isHosted();
}
/**
- * Creates a new AbstractConfigProducer with the given parent and subId.
+ * Creates a new AnyConfigProducer with the given parent and subId.
* This constructor will add the resulting producer to the children of parent.
*
* @param parent the parent of this ConfigProducer
* @param subId the fragment of the config id for the producer
*/
- public AbstractConfigProducer(AbstractConfigProducer parent, String subId) {
+ public AnyConfigProducer(TreeConfigProducer parent, String subId) {
this(subId);
if (parent != null) {
parent.addChild(this);
@@ -74,7 +72,7 @@ public abstract class AbstractConfigProducer<CHILD extends AbstractConfigProduce
parent.removeChild(this);
}
- protected final void setParent(AbstractConfigProducer<?> parent) {
+ protected final void setParent(TreeConfigProducer parent) {
this.parent = parent;
computeConfigId();
}
@@ -83,11 +81,11 @@ public abstract class AbstractConfigProducer<CHILD extends AbstractConfigProduce
/**
* Create an config producer with a configId only. Used e.g. to create root nodes, and producers
- * that are given children after construction using {@link #addChild(AbstractConfigProducer)}.
+ * that are given parents after construction using {@link TreeConfigProducer#addChild(AnyConfigProducer)}.
*
* @param subId The sub configId. Note that this can be prefixed when calling addChild with this producer as arg.
*/
- public AbstractConfigProducer(String subId) {
+ public AnyConfigProducer(String subId) {
if (subId.indexOf('/') != -1) {
throw new IllegalArgumentException("A subId might not contain '/' : '" + subId + "'");
}
@@ -95,49 +93,9 @@ public abstract class AbstractConfigProducer<CHILD extends AbstractConfigProduce
}
/**
- * Adds a child to this config producer.
- *
- * @param child the child config producer to add
- */
- protected void addChild(CHILD child) {
- if (child == null) {
- throw new IllegalArgumentException("Trying to add null child for: " + this);
- }
- if (child instanceof AbstractConfigProducerRoot) {
- throw new IllegalArgumentException("Child cannot be a root node: " + child);
- }
-
- child.setParent(this);
- if (childrenBySubId.get(child.getSubId()) != null) {
- throw new IllegalArgumentException("Multiple services/instances of the id '" + child.getSubId() + "' under the service/instance " +
- errorMsgClassName() + " '" + subId + "'. (This is commonly caused by service/node index " +
- "collisions in the config.)." +
- "\nExisting instance: " + childrenBySubId.get(child.getSubId()) +
- "\nAttempted to add: " + child);
- }
- childrenBySubId.put(child.getSubId(), child);
-
- if (child instanceof Service) {
- addDescendantService((Service)child);
- }
- }
-
- public void removeChild(CHILD child) {
- if (child.getParent() != this)
- throw new IllegalArgumentException("Could not remove " + child + ": Expected its parent to be " +
- this + ", but was " + child.getParent());
-
- if (child instanceof Service)
- descendantServices.remove(child);
-
- childrenBySubId.remove(child.getSubId());
- child.setParent(null);
- }
-
- /**
* Helper to provide an error message on collisions of sub ids (ignore SimpleConfigProducer, use the parent in that case)
*/
- private String errorMsgClassName() {
+ protected String errorMsgClassName() {
if (getClass().equals(SimpleConfigProducer.class)) return parent.getClass().getSimpleName();
return getClass().getSimpleName();
}
@@ -163,6 +121,10 @@ public abstract class AbstractConfigProducer<CHILD extends AbstractConfigProduce
return configId;
}
+ protected final String currentConfigId() {
+ return configId;
+ }
+
/**
* Sets the config id for this producer. Will also add this
* service to the root node, so the new config id will be picked
@@ -176,30 +138,6 @@ public abstract class AbstractConfigProducer<CHILD extends AbstractConfigProduce
getVespa().addDescendant(this);
}
- /** Returns this ConfigProducer's children (only 1st level) */
- public Map<String, CHILD> getChildren() { return Collections.unmodifiableMap(childrenBySubId); }
-
- @Beta
- public <J extends AbstractConfigProducer<?>> List<J> getChildrenByTypeRecursive(Class<J> type) {
- List<J> validChildren = new ArrayList<>();
-
- if (this.getClass().equals(type)) {
- validChildren.add(type.cast(this));
- }
-
- Map<String, ? extends AbstractConfigProducer<?>> children = this.getChildren();
- for (AbstractConfigProducer<?> child : children.values()) {
- validChildren.addAll(child.getChildrenByTypeRecursive(type));
- }
-
- return Collections.unmodifiableList(validChildren);
- }
-
- /** Returns a list of all the children of this who are instances of Service */
- public List<Service> getDescendantServices() { return Collections.unmodifiableList(descendantServices); }
-
- protected void addDescendantService(Service s) { descendantServices.add(s); }
-
@Override
public final boolean cascadeConfig(ConfigInstance.Builder builder) {
boolean found = false;
@@ -271,7 +209,11 @@ public abstract class AbstractConfigProducer<CHILD extends AbstractConfigProduce
*/
private ApplicationConfigProducerRoot getVespa() {
if (isRoot()) return null;
- return isVespa() ? (ApplicationConfigProducerRoot)this : parent.getVespa();
+ if (isVespa()) {
+ return (ApplicationConfigProducerRoot)this;
+ } else {
+ return getParent().getVespa();
+ }
}
private boolean isRoot() {
@@ -279,19 +221,10 @@ public abstract class AbstractConfigProducer<CHILD extends AbstractConfigProduce
}
private boolean isVespa() {
- return ((this instanceof ApplicationConfigProducerRoot) && parent.isRoot());
+ return ((this instanceof ApplicationConfigProducerRoot) && getParent().isRoot());
}
- public AbstractConfigProducer getParent() { return parent; }
-
- public void dump(PrintStream out) {
- for (ConfigProducer c : getChildren().values()) {
- out.println("id: " + c.getConfigId());
- if (c.getChildren().size() > 0) {
- c.dump(out);
- }
- }
- }
+ public AnyConfigProducer getParent() { return parent; }
void setupConfigId(String parentConfigId) {
if (this instanceof AbstractConfigProducerRoot) {
@@ -301,15 +234,6 @@ public abstract class AbstractConfigProducer<CHILD extends AbstractConfigProduce
addConfigId(configId);
}
computeConfigId();
- setupChildConfigIds(getConfigIdPrefix());
- }
-
- private String getConfigIdPrefix() {
- if (this instanceof AbstractConfigProducerRoot || this instanceof ApplicationConfigProducerRoot) {
- return "";
- }
- if (configId == null) return null;
- return configId + "/";
}
private void computeConfigId() {
@@ -328,7 +252,7 @@ public abstract class AbstractConfigProducer<CHILD extends AbstractConfigProduce
}
}
- private static ClassLoader findInheritedClassLoader(Class clazz, String producerName) {
+ protected static ClassLoader findInheritedClassLoader(Class clazz, String producerName) {
Class<?>[] interfazes = clazz.getInterfaces();
for (Class interfaze : interfazes) {
if (producerName.equals(interfaze.getName())) {
@@ -341,53 +265,13 @@ public abstract class AbstractConfigProducer<CHILD extends AbstractConfigProduce
}
protected ClassLoader getConfigClassLoader(String producerName) {
- ClassLoader classLoader = findInheritedClassLoader(getClass(), producerName);
- if (classLoader != null)
- return classLoader;
-
- // TODO: Make logic correct, so that the deepest child will be the one winning.
- for (AbstractConfigProducer child : childrenBySubId.values()) {
- ClassLoader loader = child.getConfigClassLoader(producerName);
- if (loader != null) {
- return loader;
- }
- }
- return null;
- }
-
- private void setupChildConfigIds(String currentConfigId) {
- for (AbstractConfigProducer child : childrenBySubId.values()) {
- child.setupConfigId(currentConfigId);
- }
- }
-
- void aggregateDescendantServices() {
- for (AbstractConfigProducer child : childrenBySubId.values()) {
- child.aggregateDescendantServices();
- descendantServices.addAll(child.descendantServices);
- }
- }
-
- void freeze() {
- childrenBySubId.freeze();
- for (AbstractConfigProducer child : childrenBySubId.values()) {
- child.freeze();
- }
+ return findInheritedClassLoader(getClass(), producerName);
}
public void mergeUserConfigs(UserConfigRepo newRepo) {
userConfigs.merge(newRepo);
}
- @Override
- public void validate() throws Exception {
- assert (childrenBySubId.isFrozen());
-
- for (AbstractConfigProducer<?> child : childrenBySubId.values()) {
- child.validate();
- }
- }
-
// TODO: Make producers depend on AdminModel instead
/** Returns a monitoring service if configured, null otherwise */
protected Monitoring getMonitoringService() {
@@ -401,4 +285,13 @@ public abstract class AbstractConfigProducer<CHILD extends AbstractConfigProduce
}
return null;
}
+
+ // NOPs for all config producers without children; overridden in TreeConfigProducer
+ void aggregateDescendantServices() { }
+ public List<Service> getDescendantServices() { return List.of(); }
+ <J extends AnyConfigProducer> List<J> getChildrenByTypeRecursive(Class<J> type) { return List.of(); }
+ void freeze() { }
+ @Override
+ public void validate() throws Exception { }
+
}
diff --git a/config-model/src/main/java/com/yahoo/config/model/producer/TreeConfigProducer.java b/config-model/src/main/java/com/yahoo/config/model/producer/TreeConfigProducer.java
new file mode 100644
index 00000000000..6b632572250
--- /dev/null
+++ b/config-model/src/main/java/com/yahoo/config/model/producer/TreeConfigProducer.java
@@ -0,0 +1,199 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.config.model.producer;
+
+import com.yahoo.api.annotations.Beta;
+import com.yahoo.config.ConfigInstance;
+import com.yahoo.config.model.ApplicationConfigProducerRoot;
+import com.yahoo.config.model.deploy.DeployState;
+import com.yahoo.config.subscription.ConfigInstanceUtil;
+import com.yahoo.vespa.config.ConfigDefinitionKey;
+import com.yahoo.vespa.config.ConfigPayload;
+import com.yahoo.vespa.config.ConfigPayloadBuilder;
+import com.yahoo.vespa.config.ConfigTransformer;
+import com.yahoo.vespa.config.GenericConfig;
+import com.yahoo.vespa.model.ConfigProducer;
+import com.yahoo.vespa.model.HostSystem;
+import com.yahoo.vespa.model.Service;
+import com.yahoo.vespa.model.SimpleConfigProducer;
+import com.yahoo.vespa.model.admin.Admin;
+import com.yahoo.vespa.model.admin.monitoring.Monitoring;
+import com.yahoo.vespa.model.utils.FreezableMap;
+import java.io.PrintStream;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Superclass for all config producers with children.
+ * Config producers constructs and returns config instances on request.
+ *
+ * @author gjoranv
+ */
+public abstract class TreeConfigProducer<CHILD extends AnyConfigProducer>
+ extends AnyConfigProducer
+{
+ private static final long serialVersionUID = 1L;
+ private final List<Service> descendantServices = new ArrayList<>();
+ private final FreezableMap<String, CHILD> childrenBySubId = new FreezableMap<>(LinkedHashMap.class);
+
+ /**
+ * Creates a new TreeConfigProducer with the given parent and subId.
+ * This constructor will add the resulting producer to the children of parent.
+ *
+ * @param parent the parent of this ConfigProducer
+ * @param subId the fragment of the config id for the producer
+ */
+ public TreeConfigProducer(TreeConfigProducer parent, String subId) {
+ super(parent, subId);
+ }
+
+ /**
+ * Create an config producer with a configId only. Used e.g. to create root nodes, and producers
+ * that are given children after construction using {@link #addChild(AnyConfigProducer)}.
+ *
+ * @param subId The sub configId. Note that this can be prefixed when calling addChild with this producer as arg.
+ */
+ public TreeConfigProducer(String subId) {
+ super(subId);
+ }
+
+ /**
+ * Adds a child to this config producer.
+ *
+ * @param child the child config producer to add
+ */
+ protected void addChild(CHILD child) {
+ if (child == null) {
+ throw new IllegalArgumentException("Trying to add null child for: " + this);
+ }
+ if (child instanceof AbstractConfigProducerRoot) {
+ throw new IllegalArgumentException("Child cannot be a root node: " + child);
+ }
+
+ child.setParent(this);
+ if (childrenBySubId.get(child.getSubId()) != null) {
+ throw new IllegalArgumentException("Multiple services/instances of the id '" + child.getSubId() + "' under the service/instance " +
+ errorMsgClassName() + " '" + getSubId() + "'. (This is commonly caused by service/node index " +
+ "collisions in the config.)." +
+ "\nExisting instance: " + childrenBySubId.get(child.getSubId()) +
+ "\nAttempted to add: " + child);
+ }
+ childrenBySubId.put(child.getSubId(), child);
+
+ if (child instanceof Service) {
+ addDescendantService((Service)child);
+ }
+ }
+
+ public void removeChild(CHILD child) {
+ if (child.getParent() != this)
+ throw new IllegalArgumentException("Could not remove " + child + ": Expected its parent to be " +
+ this + ", but was " + child.getParent());
+
+ if (child instanceof Service)
+ descendantServices.remove(child);
+
+ childrenBySubId.remove(child.getSubId());
+ child.setParent(null);
+ }
+
+ /** Returns this ConfigProducer's children (only 1st level) */
+ public Map<String, CHILD> getChildren() { return Collections.unmodifiableMap(childrenBySubId); }
+
+ @Beta
+ public <J extends AnyConfigProducer> List<J> getChildrenByTypeRecursive(Class<J> type) {
+ List<J> validChildren = new ArrayList<>();
+
+ if (this.getClass().equals(type)) {
+ validChildren.add(type.cast(this));
+ }
+
+ Map<String, CHILD> children = this.getChildren();
+ for (CHILD child : children.values()) {
+ validChildren.addAll(child.getChildrenByTypeRecursive(type));
+ }
+
+ return Collections.unmodifiableList(validChildren);
+ }
+
+ /** Returns a list of all the children of this who are instances of Service */
+ public List<Service> getDescendantServices() { return Collections.unmodifiableList(descendantServices); }
+
+ protected void addDescendantService(Service s) { descendantServices.add(s); }
+
+ public void dump(PrintStream out) {
+ for (ConfigProducer c : getChildren().values()) {
+ out.println("id: " + c.getConfigId());
+ if (c.getChildren().size() > 0) {
+ c.dump(out);
+ }
+ }
+ }
+
+ void setupConfigId(String parentConfigId) {
+ super.setupConfigId(parentConfigId);
+ setupChildConfigIds(getConfigIdPrefix());
+ }
+
+ String getConfigIdPrefix() {
+ if (this instanceof AbstractConfigProducerRoot || this instanceof ApplicationConfigProducerRoot) {
+ return "";
+ }
+ if (currentConfigId() == null) {
+ return null;
+ }
+ return getConfigId() + "/";
+ }
+
+ @Override
+ protected ClassLoader getConfigClassLoader(String producerName) {
+ ClassLoader classLoader = findInheritedClassLoader(getClass(), producerName);
+ if (classLoader != null)
+ return classLoader;
+
+ // TODO: Make logic correct, so that the deepest child will be the one winning.
+ for (AnyConfigProducer child : childrenBySubId.values()) {
+ ClassLoader loader = child.getConfigClassLoader(producerName);
+ if (loader != null) {
+ return loader;
+ }
+ }
+ return null;
+ }
+
+ private void setupChildConfigIds(String currentConfigId) {
+ for (AnyConfigProducer child : childrenBySubId.values()) {
+ child.setupConfigId(currentConfigId);
+ }
+ }
+
+ @Override
+ void aggregateDescendantServices() {
+ for (CHILD child : childrenBySubId.values()) {
+ child.aggregateDescendantServices();
+ descendantServices.addAll(child.getDescendantServices());
+ }
+ }
+
+ @Override
+ void freeze() {
+ childrenBySubId.freeze();
+ for (CHILD child : childrenBySubId.values()) {
+ child.freeze();
+ }
+ }
+
+ @Override
+ public void validate() throws Exception {
+ assert (childrenBySubId.isFrozen());
+ for (CHILD child : childrenBySubId.values()) {
+ child.validate();
+ }
+ }
+
+}
diff --git a/config-model/src/main/java/com/yahoo/config/model/producer/UserConfigRepo.java b/config-model/src/main/java/com/yahoo/config/model/producer/UserConfigRepo.java
index afa3e2de85f..3d7eafe658f 100644
--- a/config-model/src/main/java/com/yahoo/config/model/producer/UserConfigRepo.java
+++ b/config-model/src/main/java/com/yahoo/config/model/producer/UserConfigRepo.java
@@ -28,7 +28,7 @@ public class UserConfigRepo {
}
/**
- * Must copy the builder, because the merge method on {@link AbstractConfigProducer} might override the row's builders otherwise
+ * Must copy the builder, because the merge method on {@link TreeConfigProducer} might override the row's builders otherwise
*/
private Map<ConfigDefinitionKey, ConfigPayloadBuilder> copyBuilders(Map<ConfigDefinitionKey, ConfigPayloadBuilder> source) {
Map<ConfigDefinitionKey, ConfigPayloadBuilder> ret = new LinkedHashMap<>();
diff --git a/config-model/src/main/java/com/yahoo/config/model/test/MockRoot.java b/config-model/src/main/java/com/yahoo/config/model/test/MockRoot.java
index 80dca3776ae..f1113ee2d00 100644
--- a/config-model/src/main/java/com/yahoo/config/model/test/MockRoot.java
+++ b/config-model/src/main/java/com/yahoo/config/model/test/MockRoot.java
@@ -6,7 +6,8 @@ import com.yahoo.config.application.api.ApplicationPackage;
import com.yahoo.config.application.api.DeployLogger;
import com.yahoo.config.model.ConfigModelRepo;
import com.yahoo.config.model.deploy.DeployState;
-import com.yahoo.config.model.producer.AbstractConfigProducer;
+import com.yahoo.config.model.producer.AnyConfigProducer;
+import com.yahoo.config.model.producer.TreeConfigProducer;
import com.yahoo.config.model.producer.AbstractConfigProducerRoot;
import com.yahoo.vespa.model.ConfigProducer;
import com.yahoo.vespa.model.HostSystem;
@@ -95,7 +96,7 @@ public class MockRoot extends AbstractConfigProducerRoot {
public HostSystem hostSystem() { return hostSystem; }
- public void addDescendant(String configId, AbstractConfigProducer<?> descendant) {
+ public void addDescendant(String configId, AnyConfigProducer descendant) {
if (id2producer.containsKey(configId)) {
throw new RuntimeException
("Config ID '" + configId + "' cannot be reserved by an instance of class '" +
@@ -106,7 +107,7 @@ public class MockRoot extends AbstractConfigProducerRoot {
}
@Override
- public void addChild(AbstractConfigProducer<?> abstractConfigProducer) {
+ public void addChild(TreeConfigProducer<?> abstractConfigProducer) {
super.addChild(abstractConfigProducer);
}