Adding ability for Config to be backed by generic JsonNode, i.e. either ObjectNode or ArrayNode.
Change-Id: I5f9ec423cd5f23f61c97a57073d9d11071c47997
diff --git a/apps/routing-api/src/main/java/org/onosproject/routing/config/BgpConfig.java b/apps/routing-api/src/main/java/org/onosproject/routing/config/BgpConfig.java
index 54e2e0e..19107be 100644
--- a/apps/routing-api/src/main/java/org/onosproject/routing/config/BgpConfig.java
+++ b/apps/routing-api/src/main/java/org/onosproject/routing/config/BgpConfig.java
@@ -46,7 +46,7 @@
public Set<BgpSpeakerConfig> bgpSpeakers() {
Set<BgpSpeakerConfig> speakers = Sets.newHashSet();
- JsonNode speakersNode = node.get(SPEAKERS);
+ JsonNode speakersNode = object.get(SPEAKERS);
speakersNode.forEach(jsonNode -> {
Set<IpAddress> listenAddresses = Sets.newHashSet();
jsonNode.path(PEERS).forEach(addressNode ->
diff --git a/cli/src/main/java/org/onosproject/cli/cfg/NetworkConfigCommand.java b/cli/src/main/java/org/onosproject/cli/cfg/NetworkConfigCommand.java
index a254e47..5f2f86e 100644
--- a/cli/src/main/java/org/onosproject/cli/cfg/NetworkConfigCommand.java
+++ b/cli/src/main/java/org/onosproject/cli/cfg/NetworkConfigCommand.java
@@ -15,6 +15,7 @@
*/
package org.onosproject.cli.cfg;
+import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.apache.karaf.shell.commands.Argument;
@@ -51,17 +52,17 @@
@Override
protected void execute() {
service = get(NetworkConfigService.class);
- ObjectNode root = new ObjectMapper().createObjectNode();
+ JsonNode root = new ObjectMapper().createObjectNode();
if (isNullOrEmpty(subjectKey)) {
- addAll(root);
+ addAll((ObjectNode) root);
} else {
SubjectFactory subjectFactory = service.getSubjectFactory(subjectKey);
if (isNullOrEmpty(subject)) {
- addSubjectClass(root, subjectFactory);
+ addSubjectClass((ObjectNode) root, subjectFactory);
} else {
Object s = subjectFactory.createSubject(subject);
if (isNullOrEmpty(configKey)) {
- addSubject(root, s);
+ addSubject((ObjectNode) root, s);
} else {
root = getSubjectConfig(getConfig(s, subjectKey, configKey));
}
@@ -89,7 +90,7 @@
service.getConfigs(s).forEach(c -> root.set(c.key(), c.node()));
}
- private ObjectNode getSubjectConfig(Config config) {
+ private JsonNode getSubjectConfig(Config config) {
return config != null ? config.node() : null;
}
diff --git a/core/api/src/main/java/org/onosproject/net/config/Config.java b/core/api/src/main/java/org/onosproject/net/config/Config.java
index ee7b584..068ff88 100644
--- a/core/api/src/main/java/org/onosproject/net/config/Config.java
+++ b/core/api/src/main/java/org/onosproject/net/config/Config.java
@@ -15,6 +15,7 @@
*/
package org.onosproject.net.config;
+import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
@@ -41,8 +42,12 @@
protected S subject;
protected String key;
- protected ObjectNode node;
+
+ protected JsonNode node;
+ protected ObjectNode object;
+ protected ArrayNode array;
protected ObjectMapper mapper;
+
protected ConfigApplyDelegate delegate;
/**
@@ -50,15 +55,17 @@
*
* @param subject configuration subject
* @param key configuration key
- * @param node JSON object node where configuration data is stored
+ * @param node JSON node where configuration data is stored
* @param mapper JSON object mapper
* @param delegate delegate context
*/
- public void init(S subject, String key, ObjectNode node, ObjectMapper mapper,
+ public void init(S subject, String key, JsonNode node, ObjectMapper mapper,
ConfigApplyDelegate delegate) {
this.subject = checkNotNull(subject);
this.key = key;
this.node = checkNotNull(node);
+ this.object = node instanceof ObjectNode ? (ObjectNode) node : null;
+ this.array = node instanceof ArrayNode ? (ArrayNode) node : null;
this.mapper = checkNotNull(mapper);
this.delegate = checkNotNull(delegate);
}
@@ -88,8 +95,8 @@
*
* @return JSON node backing the configuration
*/
- public ObjectNode node() {
- return node;
+ public JsonNode node() {
+ return object;
}
/**
@@ -110,7 +117,7 @@
* @return property value or default value
*/
protected String get(String name, String defaultValue) {
- return node.path(name).asText(defaultValue);
+ return object.path(name).asText(defaultValue);
}
/**
@@ -122,9 +129,9 @@
*/
protected Config<S> setOrClear(String name, String value) {
if (value != null) {
- node.put(name, value);
+ object.put(name, value);
} else {
- node.remove(name);
+ object.remove(name);
}
return this;
}
@@ -137,7 +144,7 @@
* @return property value or default value
*/
protected boolean get(String name, boolean defaultValue) {
- return node.path(name).asBoolean(defaultValue);
+ return object.path(name).asBoolean(defaultValue);
}
/**
@@ -149,9 +156,9 @@
*/
protected Config<S> setOrClear(String name, Boolean value) {
if (value != null) {
- node.put(name, value.booleanValue());
+ object.put(name, value.booleanValue());
} else {
- node.remove(name);
+ object.remove(name);
}
return this;
}
@@ -164,7 +171,7 @@
* @return property value or default value
*/
protected int get(String name, int defaultValue) {
- return node.path(name).asInt(defaultValue);
+ return object.path(name).asInt(defaultValue);
}
/**
@@ -176,9 +183,9 @@
*/
protected Config<S> setOrClear(String name, Integer value) {
if (value != null) {
- node.put(name, value.intValue());
+ object.put(name, value.intValue());
} else {
- node.remove(name);
+ object.remove(name);
}
return this;
}
@@ -191,7 +198,7 @@
* @return property value or default value
*/
protected long get(String name, long defaultValue) {
- return node.path(name).asLong(defaultValue);
+ return object.path(name).asLong(defaultValue);
}
/**
@@ -203,9 +210,9 @@
*/
protected Config<S> setOrClear(String name, Long value) {
if (value != null) {
- node.put(name, value.longValue());
+ object.put(name, value.longValue());
} else {
- node.remove(name);
+ object.remove(name);
}
return this;
}
@@ -218,7 +225,7 @@
* @return property value or default value
*/
protected double get(String name, double defaultValue) {
- return node.path(name).asDouble(defaultValue);
+ return object.path(name).asDouble(defaultValue);
}
/**
@@ -230,9 +237,9 @@
*/
protected Config<S> setOrClear(String name, Double value) {
if (value != null) {
- node.put(name, value.doubleValue());
+ object.put(name, value.doubleValue());
} else {
- node.remove(name);
+ object.remove(name);
}
return this;
}
@@ -247,7 +254,7 @@
* @return property value or default value
*/
protected <E extends Enum<E>> E get(String name, E defaultValue, Class<E> enumClass) {
- return Enum.valueOf(enumClass, node.path(name).asText(defaultValue.toString()));
+ return Enum.valueOf(enumClass, object.path(name).asText(defaultValue.toString()));
}
/**
@@ -260,9 +267,9 @@
*/
protected <E extends Enum> Config<S> setOrClear(String name, E value) {
if (value != null) {
- node.put(name, value.toString());
+ object.put(name, value.toString());
} else {
- node.remove(name);
+ object.remove(name);
}
return this;
}
@@ -277,7 +284,7 @@
*/
protected <T> List<T> getList(String name, Function<String, T> function) {
List<T> list = Lists.newArrayList();
- ArrayNode arrayNode = (ArrayNode) node.path(name);
+ ArrayNode arrayNode = (ArrayNode) object.path(name);
arrayNode.forEach(i -> list.add(function.apply(i.asText())));
return list;
}
@@ -293,11 +300,11 @@
*/
protected <T> Config<S> setOrClear(String name, Collection<T> collection) {
if (collection == null) {
- node.remove(name);
+ object.remove(name);
} else {
ArrayNode arrayNode = mapper.createArrayNode();
collection.forEach(i -> arrayNode.add(i.toString()));
- node.set(name, arrayNode);
+ object.set(name, arrayNode);
}
return this;
}
diff --git a/core/api/src/main/java/org/onosproject/net/config/ConfigFactory.java b/core/api/src/main/java/org/onosproject/net/config/ConfigFactory.java
index f8b72df..25a3402 100644
--- a/core/api/src/main/java/org/onosproject/net/config/ConfigFactory.java
+++ b/core/api/src/main/java/org/onosproject/net/config/ConfigFactory.java
@@ -30,6 +30,7 @@
private final SubjectFactory<S> subjectFactory;
private final Class<C> configClass;
private final String configKey;
+ private final boolean isList;
/**
* Creates a new configuration factory for the specified class of subjects
@@ -38,14 +39,37 @@
* composite JSON trees.
*
* @param subjectFactory subject factory
- * @param configClass configuration class
- * @param configKey configuration class key
+ * @param configClass configuration class
+ * @param configKey configuration class key
*/
protected ConfigFactory(SubjectFactory<S> subjectFactory,
Class<C> configClass, String configKey) {
+ this(subjectFactory, configClass, configKey, false);
+ }
+
+ /**
+ * Creates a new configuration factory for the specified class of subjects
+ * capable of generating the configurations of the specified class. The
+ * subject and configuration class keys are used merely as keys for use in
+ * composite JSON trees.
+ * <p>
+ * Note that configurations backed by JSON array are not easily extensible
+ * at the top-level as they are inherently limited to holding an ordered
+ * list of items.
+ * </p>
+ *
+ * @param subjectFactory subject factory
+ * @param configClass configuration class
+ * @param configKey configuration class key
+ * @param isList true to indicate backing by JSON array
+ */
+ protected ConfigFactory(SubjectFactory<S> subjectFactory,
+ Class<C> configClass, String configKey,
+ boolean isList) {
this.subjectFactory = subjectFactory;
this.configClass = configClass;
this.configKey = configKey;
+ this.isList = isList;
}
/**
@@ -85,4 +109,14 @@
*/
public abstract C createConfig();
+ /**
+ * Indicates whether the configuration is a list and should be backed by
+ * a JSON array rather than JSON object.
+ *
+ * @return true if backed by JSON array
+ */
+ public boolean isList() {
+ return isList;
+ }
+
}
diff --git a/core/api/src/main/java/org/onosproject/net/config/NetworkConfigService.java b/core/api/src/main/java/org/onosproject/net/config/NetworkConfigService.java
index 465751b..c1eed98 100644
--- a/core/api/src/main/java/org/onosproject/net/config/NetworkConfigService.java
+++ b/core/api/src/main/java/org/onosproject/net/config/NetworkConfigService.java
@@ -15,7 +15,7 @@
*/
package org.onosproject.net.config;
-import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.fasterxml.jackson.databind.JsonNode;
import com.google.common.annotations.Beta;
import org.onosproject.event.ListenerService;
@@ -130,7 +130,7 @@
* @return configuration or null if one is not available
*/
<S, C extends Config<S>> C applyConfig(S subject, Class<C> configClass,
- ObjectNode json);
+ JsonNode json);
/**
* Clears any configuration for the specified subject and configuration
diff --git a/core/api/src/main/java/org/onosproject/net/config/NetworkConfigStore.java b/core/api/src/main/java/org/onosproject/net/config/NetworkConfigStore.java
index c06fe6d..9dd66e8 100644
--- a/core/api/src/main/java/org/onosproject/net/config/NetworkConfigStore.java
+++ b/core/api/src/main/java/org/onosproject/net/config/NetworkConfigStore.java
@@ -15,7 +15,7 @@
*/
package org.onosproject.net.config;
-import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.fasterxml.jackson.databind.JsonNode;
import org.onosproject.store.Store;
import java.util.Set;
@@ -115,7 +115,7 @@
* @return configuration object
*/
<S, C extends Config<S>> C applyConfig(S subject, Class<C> configClass,
- ObjectNode json);
+ JsonNode json);
/**
* Clears the configuration of the given class for the specified subject.
diff --git a/core/api/src/main/java/org/onosproject/net/config/basics/OpticalPortConfig.java b/core/api/src/main/java/org/onosproject/net/config/basics/OpticalPortConfig.java
index d0ad5c3..b06c422 100644
--- a/core/api/src/main/java/org/onosproject/net/config/basics/OpticalPortConfig.java
+++ b/core/api/src/main/java/org/onosproject/net/config/basics/OpticalPortConfig.java
@@ -33,7 +33,7 @@
* @return the port type, or null if invalid or unset
*/
public Port.Type type() {
- JsonNode type = node.path(TYPE);
+ JsonNode type = object.path(TYPE);
if (type.isMissingNode()) {
return null;
}
@@ -72,7 +72,7 @@
}
private String getStringValue(String field) {
- JsonNode name = node.path(field);
+ JsonNode name = object.path(field);
return name.isMissingNode() ? "" : name.asText();
}
@@ -84,7 +84,7 @@
* @return an Optional that may contain a frequency value.
*/
public Optional<Long> staticLambda() {
- JsonNode sl = node.path(STATIC_LAMBDA);
+ JsonNode sl = object.path(STATIC_LAMBDA);
if (sl.isMissingNode()) {
return Optional.empty();
}
@@ -98,7 +98,7 @@
* @return a port speed value whose default is 0.
*/
public Optional<Integer> speed() {
- JsonNode s = node.path(SPEED);
+ JsonNode s = object.path(SPEED);
if (s.isMissingNode()) {
return Optional.empty();
}
diff --git a/core/api/src/test/java/org/onosproject/net/config/NetworkConfigServiceAdapter.java b/core/api/src/test/java/org/onosproject/net/config/NetworkConfigServiceAdapter.java
index 06632ca..b70d14e 100644
--- a/core/api/src/test/java/org/onosproject/net/config/NetworkConfigServiceAdapter.java
+++ b/core/api/src/test/java/org/onosproject/net/config/NetworkConfigServiceAdapter.java
@@ -1,4 +1,3 @@
-
/*
* Copyright 2015 Open Networking Laboratory
*
@@ -14,10 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package org.onosproject.net.config;
-import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.fasterxml.jackson.databind.JsonNode;
import java.util.Set;
@@ -71,7 +69,7 @@
}
@Override
- public <S, C extends Config<S>> C applyConfig(S subject, Class<C> configClass, ObjectNode json) {
+ public <S, C extends Config<S>> C applyConfig(S subject, Class<C> configClass, JsonNode json) {
return null;
}
diff --git a/core/net/src/main/java/org/onosproject/net/config/impl/NetworkConfigManager.java b/core/net/src/main/java/org/onosproject/net/config/impl/NetworkConfigManager.java
index 5c6cc0e..5cd96ca 100644
--- a/core/net/src/main/java/org/onosproject/net/config/impl/NetworkConfigManager.java
+++ b/core/net/src/main/java/org/onosproject/net/config/impl/NetworkConfigManager.java
@@ -15,7 +15,7 @@
*/
package org.onosproject.net.config.impl;
-import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.fasterxml.jackson.databind.JsonNode;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import org.apache.felix.scr.annotations.Activate;
@@ -197,7 +197,7 @@
}
@Override
- public <S, C extends Config<S>> C applyConfig(S subject, Class<C> configClass, ObjectNode json) {
+ public <S, C extends Config<S>> C applyConfig(S subject, Class<C> configClass, JsonNode json) {
checkNotNull(subject, NULL_SUBJECT_MSG);
checkNotNull(configClass, NULL_CCLASS_MSG);
return store.applyConfig(subject, configClass, json);
diff --git a/core/store/dist/src/main/java/org/onosproject/store/config/impl/DistributedNetworkConfigStore.java b/core/store/dist/src/main/java/org/onosproject/store/config/impl/DistributedNetworkConfigStore.java
index b33f32a..3e73d8f 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/config/impl/DistributedNetworkConfigStore.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/config/impl/DistributedNetworkConfigStore.java
@@ -15,6 +15,7 @@
*/
package org.onosproject.store.config.impl;
+import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.BooleanNode;
@@ -77,12 +78,12 @@
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected StorageService storageService;
- private ConsistentMap<ConfigKey, ObjectNode> configs;
+ private ConsistentMap<ConfigKey, JsonNode> configs;
private final Map<String, ConfigFactory> factoriesByConfig = Maps.newConcurrentMap();
private final ObjectMapper mapper = new ObjectMapper();
private final ConfigApplyDelegate applyDelegate = new InternalApplyDelegate();
- private final MapEventListener<ConfigKey, ObjectNode> listener = new InternalMapListener();
+ private final MapEventListener<ConfigKey, JsonNode> listener = new InternalMapListener();
@Activate
public void activate() {
@@ -93,7 +94,7 @@
TextNode.class, BooleanNode.class,
LongNode.class, DoubleNode.class, ShortNode.class, IntNode.class);
- configs = storageService.<ConfigKey, ObjectNode>consistentMapBuilder()
+ configs = storageService.<ConfigKey, JsonNode>consistentMapBuilder()
.withSerializer(Serializer.using(kryoBuilder.build()))
.withName("onos-network-configs")
.withRelaxedReadConsistency()
@@ -168,21 +169,24 @@
@Override
public <S, T extends Config<S>> T getConfig(S subject, Class<T> configClass) {
// TODO: need to identify and address the root cause for timeouts.
- Versioned<ObjectNode> json = Tools.retryable(configs::get, ConsistentMapException.class, 1, MAX_BACKOFF)
- .apply(key(subject, configClass));
+ Versioned<JsonNode> json = Tools.retryable(configs::get, ConsistentMapException.class, 1, MAX_BACKOFF)
+ .apply(key(subject, configClass));
return json != null ? createConfig(subject, configClass, json.value()) : null;
}
@Override
public <S, C extends Config<S>> C createConfig(S subject, Class<C> configClass) {
- Versioned<ObjectNode> json = configs.computeIfAbsent(key(subject, configClass),
- k -> mapper.createObjectNode());
+ ConfigFactory<S, C> factory = getConfigFactory(configClass);
+ Versioned<JsonNode> json = configs.computeIfAbsent(key(subject, configClass),
+ k -> factory.isList() ?
+ mapper.createArrayNode() :
+ mapper.createObjectNode());
return createConfig(subject, configClass, json.value());
}
@Override
- public <S, C extends Config<S>> C applyConfig(S subject, Class<C> configClass, ObjectNode json) {
+ public <S, C extends Config<S>> C applyConfig(S subject, Class<C> configClass, JsonNode json) {
return createConfig(subject, configClass,
configs.putAndGet(key(subject, configClass), json).value());
}
@@ -203,7 +207,7 @@
*/
@SuppressWarnings("unchecked")
private <S, C extends Config<S>> C createConfig(S subject, Class<C> configClass,
- ObjectNode json) {
+ JsonNode json) {
if (json != null) {
ConfigFactory<S, C> factory = factoriesByConfig.get(configClass.getName());
if (factory != null) {
@@ -259,9 +263,9 @@
}
}
- private class InternalMapListener implements MapEventListener<ConfigKey, ObjectNode> {
+ private class InternalMapListener implements MapEventListener<ConfigKey, JsonNode> {
@Override
- public void event(MapEvent<ConfigKey, ObjectNode> event) {
+ public void event(MapEvent<ConfigKey, JsonNode> event) {
NetworkConfigEvent.Type type;
switch (event.type()) {
case INSERT:
diff --git a/incubator/api/src/main/java/org/onosproject/incubator/net/config/basics/InterfaceConfig.java b/incubator/api/src/main/java/org/onosproject/incubator/net/config/basics/InterfaceConfig.java
index 600fe3d..acda179 100644
--- a/incubator/api/src/main/java/org/onosproject/incubator/net/config/basics/InterfaceConfig.java
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/config/basics/InterfaceConfig.java
@@ -50,7 +50,8 @@
Set<Interface> interfaces = Sets.newHashSet();
try {
- for (JsonNode intfNode : node.path(INTERFACES)) {
+ // TODO: rework this to take advantage of ArrayNode backing
+ for (JsonNode intfNode : object.path(INTERFACES)) {
Set<InterfaceIpAddress> ips = getIps(intfNode);
if (ips.isEmpty()) {
throw new ConfigException(IP_MISSING_ERROR);