Committed by
Gerrit Code Review
Allow list-type config to be POSTed to subjectkey/subject/configkey endpoint.
Also add validation that the given JSON node is appropriate for the config type (list vs object). Change-Id: Ib1c12b538860a6f18b8311c5f5a786608c04beb8
Showing
2 changed files
with
60 additions
and
33 deletions
... | @@ -61,7 +61,11 @@ import java.util.Objects; | ... | @@ -61,7 +61,11 @@ import java.util.Objects; |
61 | import java.util.Set; | 61 | import java.util.Set; |
62 | 62 | ||
63 | import static com.google.common.base.Preconditions.checkArgument; | 63 | import static com.google.common.base.Preconditions.checkArgument; |
64 | -import static org.onosproject.net.config.NetworkConfigEvent.Type.*; | 64 | +import static org.onosproject.net.config.NetworkConfigEvent.Type.CONFIG_ADDED; |
65 | +import static org.onosproject.net.config.NetworkConfigEvent.Type.CONFIG_REGISTERED; | ||
66 | +import static org.onosproject.net.config.NetworkConfigEvent.Type.CONFIG_REMOVED; | ||
67 | +import static org.onosproject.net.config.NetworkConfigEvent.Type.CONFIG_UNREGISTERED; | ||
68 | +import static org.onosproject.net.config.NetworkConfigEvent.Type.CONFIG_UPDATED; | ||
65 | 69 | ||
66 | /** | 70 | /** |
67 | * Implementation of a distributed network configuration store. | 71 | * Implementation of a distributed network configuration store. |
... | @@ -77,6 +81,10 @@ public class DistributedNetworkConfigStore | ... | @@ -77,6 +81,10 @@ public class DistributedNetworkConfigStore |
77 | private static final int MAX_BACKOFF = 10; | 81 | private static final int MAX_BACKOFF = 10; |
78 | private static final String INVALID_CONFIG_JSON = | 82 | private static final String INVALID_CONFIG_JSON = |
79 | "JSON node does not contain valid configuration"; | 83 | "JSON node does not contain valid configuration"; |
84 | + private static final String INVALID_JSON_LIST = | ||
85 | + "JSON node is not a list for list type config"; | ||
86 | + private static final String INVALID_JSON_OBJECT = | ||
87 | + "JSON node is not an object for object type config"; | ||
80 | 88 | ||
81 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 89 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
82 | protected StorageService storageService; | 90 | protected StorageService storageService; |
... | @@ -262,47 +270,67 @@ public class DistributedNetworkConfigStore | ... | @@ -262,47 +270,67 @@ public class DistributedNetworkConfigStore |
262 | * @return config object or null of no factory found or if the specified | 270 | * @return config object or null of no factory found or if the specified |
263 | * JSON is null | 271 | * JSON is null |
264 | */ | 272 | */ |
265 | - @SuppressWarnings("unchecked") | ||
266 | private <S, C extends Config<S>> C createConfig(S subject, Class<C> configClass, | 273 | private <S, C extends Config<S>> C createConfig(S subject, Class<C> configClass, |
267 | JsonNode json) { | 274 | JsonNode json) { |
268 | - if (json != null) { | 275 | + return createConfig(subject, configClass, json, false); |
269 | - ConfigFactory<S, C> factory = factoriesByConfig.get(configClass.getName()); | ||
270 | - if (factory != null) { | ||
271 | - C config = factory.createConfig(); | ||
272 | - config.init(subject, factory.configKey(), json, mapper, applyDelegate); | ||
273 | - return config; | ||
274 | - } | ||
275 | - } | ||
276 | - return null; | ||
277 | } | 276 | } |
278 | 277 | ||
279 | /** | 278 | /** |
280 | - * Produces a detached config from the specified subject, config class and | 279 | + * Produces a config from the specified subject, config class and raw JSON. |
281 | - * raw JSON. | ||
282 | * | 280 | * |
283 | - * A detached config can no longer be applied. This should be used only for | 281 | + * The config can optionally be detached, which means it does not contain a |
284 | - * passing the config object in the NetworkConfigEvent. | 282 | + * reference to an apply delegate. This means a detached config can not be |
283 | + * applied. This should be used only for passing the config object in the | ||
284 | + * NetworkConfigEvent. | ||
285 | * | 285 | * |
286 | * @param subject config subject | 286 | * @param subject config subject |
287 | * @param configClass config class | 287 | * @param configClass config class |
288 | * @param json raw JSON data | 288 | * @param json raw JSON data |
289 | + * @param detached whether the config should be detached, that is, should | ||
290 | + * be created without setting an apply delegate. | ||
289 | * @return config object or null of no factory found or if the specified | 291 | * @return config object or null of no factory found or if the specified |
290 | * JSON is null | 292 | * JSON is null |
291 | */ | 293 | */ |
292 | @SuppressWarnings("unchecked") | 294 | @SuppressWarnings("unchecked") |
293 | - private Config createDetachedConfig(Object subject, | 295 | + private <S, C extends Config<S>> C createConfig(S subject, Class<C> configClass, |
294 | - Class configClass, JsonNode json) { | 296 | + JsonNode json, boolean detached) { |
295 | if (json != null) { | 297 | if (json != null) { |
296 | - ConfigFactory factory = factoriesByConfig.get(configClass.getName()); | 298 | + ConfigFactory<S, C> factory = factoriesByConfig.get(configClass.getName()); |
297 | if (factory != null) { | 299 | if (factory != null) { |
298 | - Config config = factory.createConfig(); | 300 | + validateJsonType(json, factory); |
299 | - config.init(subject, factory.configKey(), json, mapper, null); | 301 | + C config = factory.createConfig(); |
302 | + config.init(subject, factory.configKey(), json, mapper, | ||
303 | + detached ? null : applyDelegate); | ||
300 | return config; | 304 | return config; |
301 | } | 305 | } |
302 | } | 306 | } |
303 | return null; | 307 | return null; |
304 | } | 308 | } |
305 | 309 | ||
310 | + /** | ||
311 | + * Validates that the type of the JSON node is appropriate for the type of | ||
312 | + * configuration. A list type configuration must be created with an | ||
313 | + * ArrayNode, and an object type configuration must be created with an | ||
314 | + * ObjectNode. | ||
315 | + * | ||
316 | + * @param json JSON node to check | ||
317 | + * @param factory config factory of configuration | ||
318 | + * @param <S> subject | ||
319 | + * @param <C> configuration | ||
320 | + * @return true if the JSON node type is appropriate for the configuration | ||
321 | + */ | ||
322 | + private <S, C extends Config<S>> boolean validateJsonType(JsonNode json, | ||
323 | + ConfigFactory<S, C> factory) { | ||
324 | + if (factory.isList() && !(json instanceof ArrayNode)) { | ||
325 | + throw new IllegalArgumentException(INVALID_JSON_LIST); | ||
326 | + } | ||
327 | + if (!factory.isList() && !(json instanceof ObjectNode)) { | ||
328 | + throw new IllegalArgumentException(INVALID_JSON_OBJECT); | ||
329 | + } | ||
330 | + | ||
331 | + return true; | ||
332 | + } | ||
333 | + | ||
306 | 334 | ||
307 | // Auxiliary delegate to receive notifications about changes applied to | 335 | // Auxiliary delegate to receive notifications about changes applied to |
308 | // the network configuration - by the apps. | 336 | // the network configuration - by the apps. |
... | @@ -380,10 +408,10 @@ public class DistributedNetworkConfigStore | ... | @@ -380,10 +408,10 @@ public class DistributedNetworkConfigStore |
380 | Versioned<JsonNode> oldValue = event.oldValue(); | 408 | Versioned<JsonNode> oldValue = event.oldValue(); |
381 | 409 | ||
382 | Config config = (newValue != null) ? | 410 | Config config = (newValue != null) ? |
383 | - createDetachedConfig(subject, configClass, newValue.value()) : | 411 | + createConfig(subject, configClass, newValue.value(), true) : |
384 | null; | 412 | null; |
385 | Config prevConfig = (oldValue != null) ? | 413 | Config prevConfig = (oldValue != null) ? |
386 | - createDetachedConfig(subject, configClass, oldValue.value()) : | 414 | + createConfig(subject, configClass, oldValue.value(), true) : |
387 | null; | 415 | null; |
388 | 416 | ||
389 | NetworkConfigEvent.Type type; | 417 | NetworkConfigEvent.Type type; | ... | ... |
... | @@ -15,9 +15,12 @@ | ... | @@ -15,9 +15,12 @@ |
15 | */ | 15 | */ |
16 | package org.onosproject.rest.resources; | 16 | package org.onosproject.rest.resources; |
17 | 17 | ||
18 | -import java.io.IOException; | 18 | +import com.fasterxml.jackson.databind.JsonNode; |
19 | -import java.io.InputStream; | 19 | +import com.fasterxml.jackson.databind.node.ObjectNode; |
20 | -import java.util.Set; | 20 | +import org.onosproject.net.config.Config; |
21 | +import org.onosproject.net.config.NetworkConfigService; | ||
22 | +import org.onosproject.net.config.SubjectFactory; | ||
23 | +import org.onosproject.rest.AbstractWebResource; | ||
21 | 24 | ||
22 | import javax.ws.rs.Consumes; | 25 | import javax.ws.rs.Consumes; |
23 | import javax.ws.rs.DELETE; | 26 | import javax.ws.rs.DELETE; |
... | @@ -28,13 +31,9 @@ import javax.ws.rs.PathParam; | ... | @@ -28,13 +31,9 @@ import javax.ws.rs.PathParam; |
28 | import javax.ws.rs.Produces; | 31 | import javax.ws.rs.Produces; |
29 | import javax.ws.rs.core.MediaType; | 32 | import javax.ws.rs.core.MediaType; |
30 | import javax.ws.rs.core.Response; | 33 | import javax.ws.rs.core.Response; |
31 | - | 34 | +import java.io.IOException; |
32 | -import org.onosproject.net.config.Config; | 35 | +import java.io.InputStream; |
33 | -import org.onosproject.net.config.NetworkConfigService; | 36 | +import java.util.Set; |
34 | -import org.onosproject.net.config.SubjectFactory; | ||
35 | -import org.onosproject.rest.AbstractWebResource; | ||
36 | - | ||
37 | -import com.fasterxml.jackson.databind.node.ObjectNode; | ||
38 | 37 | ||
39 | import static org.onlab.util.Tools.emptyIsNotFound; | 38 | import static org.onlab.util.Tools.emptyIsNotFound; |
40 | import static org.onlab.util.Tools.nullIsNotFound; | 39 | import static org.onlab.util.Tools.nullIsNotFound; |
... | @@ -263,7 +262,7 @@ public class NetworkConfigWebResource extends AbstractWebResource { | ... | @@ -263,7 +262,7 @@ public class NetworkConfigWebResource extends AbstractWebResource { |
263 | @PathParam("configKey") String configKey, | 262 | @PathParam("configKey") String configKey, |
264 | InputStream request) throws IOException { | 263 | InputStream request) throws IOException { |
265 | NetworkConfigService service = get(NetworkConfigService.class); | 264 | NetworkConfigService service = get(NetworkConfigService.class); |
266 | - ObjectNode root = (ObjectNode) mapper().readTree(request); | 265 | + JsonNode root = mapper().readTree(request); |
267 | service.applyConfig(subjectClassKey, | 266 | service.applyConfig(subjectClassKey, |
268 | service.getSubjectFactory(subjectClassKey).createSubject(subjectKey), | 267 | service.getSubjectFactory(subjectClassKey).createSubject(subjectKey), |
269 | configKey, root); | 268 | configKey, root); | ... | ... |
-
Please register or login to post a comment