blob: 600b70310d7ad7ec12fbd64dc4c9e2b1c4ba2873 [file] [log] [blame]
Thomas Vachuska96d55b12015-05-11 08:52:03 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
Thomas Vachuska96d55b12015-05-11 08:52:03 -07003 *
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 */
Thomas Vachuska4998caa2015-08-26 13:28:38 -070016package org.onosproject.net.config.impl;
Thomas Vachuska96d55b12015-05-11 08:52:03 -070017
Thomas Vachuska0a400ea2015-09-04 11:25:03 -070018import com.fasterxml.jackson.databind.JsonNode;
Thomas Vachuska96d55b12015-05-11 08:52:03 -070019import com.google.common.collect.ImmutableSet;
20import com.google.common.collect.Maps;
21import org.apache.felix.scr.annotations.Activate;
22import org.apache.felix.scr.annotations.Component;
23import org.apache.felix.scr.annotations.Deactivate;
24import org.apache.felix.scr.annotations.Reference;
25import org.apache.felix.scr.annotations.ReferenceCardinality;
26import org.apache.felix.scr.annotations.Service;
Thomas Vachuska42e8cce2015-07-29 19:25:18 -070027import org.onosproject.event.AbstractListenerManager;
Ray Milkeya4122362015-08-18 15:19:08 -070028import org.onosproject.net.config.Config;
29import org.onosproject.net.config.ConfigFactory;
30import org.onosproject.net.config.NetworkConfigEvent;
31import org.onosproject.net.config.NetworkConfigListener;
32import org.onosproject.net.config.NetworkConfigRegistry;
33import org.onosproject.net.config.NetworkConfigService;
34import org.onosproject.net.config.NetworkConfigStore;
35import org.onosproject.net.config.NetworkConfigStoreDelegate;
36import org.onosproject.net.config.SubjectFactory;
Thomas Vachuska96d55b12015-05-11 08:52:03 -070037import org.slf4j.Logger;
38import org.slf4j.LoggerFactory;
39
40import java.util.Map;
41import java.util.Objects;
42import java.util.Set;
43
44import static com.google.common.base.Preconditions.checkNotNull;
Heedo Kang4a47a302016-02-29 17:40:23 +090045import static org.onosproject.security.AppGuard.checkPermission;
46import static org.onosproject.security.AppPermission.Type.*;
Thomas Vachuska96d55b12015-05-11 08:52:03 -070047
48/**
49 * Implementation of the network configuration subsystem.
50 */
51@Component(immediate = true)
52@Service
Thomas Vachuska42e8cce2015-07-29 19:25:18 -070053public class NetworkConfigManager
54 extends AbstractListenerManager<NetworkConfigEvent, NetworkConfigListener>
55 implements NetworkConfigRegistry, NetworkConfigService {
Thomas Vachuska96d55b12015-05-11 08:52:03 -070056
57 private final Logger log = LoggerFactory.getLogger(getClass());
58
59 private static final String NULL_FACTORY_MSG = "Factory cannot be null";
60 private static final String NULL_SCLASS_MSG = "Subject class cannot be null";
Simon Hunt3da1a182016-02-08 16:42:54 -080061 private static final String NULL_SCKEY_MSG = "Subject class key cannot be null";
Thomas Vachuska96d55b12015-05-11 08:52:03 -070062 private static final String NULL_CCLASS_MSG = "Config class cannot be null";
Thomas Vachuska6f350ed2016-01-08 09:53:03 -080063 private static final String NULL_CKEY_MSG = "Config key cannot be null";
Thomas Vachuska96d55b12015-05-11 08:52:03 -070064 private static final String NULL_SUBJECT_MSG = "Subject cannot be null";
Thomas Vachuska6f350ed2016-01-08 09:53:03 -080065 private static final String NULL_JSON_MSG = "JSON cannot be null";
Thomas Vachuska96d55b12015-05-11 08:52:03 -070066
67 // Inventory of configuration factories
68 private final Map<ConfigKey, ConfigFactory> factories = Maps.newConcurrentMap();
ke han31dd5b42017-06-23 13:35:09 +080069 private final Map<ConfigKey, Integer> factoryCounters = Maps.newConcurrentMap();
Thomas Vachuska96d55b12015-05-11 08:52:03 -070070
Ray Milkey0a4f6c32015-08-03 11:22:01 -070071 // Secondary indices to retrieve subject and config classes by keys
Thomas Vachuska96d55b12015-05-11 08:52:03 -070072 private final Map<String, SubjectFactory> subjectClasses = Maps.newConcurrentMap();
73 private final Map<Class, SubjectFactory> subjectClassKeys = Maps.newConcurrentMap();
Jonathan Hart111b42b2015-07-14 13:28:05 -070074 private final Map<ConfigIdentifier, Class<? extends Config>> configClasses = Maps.newConcurrentMap();
Thomas Vachuska96d55b12015-05-11 08:52:03 -070075
Thomas Vachuska96d55b12015-05-11 08:52:03 -070076 private final NetworkConfigStoreDelegate storeDelegate = new InternalStoreDelegate();
77
78 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
79 protected NetworkConfigStore store;
80
Thomas Vachuska96d55b12015-05-11 08:52:03 -070081
82 @Activate
83 public void activate() {
84 eventDispatcher.addSink(NetworkConfigEvent.class, listenerRegistry);
85 store.setDelegate(storeDelegate);
86 log.info("Started");
87 }
88
89 @Deactivate
90 public void deactivate() {
91 eventDispatcher.removeSink(NetworkConfigEvent.class);
92 store.unsetDelegate(storeDelegate);
93 log.info("Stopped");
94 }
95
96
97 @Override
98 @SuppressWarnings("unchecked")
99 public void registerConfigFactory(ConfigFactory configFactory) {
100 checkNotNull(configFactory, NULL_FACTORY_MSG);
ke han31dd5b42017-06-23 13:35:09 +0800101 if (factoryCounters.containsKey(key(configFactory))) {
102 factoryCounters.replace(key(configFactory), (factoryCounters.get(key(configFactory)) + 1));
103 } else {
104 factories.put(key(configFactory), configFactory);
105 factoryCounters.put(key(configFactory), 1);
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700106
ke han31dd5b42017-06-23 13:35:09 +0800107 configClasses.put(identifier(configFactory), configFactory.configClass());
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700108
ke han31dd5b42017-06-23 13:35:09 +0800109 SubjectFactory subjectFactory = configFactory.subjectFactory();
110 subjectClasses.putIfAbsent(subjectFactory.subjectClassKey(), subjectFactory);
111 subjectClassKeys.putIfAbsent(subjectFactory.subjectClass(), subjectFactory);
112
113 store.addConfigFactory(configFactory);
114 }
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700115 }
116
117 @Override
118 public void unregisterConfigFactory(ConfigFactory configFactory) {
119 checkNotNull(configFactory, NULL_FACTORY_MSG);
ke han31dd5b42017-06-23 13:35:09 +0800120 Integer factoryCounter = factoryCounters.get(key(configFactory));
121 if (factoryCounter > 1) {
122 factoryCounters.replace(key(configFactory), (factoryCounter - 1));
123 } else {
124 factoryCounters.remove(key(configFactory));
125 factories.remove(key(configFactory));
126 configClasses.remove(identifier(configFactory));
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700127
ke han31dd5b42017-06-23 13:35:09 +0800128 // Note that we are deliberately not removing subject factory key bindings.
129 store.removeConfigFactory(configFactory);
130 }
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700131 }
132
133 @Override
134 public Set<ConfigFactory> getConfigFactories() {
135 return ImmutableSet.copyOf(factories.values());
136 }
137
138
139 @Override
140 @SuppressWarnings("unchecked")
141 public <S, C extends Config<S>> Set<ConfigFactory<S, C>> getConfigFactories(Class<S> subjectClass) {
142 ImmutableSet.Builder<ConfigFactory<S, C>> builder = ImmutableSet.builder();
143 factories.forEach((key, factory) -> {
144 if (factory.subjectFactory().subjectClass().equals(subjectClass)) {
145 builder.add(factory);
146 }
147 });
148 return builder.build();
149 }
150
151 @Override
152 public <S, C extends Config<S>> ConfigFactory<S, C> getConfigFactory(Class<C> configClass) {
153 checkNotNull(configClass, NULL_CCLASS_MSG);
154 return store.getConfigFactory(configClass);
155 }
156
157
158 @Override
159 public Set<Class> getSubjectClasses() {
Heedo Kang4a47a302016-02-29 17:40:23 +0900160 checkPermission(CONFIG_READ);
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700161 ImmutableSet.Builder<Class> builder = ImmutableSet.builder();
162 factories.forEach((k, v) -> builder.add(k.subjectClass));
163 return builder.build();
164 }
165
166 @Override
Thomas Vachuskaea5adc62015-10-07 11:52:30 -0700167 public SubjectFactory getSubjectFactory(String subjectClassKey) {
Heedo Kang4a47a302016-02-29 17:40:23 +0900168 checkPermission(CONFIG_READ);
Thomas Vachuskaea5adc62015-10-07 11:52:30 -0700169 return subjectClasses.get(subjectClassKey);
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700170 }
171
172 @Override
173 public SubjectFactory getSubjectFactory(Class subjectClass) {
Heedo Kang4a47a302016-02-29 17:40:23 +0900174 checkPermission(CONFIG_READ);
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700175 return subjectClassKeys.get(subjectClass);
176 }
177
178 @Override
Thomas Vachuskaea5adc62015-10-07 11:52:30 -0700179 public Class<? extends Config> getConfigClass(String subjectClassKey, String configKey) {
Heedo Kang4a47a302016-02-29 17:40:23 +0900180 checkPermission(CONFIG_READ);
Simon Hunt3da1a182016-02-08 16:42:54 -0800181 checkNotNull(subjectClassKey, NULL_SCKEY_MSG);
Thomas Vachuska6f350ed2016-01-08 09:53:03 -0800182 checkNotNull(configKey, NULL_CKEY_MSG);
Thomas Vachuskaea5adc62015-10-07 11:52:30 -0700183 return configClasses.get(new ConfigIdentifier(subjectClassKey, configKey));
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700184 }
185
186 @Override
187 public <S> Set<S> getSubjects(Class<S> subjectClass) {
Heedo Kang4a47a302016-02-29 17:40:23 +0900188 checkPermission(CONFIG_READ);
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700189 checkNotNull(subjectClass, NULL_SCLASS_MSG);
190 return store.getSubjects(subjectClass);
191 }
192
193 @Override
194 public <S, C extends Config<S>> Set<S> getSubjects(Class<S> subjectClass, Class<C> configClass) {
Heedo Kang4a47a302016-02-29 17:40:23 +0900195 checkPermission(CONFIG_READ);
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700196 checkNotNull(subjectClass, NULL_SCLASS_MSG);
197 checkNotNull(configClass, NULL_CCLASS_MSG);
198 return store.getSubjects(subjectClass, configClass);
199 }
200
201 @Override
202 public <S> Set<Config<S>> getConfigs(S subject) {
Heedo Kang4a47a302016-02-29 17:40:23 +0900203 checkPermission(CONFIG_READ);
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700204 checkNotNull(subject, NULL_SUBJECT_MSG);
205 Set<Class<? extends Config<S>>> configClasses = store.getConfigClasses(subject);
206 ImmutableSet.Builder<Config<S>> cfg = ImmutableSet.builder();
207 configClasses.forEach(cc -> cfg.add(store.getConfig(subject, cc)));
208 return cfg.build();
209 }
210
211 @Override
Thomas Vachuska6f350ed2016-01-08 09:53:03 -0800212 public <S, C extends Config<S>> C getConfig(S subject, Class<C> configClass) {
Heedo Kang4a47a302016-02-29 17:40:23 +0900213 checkPermission(CONFIG_READ);
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700214 checkNotNull(subject, NULL_SUBJECT_MSG);
215 checkNotNull(configClass, NULL_CCLASS_MSG);
216 return store.getConfig(subject, configClass);
217 }
218
219
220 @Override
221 public <S, C extends Config<S>> C addConfig(S subject, Class<C> configClass) {
Heedo Kang4a47a302016-02-29 17:40:23 +0900222 checkPermission(CONFIG_WRITE);
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700223 checkNotNull(subject, NULL_SUBJECT_MSG);
224 checkNotNull(configClass, NULL_CCLASS_MSG);
225 return store.createConfig(subject, configClass);
226 }
227
228 @Override
Thomas Vachuska0a400ea2015-09-04 11:25:03 -0700229 public <S, C extends Config<S>> C applyConfig(S subject, Class<C> configClass, JsonNode json) {
Heedo Kang4a47a302016-02-29 17:40:23 +0900230 checkPermission(CONFIG_WRITE);
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700231 checkNotNull(subject, NULL_SUBJECT_MSG);
232 checkNotNull(configClass, NULL_CCLASS_MSG);
Simon Hunt3da1a182016-02-08 16:42:54 -0800233 checkNotNull(json, NULL_JSON_MSG);
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700234 return store.applyConfig(subject, configClass, json);
235 }
236
237 @Override
Thomas Vachuska6f350ed2016-01-08 09:53:03 -0800238 @SuppressWarnings("unchecked")
239 public <S, C extends Config<S>> C applyConfig(String subjectClassKey, S subject,
240 String configKey, JsonNode json) {
Heedo Kang4a47a302016-02-29 17:40:23 +0900241 checkPermission(CONFIG_WRITE);
Simon Hunt3da1a182016-02-08 16:42:54 -0800242 checkNotNull(subjectClassKey, NULL_SCKEY_MSG);
Thomas Vachuska6f350ed2016-01-08 09:53:03 -0800243 checkNotNull(subject, NULL_SUBJECT_MSG);
244 checkNotNull(configKey, NULL_CKEY_MSG);
Simon Hunt3da1a182016-02-08 16:42:54 -0800245 checkNotNull(json, NULL_JSON_MSG);
Thomas Vachuska6f350ed2016-01-08 09:53:03 -0800246 Class<? extends Config> configClass = configClasses.get(new ConfigIdentifier(subjectClassKey, configKey));
247 if (configClass != null) {
248 return store.applyConfig(subject, (Class<C>) configClass, json);
249 } else {
Andrea Campanelladcb5e932016-01-11 17:32:23 -0800250 log.info("Configuration \'{}\' queued for subject {}", configKey, subject);
Thomas Vachuska6f350ed2016-01-08 09:53:03 -0800251 store.queueConfig(subject, configKey, json);
252 return null;
253 }
254 }
255
256 @Override
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700257 public <S, C extends Config<S>> void removeConfig(S subject, Class<C> configClass) {
Heedo Kang4a47a302016-02-29 17:40:23 +0900258 checkPermission(CONFIG_WRITE);
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700259 checkNotNull(subject, NULL_SUBJECT_MSG);
260 checkNotNull(configClass, NULL_CCLASS_MSG);
261 store.clearConfig(subject, configClass);
262 }
263
Thomas Vachuska6f350ed2016-01-08 09:53:03 -0800264 @Override
265 public <S> void removeConfig(String subjectClassKey, S subject, String configKey) {
Simon Hunt3da1a182016-02-08 16:42:54 -0800266 checkNotNull(subjectClassKey, NULL_SCKEY_MSG);
Thomas Vachuska6f350ed2016-01-08 09:53:03 -0800267 checkNotNull(subject, NULL_SUBJECT_MSG);
Simon Hunt3da1a182016-02-08 16:42:54 -0800268 checkNotNull(configKey, NULL_CKEY_MSG);
Thomas Vachuska6f350ed2016-01-08 09:53:03 -0800269 Class<? extends Config> configClass = configClasses.get(new ConfigIdentifier(subjectClassKey, configKey));
270 if (configClass != null) {
271 store.clearConfig(subject, configClass);
272 } else {
273 store.clearQueuedConfig(subject, configKey);
274 }
275 }
276
Deepa Vaddireddy0c49b602016-06-02 12:19:07 +0530277 @Override
278 public <S> void removeConfig(S subject) {
279 checkPermission(CONFIG_WRITE);
280 store.clearConfig(subject);
281 }
282
283 @Override
284 public <S> void removeConfig() {
285 checkPermission(CONFIG_WRITE);
286 store.clearConfig();
287 }
288
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700289 // Auxiliary store delegate to receive notification about changes in
290 // the network configuration store state - by the store itself.
291 private class InternalStoreDelegate implements NetworkConfigStoreDelegate {
292 @Override
293 public void notify(NetworkConfigEvent event) {
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700294 post(event);
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700295 }
296 }
297
298
299 // Produces a key for uniquely tracking a config factory.
300 private static ConfigKey key(ConfigFactory factory) {
301 return new ConfigKey(factory.subjectFactory().subjectClass(), factory.configClass());
302 }
303
304 // Auxiliary key to track config factories.
Ray Milkeyae9faf12015-08-03 15:52:26 -0700305 protected static final class ConfigKey {
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700306 final Class subjectClass;
307 final Class configClass;
308
Ray Milkeyae9faf12015-08-03 15:52:26 -0700309 protected ConfigKey(Class subjectClass, Class configClass) {
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700310 this.subjectClass = subjectClass;
311 this.configClass = configClass;
312 }
313
314 @Override
315 public int hashCode() {
316 return Objects.hash(subjectClass, configClass);
317 }
318
319 @Override
320 public boolean equals(Object obj) {
321 if (this == obj) {
322 return true;
323 }
324 if (obj instanceof ConfigKey) {
325 final ConfigKey other = (ConfigKey) obj;
326 return Objects.equals(this.subjectClass, other.subjectClass)
327 && Objects.equals(this.configClass, other.configClass);
328 }
329 return false;
330 }
331 }
332
Jonathan Hart111b42b2015-07-14 13:28:05 -0700333 private static ConfigIdentifier identifier(ConfigFactory factory) {
Thomas Vachuskaea5adc62015-10-07 11:52:30 -0700334 return new ConfigIdentifier(factory.subjectFactory().subjectClassKey(), factory.configKey());
Jonathan Hart111b42b2015-07-14 13:28:05 -0700335 }
336
Thomas Vachuska4998caa2015-08-26 13:28:38 -0700337 static final class ConfigIdentifier {
Thomas Vachuska6f350ed2016-01-08 09:53:03 -0800338 final String subjectClassKey;
Jonathan Hart111b42b2015-07-14 13:28:05 -0700339 final String configKey;
340
Thomas Vachuska6f350ed2016-01-08 09:53:03 -0800341 protected ConfigIdentifier(String subjectClassKey, String configKey) {
342 this.subjectClassKey = subjectClassKey;
Jonathan Hart111b42b2015-07-14 13:28:05 -0700343 this.configKey = configKey;
344 }
345
346 @Override
347 public int hashCode() {
Thomas Vachuska6f350ed2016-01-08 09:53:03 -0800348 return Objects.hash(subjectClassKey, configKey);
Jonathan Hart111b42b2015-07-14 13:28:05 -0700349 }
350
351 @Override
352 public boolean equals(Object obj) {
353 if (this == obj) {
354 return true;
355 }
356 if (obj instanceof ConfigIdentifier) {
357 final ConfigIdentifier other = (ConfigIdentifier) obj;
Thomas Vachuska6f350ed2016-01-08 09:53:03 -0800358 return Objects.equals(this.subjectClassKey, other.subjectClassKey)
Jonathan Hart111b42b2015-07-14 13:28:05 -0700359 && Objects.equals(this.configKey, other.configKey);
360 }
361 return false;
362 }
363 }
Thomas Vachuska6f350ed2016-01-08 09:53:03 -0800364
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700365}