1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.config.model.builder.xml;
import com.yahoo.component.AbstractComponent;
import com.yahoo.config.model.ConfigModel;
import com.yahoo.config.model.ConfigModelContext;
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.vespa.model.VespaModel;
import org.w3c.dom.Element;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
/**
* Builds a config model using DOM parsers
*
* @author vegardh
*/
public abstract class ConfigModelBuilder<MODEL extends ConfigModel> extends AbstractComponent implements ConfigModelPlugin {
private final Class<MODEL> configModelClass;
public ConfigModelBuilder(Class<MODEL> configModelClass) {
this.configModelClass = configModelClass;
}
/**
* Method that must return the XML elements this builder handles. Subclasses must implement this in order to
* get called when one of the elements have been encountered when parsing.
*
* @return a list of elements that this builder handles
*/
public abstract List<ConfigModelId> handlesElements();
/**
* Convenience hook called from {@link #build}. Implement this method to build a config model.
*
* @param spec the XML element that this builder should handle
* @param modelContext a model context that contains the application package and other data needed by the
* config model constructor
*/
public abstract void doBuild(MODEL model, Element spec, ConfigModelContext modelContext);
/**
* Builds an instance of this component model.
* This calls instantiate(...), instance.setUp(...), doBuild(instance, ...).
*
* @param deployState a global deployment state used for this model.
* @param parent the root config producer this should be added to
* @param spec the XML element this is constructed from
*/
public final MODEL build(DeployState deployState, VespaModel vespaModel, ConfigModelRepo configModelRepo,
AbstractConfigProducer<?> parent, Element spec) {
ConfigModelContext context = ConfigModelContext.create(deployState, vespaModel, configModelRepo, parent, getIdString(spec));
return build(new DefaultModelInstanceFactory(), spec, context);
}
/**
* Builds an instance of this component model.
* This calls instantiate(...), instance.setUp(...), doBuild(instance, ...).
*
* @param factory A factory capable of creating models.
* @param spec the XML element this is constructed from
* @param context A context object containing various data used by builders.
*/
public MODEL build(ConfigModelInstanceFactory<MODEL> factory, Element spec, ConfigModelContext context) {
MODEL model = factory.createModel(context);
doBuild(model, spec, context);
return model;
}
public Class<MODEL> getModelClass() {
return configModelClass;
}
private static String getIdString(Element spec) {
String idString = XmlHelper.getIdString(spec);
if (idString == null || idString.isEmpty()) {
idString = spec.getTagName();
}
return idString;
}
@Override
public boolean equals(Object other) {
if (!(other instanceof ConfigModelBuilder)) {
return false;
}
ConfigModelBuilder<?> otherBuilder = (ConfigModelBuilder<?>) other;
List<ConfigModelId> thisIds = this.handlesElements();
List<ConfigModelId> otherIds = otherBuilder.handlesElements();
if (thisIds.size() != otherIds.size()) {
return false;
}
for (int i = 0; i < thisIds.size(); i++) {
if (!thisIds.get(i).equals(otherIds.get(i))) {
return false;
}
}
return true;
}
private class DefaultModelInstanceFactory implements ConfigModelInstanceFactory<MODEL> {
@Override
public MODEL createModel(ConfigModelContext context) {
try {
Constructor<MODEL> constructor = configModelClass.getConstructor(ConfigModelContext.class);
return constructor.newInstance(context);
} catch (NoSuchMethodException | InvocationTargetException | InstantiationException | IllegalAccessException e) {
throw new RuntimeException("Error constructing model '" + configModelClass.getName() + "'", e);
}
}
}
}
|