blob: 98c9fe2567ffee526ef5b299bf16dacc3b95efe0 [file] [log] [blame]
Yuta HIGUCHI7438f5a2017-02-15 22:09:46 -08001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2017-present Open Networking Foundation
Yuta HIGUCHI7438f5a2017-02-15 22:09:46 -08003 *
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.ConnectPoint;
23import org.onosproject.net.config.BaseConfig;
Jordan Halterman83949a12017-06-21 10:35:38 -070024import org.onosproject.net.config.InvalidFieldException;
Yuta HIGUCHI7438f5a2017-02-15 22:09:46 -080025import 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 port via netcfg subsystem.
34 */
35public class PortAnnotationConfig
36 extends BaseConfig<ConnectPoint> {
37
38 /**
39 * {@value #CONFIG_KEY} : a netcfg ConfigKey for {@link PortAnnotationConfig}.
40 */
41 public static final String CONFIG_KEY = "annotations";
42
43 /**
44 * JSON key for annotation entries.
45 * Value is a JSON object.
46 */
47 private static final String ENTRIES = "entries";
48
49 private final Logger log = getLogger(getClass());
50
Jordan Halterman83949a12017-06-21 10:35:38 -070051 private static final int KEY_MAX_LENGTH = 1024;
52 private static final int VALUE_MAX_LENGTH = 1024;
53
Yuta HIGUCHI7438f5a2017-02-15 22:09:46 -080054 @Override
55 public boolean isValid() {
Jordan Halterman83949a12017-06-21 10:35:38 -070056 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 }
Yuta HIGUCHI7438f5a2017-02-15 22:09:46 -080069 return hasField(ENTRIES) && object.get(ENTRIES).isObject();
70 }
71
72 /**
73 * Returns annotations to add to a Port.
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 Port.
105 *
106 * @param replace annotations to be added by this configuration.
107 * null value represent key removal request
108 * @return self
109 */
110 public PortAnnotationConfig 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 PortAnnotationConfig 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 PortAnnotationConfig 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 PortAnnotationConfig}.
156 * <p>
157 * Note: created instance needs to be initialized by #init(..) before using.
158 */
159 public PortAnnotationConfig() {
160 super();
161 }
162
163 /**
164 * Create a detached {@link PortAnnotationConfig} for specified port.
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 cp ConnectPoint
171 */
172 public PortAnnotationConfig(ConnectPoint cp) {
173 ObjectMapper mapper = new ObjectMapper();
174 init(cp, CONFIG_KEY, mapper.createObjectNode(), mapper, null);
175 }
176}