blob: 5cdc0c12773798d37bd7a5a65e2f09a3757d570a [file] [log] [blame]
Thomas Vachuskaf0e1fae2015-04-24 00:51:51 -07001/*
2 * Copyright 2015 Open Networking Laboratory
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 */
Ray Milkeya4122362015-08-18 15:19:08 -070016package org.onosproject.net.config;
Thomas Vachuskaf0e1fae2015-04-24 00:51:51 -070017
Thomas Vachuska0a400ea2015-09-04 11:25:03 -070018import com.fasterxml.jackson.databind.JsonNode;
Thomas Vachuskaf0e1fae2015-04-24 00:51:51 -070019import com.fasterxml.jackson.databind.ObjectMapper;
Brian O'Connorce2d8b52015-07-29 16:24:13 -070020import com.fasterxml.jackson.databind.node.ArrayNode;
Thomas Vachuskaf0e1fae2015-04-24 00:51:51 -070021import com.fasterxml.jackson.databind.node.ObjectNode;
Thomas Vachuskae2b7e7e2015-05-20 11:11:31 -070022import com.google.common.annotations.Beta;
Brian O'Connorce2d8b52015-07-29 16:24:13 -070023import com.google.common.collect.Lists;
24
25import java.util.Collection;
26import java.util.List;
27import java.util.function.Function;
Thomas Vachuskaf0e1fae2015-04-24 00:51:51 -070028
29import static com.google.common.base.Preconditions.checkNotNull;
30
31/**
32 * Base abstraction of a configuration facade for a specific subject. Derived
Thomas Vachuska96d55b12015-05-11 08:52:03 -070033 * classes should keep all state in the specified JSON tree as that is the
34 * only state that will be distributed or persisted; this class is merely
35 * a facade for interacting with a particular facet of configuration on a
36 * given subject.
Thomas Vachuskaf0e1fae2015-04-24 00:51:51 -070037 *
38 * @param <S> type of subject
39 */
Thomas Vachuskae2b7e7e2015-05-20 11:11:31 -070040@Beta
Thomas Vachuskaf0e1fae2015-04-24 00:51:51 -070041public abstract class Config<S> {
42
Thomas Vachuska96d55b12015-05-11 08:52:03 -070043 protected S subject;
44 protected String key;
Thomas Vachuska0a400ea2015-09-04 11:25:03 -070045
46 protected JsonNode node;
47 protected ObjectNode object;
48 protected ArrayNode array;
Thomas Vachuska96d55b12015-05-11 08:52:03 -070049 protected ObjectMapper mapper;
Thomas Vachuska0a400ea2015-09-04 11:25:03 -070050
Thomas Vachuska96d55b12015-05-11 08:52:03 -070051 protected ConfigApplyDelegate delegate;
52
53 /**
54 * Initializes the configuration behaviour with necessary context.
55 *
56 * @param subject configuration subject
57 * @param key configuration key
Thomas Vachuska0a400ea2015-09-04 11:25:03 -070058 * @param node JSON node where configuration data is stored
Thomas Vachuska96d55b12015-05-11 08:52:03 -070059 * @param mapper JSON object mapper
60 * @param delegate delegate context
61 */
Thomas Vachuska0a400ea2015-09-04 11:25:03 -070062 public void init(S subject, String key, JsonNode node, ObjectMapper mapper,
Thomas Vachuska96d55b12015-05-11 08:52:03 -070063 ConfigApplyDelegate delegate) {
64 this.subject = checkNotNull(subject);
65 this.key = key;
66 this.node = checkNotNull(node);
Thomas Vachuska0a400ea2015-09-04 11:25:03 -070067 this.object = node instanceof ObjectNode ? (ObjectNode) node : null;
68 this.array = node instanceof ArrayNode ? (ArrayNode) node : null;
Thomas Vachuska96d55b12015-05-11 08:52:03 -070069 this.mapper = checkNotNull(mapper);
70 this.delegate = checkNotNull(delegate);
71 }
Thomas Vachuskaf0e1fae2015-04-24 00:51:51 -070072
73 /**
74 * Returns the specific subject to which this configuration pertains.
75 *
76 * @return configuration subject
77 */
Thomas Vachuska96d55b12015-05-11 08:52:03 -070078 public S subject() {
Thomas Vachuskaf0e1fae2015-04-24 00:51:51 -070079 return subject;
80 }
81
82 /**
Thomas Vachuska96d55b12015-05-11 08:52:03 -070083 * Returns the configuration key. This is primarily aimed for use in
84 * composite JSON trees in external representations and has no bearing on
85 * the internal behaviours.
Thomas Vachuskaf0e1fae2015-04-24 00:51:51 -070086 *
Thomas Vachuska96d55b12015-05-11 08:52:03 -070087 * @return configuration key
Thomas Vachuskaf0e1fae2015-04-24 00:51:51 -070088 */
Thomas Vachuska96d55b12015-05-11 08:52:03 -070089 public String key() {
90 return key;
91 }
92
93 /**
94 * Returns the JSON node that contains the configuration data.
95 *
96 * @return JSON node backing the configuration
97 */
Thomas Vachuska0a400ea2015-09-04 11:25:03 -070098 public JsonNode node() {
Jonathan Harta8625482015-09-08 16:14:56 -070099 return node;
Thomas Vachuskaf0e1fae2015-04-24 00:51:51 -0700100 }
101
102 /**
103 * Applies any configuration changes made via this configuration.
104 */
105 public void apply() {
106 delegate.onApply(this);
107 }
108
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700109
110 // Miscellaneous helpers for interacting with JSON
111
112 /**
113 * Gets the specified property as a string.
114 *
115 * @param name property name
116 * @param defaultValue default value if property not set
117 * @return property value or default value
118 */
119 protected String get(String name, String defaultValue) {
Thomas Vachuska0a400ea2015-09-04 11:25:03 -0700120 return object.path(name).asText(defaultValue);
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700121 }
122
123 /**
124 * Sets the specified property as a string or clears it if null value given.
125 *
126 * @param name property name
127 * @param value new value or null to clear the property
128 * @return self
129 */
130 protected Config<S> setOrClear(String name, String value) {
131 if (value != null) {
Thomas Vachuska0a400ea2015-09-04 11:25:03 -0700132 object.put(name, value);
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700133 } else {
Thomas Vachuska0a400ea2015-09-04 11:25:03 -0700134 object.remove(name);
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700135 }
136 return this;
137 }
138
139 /**
140 * Gets the specified property as a boolean.
141 *
142 * @param name property name
143 * @param defaultValue default value if property not set
144 * @return property value or default value
145 */
146 protected boolean get(String name, boolean defaultValue) {
Thomas Vachuska0a400ea2015-09-04 11:25:03 -0700147 return object.path(name).asBoolean(defaultValue);
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700148 }
149
150 /**
151 * Sets the specified property as a boolean or clears it if null value given.
152 *
153 * @param name property name
154 * @param value new value or null to clear the property
155 * @return self
156 */
157 protected Config<S> setOrClear(String name, Boolean value) {
158 if (value != null) {
Thomas Vachuska0a400ea2015-09-04 11:25:03 -0700159 object.put(name, value.booleanValue());
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700160 } else {
Thomas Vachuska0a400ea2015-09-04 11:25:03 -0700161 object.remove(name);
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700162 }
163 return this;
164 }
165
166 /**
Jonathan Hart111b42b2015-07-14 13:28:05 -0700167 * Gets the specified property as an integer.
168 *
169 * @param name property name
170 * @param defaultValue default value if property not set
171 * @return property value or default value
172 */
173 protected int get(String name, int defaultValue) {
Thomas Vachuska0a400ea2015-09-04 11:25:03 -0700174 return object.path(name).asInt(defaultValue);
Jonathan Hart111b42b2015-07-14 13:28:05 -0700175 }
176
177 /**
178 * Sets the specified property as an integer or clears it if null value given.
179 *
180 * @param name property name
181 * @param value new value or null to clear the property
182 * @return self
183 */
184 protected Config<S> setOrClear(String name, Integer value) {
185 if (value != null) {
Thomas Vachuska0a400ea2015-09-04 11:25:03 -0700186 object.put(name, value.intValue());
Jonathan Hart111b42b2015-07-14 13:28:05 -0700187 } else {
Thomas Vachuska0a400ea2015-09-04 11:25:03 -0700188 object.remove(name);
Jonathan Hart111b42b2015-07-14 13:28:05 -0700189 }
190 return this;
191 }
192
193 /**
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700194 * Gets the specified property as a long.
195 *
196 * @param name property name
197 * @param defaultValue default value if property not set
198 * @return property value or default value
199 */
200 protected long get(String name, long defaultValue) {
Thomas Vachuska0a400ea2015-09-04 11:25:03 -0700201 return object.path(name).asLong(defaultValue);
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700202 }
203
204 /**
205 * Sets the specified property as a long or clears it if null value given.
206 *
207 * @param name property name
208 * @param value new value or null to clear the property
209 * @return self
210 */
211 protected Config<S> setOrClear(String name, Long value) {
212 if (value != null) {
Thomas Vachuska0a400ea2015-09-04 11:25:03 -0700213 object.put(name, value.longValue());
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700214 } else {
Thomas Vachuska0a400ea2015-09-04 11:25:03 -0700215 object.remove(name);
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700216 }
217 return this;
218 }
219
220 /**
221 * Gets the specified property as a double.
222 *
223 * @param name property name
224 * @param defaultValue default value if property not set
225 * @return property value or default value
226 */
227 protected double get(String name, double defaultValue) {
Thomas Vachuska0a400ea2015-09-04 11:25:03 -0700228 return object.path(name).asDouble(defaultValue);
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700229 }
230
231 /**
232 * Sets the specified property as a double or clears it if null value given.
233 *
234 * @param name property name
235 * @param value new value or null to clear the property
236 * @return self
237 */
238 protected Config<S> setOrClear(String name, Double value) {
239 if (value != null) {
Thomas Vachuska0a400ea2015-09-04 11:25:03 -0700240 object.put(name, value.doubleValue());
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700241 } else {
Thomas Vachuska0a400ea2015-09-04 11:25:03 -0700242 object.remove(name);
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700243 }
244 return this;
245 }
246
247 /**
248 * Gets the specified property as an enum.
249 *
250 * @param name property name
251 * @param defaultValue default value if property not set
252 * @param enumClass the enum class
Thomas Vachuskad894b5d2015-07-30 11:59:07 -0700253 * @param <E> type of enum
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700254 * @return property value or default value
255 */
256 protected <E extends Enum<E>> E get(String name, E defaultValue, Class<E> enumClass) {
Thomas Vachuska0a400ea2015-09-04 11:25:03 -0700257 return Enum.valueOf(enumClass, object.path(name).asText(defaultValue.toString()));
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700258 }
259
260 /**
261 * Sets the specified property as a double or clears it if null value given.
262 *
263 * @param name property name
264 * @param value new value or null to clear the property
Thomas Vachuskad894b5d2015-07-30 11:59:07 -0700265 * @param <E> type of enum
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700266 * @return self
267 */
268 protected <E extends Enum> Config<S> setOrClear(String name, E value) {
269 if (value != null) {
Thomas Vachuska0a400ea2015-09-04 11:25:03 -0700270 object.put(name, value.toString());
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700271 } else {
Thomas Vachuska0a400ea2015-09-04 11:25:03 -0700272 object.remove(name);
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700273 }
274 return this;
275 }
Jonathan Hart111b42b2015-07-14 13:28:05 -0700276
Brian O'Connorce2d8b52015-07-29 16:24:13 -0700277 /**
278 * Gets the specified array property as a list of items.
279 *
Thomas Vachuskad894b5d2015-07-30 11:59:07 -0700280 * @param name property name
Brian O'Connorce2d8b52015-07-29 16:24:13 -0700281 * @param function mapper from string to item
Thomas Vachuskad894b5d2015-07-30 11:59:07 -0700282 * @param <T> type of item
Brian O'Connorce2d8b52015-07-29 16:24:13 -0700283 * @return list of items
284 */
285 protected <T> List<T> getList(String name, Function<String, T> function) {
286 List<T> list = Lists.newArrayList();
Thomas Vachuska0a400ea2015-09-04 11:25:03 -0700287 ArrayNode arrayNode = (ArrayNode) object.path(name);
Brian O'Connorce2d8b52015-07-29 16:24:13 -0700288 arrayNode.forEach(i -> list.add(function.apply(i.asText())));
289 return list;
290 }
291
292 /**
293 * Sets the specified property as an array of items in a given collection or
294 * clears it if null is given.
295 *
Thomas Vachuskad894b5d2015-07-30 11:59:07 -0700296 * @param name propertyName
Brian O'Connorce2d8b52015-07-29 16:24:13 -0700297 * @param collection collection of items
Thomas Vachuskad894b5d2015-07-30 11:59:07 -0700298 * @param <T> type of items
Brian O'Connorce2d8b52015-07-29 16:24:13 -0700299 * @return self
300 */
301 protected <T> Config<S> setOrClear(String name, Collection<T> collection) {
302 if (collection == null) {
Thomas Vachuska0a400ea2015-09-04 11:25:03 -0700303 object.remove(name);
Brian O'Connorce2d8b52015-07-29 16:24:13 -0700304 } else {
305 ArrayNode arrayNode = mapper.createArrayNode();
306 collection.forEach(i -> arrayNode.add(i.toString()));
Thomas Vachuska0a400ea2015-09-04 11:25:03 -0700307 object.set(name, arrayNode);
Brian O'Connorce2d8b52015-07-29 16:24:13 -0700308 }
309 return this;
310 }
311
Thomas Vachuskaf0e1fae2015-04-24 00:51:51 -0700312}