blob: 14e6712e1478c98bd72d1f9d4aeeef31dd9f101c [file] [log] [blame]
Palash Kalaa06a6162017-11-15 20:42:40 +09001/*
2 * Copyright 2017-present Open Networking Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.net.config.basics;
17
18import static org.slf4j.LoggerFactory.getLogger;
19
20import java.util.HashMap;
21import java.util.Map;
22import org.onosproject.net.DeviceId;
23import org.onosproject.net.config.BaseConfig;
24import org.onosproject.net.config.InvalidFieldException;
25import org.slf4j.Logger;
26
27import com.fasterxml.jackson.core.JsonProcessingException;
28import com.fasterxml.jackson.databind.JsonNode;
29import com.fasterxml.jackson.databind.ObjectMapper;
30import com.fasterxml.jackson.databind.node.ObjectNode;
31
32/**
33 * Configuration to add extra annotations to a device via netcfg subsystem.
34 */
35public class DeviceAnnotationConfig
36 extends BaseConfig<DeviceId> {
37
38 /**
39 * {@value #CONFIG_KEY} : a netcfg ConfigKey for {@link DeviceAnnotationConfig}.
40 */
41 public static final String CONFIG_KEY = "annotations";
42
43 /**
44 * JSON key for annotation entries.
45 * Value is a String.
46 */
47 private static final String ENTRIES = "entries";
48
49 private final Logger log = getLogger(getClass());
50
51 private static final int KEY_MAX_LENGTH = 1024;
52 private static final int VALUE_MAX_LENGTH = 1024;
53
54 @Override
55 public boolean isValid() {
56 JsonNode jsonNode = object.path(ENTRIES);
57 if (jsonNode.isObject()) {
58 jsonNode.fields().forEachRemaining(entry -> {
59 if (entry.getKey().length() > KEY_MAX_LENGTH) {
60 throw new InvalidFieldException(entry.getKey(),
61 entry.getKey() + " exceeds maximum length " + KEY_MAX_LENGTH);
62 }
63 if (entry.getValue().asText("").length() > VALUE_MAX_LENGTH) {
64 throw new InvalidFieldException(entry.getKey(),
65 entry.getKey() + " exceeds maximum length " + VALUE_MAX_LENGTH);
66 }
67 });
68 }
69 return hasField(ENTRIES) && object.get(ENTRIES).isObject();
70 }
71
72 /**
73 * Returns annotations to add to a Device.
74 *
75 * @return annotations as a map. null value represent key removal request
76 */
77 public Map<String, String> annotations() {
78 Map<String, String> map = new HashMap<>();
79
80 JsonNode jsonNode = object.path(ENTRIES);
81 if (!jsonNode.isObject()) {
82 return map;
83 }
84
85 jsonNode.fields().forEachRemaining(entry -> {
86 String key = entry.getKey();
87 JsonNode value = entry.getValue();
88 if (value.isTextual()) {
89 map.put(key, value.asText());
90 } else if (value.isNull()) {
91 map.put(key, null);
92 } else {
93 try {
94 map.put(key, mapper().writeValueAsString(value));
95 } catch (JsonProcessingException e) {
96 log.warn("Error processing JSON value for {}.", key, e);
97 }
98 }
99 });
100 return map;
101 }
102
103 /**
104 * Sets annotations to add to a Device.
105 *
106 * @param replace annotations to be added by this configuration.
107 * null value represent key removal request
108 * @return self
109 */
110 public DeviceAnnotationConfig annotations(Map<String, String> replace) {
111 ObjectNode anns = object.objectNode();
112 if (replace != null) {
113 replace.forEach((k, v) -> {
114 anns.put(k, v);
115 });
116 }
117 object.set(ENTRIES, anns);
118 return this;
119 }
120
121 /**
122 * Add configuration to set or remove annotation entry.
123 *
124 * @param key annotations key
125 * @param value annotations value. specifying null removes the entry.
126 * @return self
127 */
128 public DeviceAnnotationConfig annotation(String key, String value) {
129 JsonNode ent = object.path(ENTRIES);
130 ObjectNode obj = (ent.isObject()) ? (ObjectNode) ent : object.objectNode();
131
132 obj.put(key, value);
133
134 object.set(ENTRIES, obj);
135 return this;
136 }
137
138 /**
139 * Remove configuration about specified key.
140 *
141 * @param key annotations key
142 * @return self
143 */
144 public DeviceAnnotationConfig annotation(String key) {
145 JsonNode ent = object.path(ENTRIES);
146 ObjectNode obj = (ent.isObject()) ? (ObjectNode) ent : object.objectNode();
147
148 obj.remove(key);
149
150 object.set(ENTRIES, obj);
151 return this;
152 }
153
154 /**
155 * Create a detached {@link DeviceAnnotationConfig}.
156 * <p>
157 * Note: created instance needs to be initialized by #init(..) before using.
158 */
159 public DeviceAnnotationConfig() {
160 super();
161 }
162
163 /**
164 * Create a detached {@link DeviceAnnotationConfig} for specified device.
165 * <p>
166 * Note: created instance is not bound to NetworkConfigService,
167 * thus cannot use {@link #apply()}. Must be passed to the service
168 * using NetworkConfigService#applyConfig
169 *
170 * @param deviceId Device id
171 */
172 public DeviceAnnotationConfig(DeviceId deviceId) {
173 ObjectMapper mapper = new ObjectMapper();
174 init(deviceId, CONFIG_KEY, mapper.createObjectNode(), mapper, null);
175 }
176}