blob: 89217163055438bd5a7a5a92b0497d21db903555 [file] [log] [blame]
Thomas Vachuskae6360222015-07-21 10:10:36 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
Thomas Vachuskae6360222015-07-21 10:10:36 -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 Vachuskae6360222015-07-21 10:10:36 -070017
Jonathan Harted4fdcd2015-09-08 14:13:37 -070018import com.fasterxml.jackson.databind.JsonNode;
Thomas Vachuskae6360222015-07-21 10:10:36 -070019import com.fasterxml.jackson.databind.ObjectMapper;
20import com.fasterxml.jackson.databind.node.ObjectNode;
Aaron Kruglikovbd1eb3f2015-07-21 10:39:06 -070021import com.google.common.collect.Maps;
Thomas Vachuskae6360222015-07-21 10:10:36 -070022import org.apache.felix.scr.annotations.Activate;
23import org.apache.felix.scr.annotations.Component;
Aaron Kruglikovbd1eb3f2015-07-21 10:39:06 -070024import org.apache.felix.scr.annotations.Deactivate;
Thomas Vachuskae6360222015-07-21 10:10:36 -070025import org.apache.felix.scr.annotations.Reference;
26import org.apache.felix.scr.annotations.ReferenceCardinality;
Jonathan Hartc43fd1c2016-01-18 20:02:20 -080027import org.onosproject.net.config.BasicNetworkConfigService;
Jonathan Hart4cb39882015-08-12 23:50:55 -040028import org.onosproject.net.config.Config;
Ray Milkeya4122362015-08-18 15:19:08 -070029import org.onosproject.net.config.NetworkConfigEvent;
30import org.onosproject.net.config.NetworkConfigListener;
31import org.onosproject.net.config.NetworkConfigService;
Thomas Vachuskae6360222015-07-21 10:10:36 -070032import org.slf4j.Logger;
33import org.slf4j.LoggerFactory;
34
35import java.io.File;
Aaron Kruglikovbd1eb3f2015-07-21 10:39:06 -070036import java.util.Iterator;
37import java.util.Map;
38import java.util.Objects;
Thomas Vachuskae6360222015-07-21 10:10:36 -070039
40/**
41 * Component for loading the initial network configuration.
42 */
43@Component(immediate = true)
44public class NetworkConfigLoader {
45
46 private static final File CFG_FILE = new File("../config/network-cfg.json");
47
48 private final Logger log = LoggerFactory.getLogger(getClass());
49
Jonathan Hartc43fd1c2016-01-18 20:02:20 -080050 // Dependency to ensure the basic subject factories are properly initialized
51 // before we start loading configs from file
52 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
53 protected BasicNetworkConfigService basicConfigs;
54
Thomas Vachuskae6360222015-07-21 10:10:36 -070055 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
56 protected NetworkConfigService networkConfigService;
57
58 // FIXME: Add mutual exclusion to make sure this happens only once per startup.
59
Jonathan Harted4fdcd2015-09-08 14:13:37 -070060 private final Map<InnerConfigPosition, JsonNode> jsons = Maps.newConcurrentMap();
Aaron Kruglikovbd1eb3f2015-07-21 10:39:06 -070061
62 private final NetworkConfigListener configListener = new InnerConfigListener();
63
Jonathan Hart4cb39882015-08-12 23:50:55 -040064 private ObjectNode root;
Thomas Vachuskae6360222015-07-21 10:10:36 -070065
66 @Activate
67 public void activate() {
Aaron Kruglikovbd1eb3f2015-07-21 10:39:06 -070068 //TODO Maybe this should be at the bottom to avoid a potential race
69 networkConfigService.addListener(configListener);
Thomas Vachuskae6360222015-07-21 10:10:36 -070070 try {
71 if (CFG_FILE.exists()) {
Aaron Kruglikovbd1eb3f2015-07-21 10:39:06 -070072 root = (ObjectNode) new ObjectMapper().readTree(CFG_FILE);
Thomas Vachuskae6360222015-07-21 10:10:36 -070073
Aaron Kruglikovbd1eb3f2015-07-21 10:39:06 -070074 populateConfigurations();
Thomas Vachuskae6360222015-07-21 10:10:36 -070075
Aaron Kruglikovbd1eb3f2015-07-21 10:39:06 -070076 applyConfigurations();
77
Thomas Vachuskae6360222015-07-21 10:10:36 -070078 log.info("Loaded initial network configuration from {}", CFG_FILE);
79 }
80 } catch (Exception e) {
81 log.warn("Unable to load initial network configuration from {}",
Aaron Kruglikovbd1eb3f2015-07-21 10:39:06 -070082 CFG_FILE, e);
Thomas Vachuskae6360222015-07-21 10:10:36 -070083 }
84 }
85
Aaron Kruglikovbd1eb3f2015-07-21 10:39:06 -070086 @Deactivate
87 public void deactivate() {
88 networkConfigService.removeListener(configListener);
89 }
Thomas Vachuskae6360222015-07-21 10:10:36 -070090 // sweep through pending config jsons and try to add them
91
92 /**
Aaron Kruglikovbd1eb3f2015-07-21 10:39:06 -070093 * Inner class that allows for handling of newly added NetConfig types.
Thomas Vachuskae6360222015-07-21 10:10:36 -070094 */
Aaron Kruglikovbd1eb3f2015-07-21 10:39:06 -070095 private final class InnerConfigListener implements NetworkConfigListener {
96
97 @Override
98 public void event(NetworkConfigEvent event) {
99 //TODO should this be done for other types of NetworkConfigEvents?
100 if (event.type() == NetworkConfigEvent.Type.CONFIG_REGISTERED ||
101 event.type() == NetworkConfigEvent.Type.CONFIG_ADDED) {
102 applyConfigurations();
103 }
104
105 }
Thomas Vachuskae6360222015-07-21 10:10:36 -0700106 }
107
Aaron Kruglikovbd1eb3f2015-07-21 10:39:06 -0700108 /**
109 * Inner class that allows for tracking of JSON class configurations.
110 */
111 private final class InnerConfigPosition {
Jonathan Hart4cb39882015-08-12 23:50:55 -0400112 private final String subjectKey, subject, configKey;
Aaron Kruglikovbd1eb3f2015-07-21 10:39:06 -0700113
Jonathan Hart4cb39882015-08-12 23:50:55 -0400114 private String subjectKey() {
Aaron Kruglikovbd1eb3f2015-07-21 10:39:06 -0700115 return subjectKey;
116 }
117
Jonathan Hart4cb39882015-08-12 23:50:55 -0400118 private String subject() {
Aaron Kruglikovbd1eb3f2015-07-21 10:39:06 -0700119 return subject;
120 }
121
Jonathan Hart4cb39882015-08-12 23:50:55 -0400122 private String configKey() {
123 return configKey;
Aaron Kruglikovbd1eb3f2015-07-21 10:39:06 -0700124 }
125
Jonathan Hart4cb39882015-08-12 23:50:55 -0400126 private InnerConfigPosition(String subjectKey, String subject, String configKey) {
Aaron Kruglikovbd1eb3f2015-07-21 10:39:06 -0700127 this.subjectKey = subjectKey;
128 this.subject = subject;
Jonathan Hart4cb39882015-08-12 23:50:55 -0400129 this.configKey = configKey;
Aaron Kruglikovbd1eb3f2015-07-21 10:39:06 -0700130 }
131
132 @Override
133 public boolean equals(Object obj) {
134 if (this == obj) {
135 return true;
136 }
137 if (obj instanceof InnerConfigPosition) {
138 final InnerConfigPosition that = (InnerConfigPosition) obj;
Jonathan Hart4cb39882015-08-12 23:50:55 -0400139 return Objects.equals(this.subjectKey, that.subjectKey)
140 && Objects.equals(this.subject, that.subject)
141 && Objects.equals(this.configKey, that.configKey);
Aaron Kruglikovbd1eb3f2015-07-21 10:39:06 -0700142 }
143 return false;
144 }
145
146 @Override
147 public int hashCode() {
Jonathan Hart4cb39882015-08-12 23:50:55 -0400148 return Objects.hash(subjectKey, subject, configKey);
Aaron Kruglikovbd1eb3f2015-07-21 10:39:06 -0700149 }
150 }
151
Aaron Kruglikova598c9e2015-07-23 16:56:27 -0700152 /**
153 * Save the JSON leaves associated with a specific subject key.
154 *
155 * @param sk the subject key string.
156 * @param node the node associated with the subject key.
157 */
Aaron Kruglikovbd1eb3f2015-07-21 10:39:06 -0700158 private void saveJson(String sk, ObjectNode node) {
159 node.fieldNames().forEachRemaining(s ->
160 saveSubjectJson(sk, s, (ObjectNode) node.path(s)));
161 }
162
Aaron Kruglikova598c9e2015-07-23 16:56:27 -0700163 /**
164 * Save the JSON leaves of the tree rooted as the node 'node' with subject key 'sk'.
165 *
166 * @param sk the string of the subject key.
167 * @param s the subject name.
168 * @param node the node rooting this subtree.
169 */
Aaron Kruglikovbd1eb3f2015-07-21 10:39:06 -0700170 private void saveSubjectJson(String sk,
171 String s, ObjectNode node) {
172 node.fieldNames().forEachRemaining(c ->
Jonathan Harted4fdcd2015-09-08 14:13:37 -0700173 this.jsons.put(new InnerConfigPosition(sk, s, c), node.path(c)));
Aaron Kruglikovbd1eb3f2015-07-21 10:39:06 -0700174 }
175
Aaron Kruglikova598c9e2015-07-23 16:56:27 -0700176 /**
177 * Iterate through the JSON and populate a list of the leaf nodes of the structure.
178 */
Aaron Kruglikovbd1eb3f2015-07-21 10:39:06 -0700179 private void populateConfigurations() {
180 root.fieldNames().forEachRemaining(sk ->
181 saveJson(sk, (ObjectNode) root.path(sk)));
182
183 }
184
Aaron Kruglikova598c9e2015-07-23 16:56:27 -0700185 /**
Jonathan Hart4cb39882015-08-12 23:50:55 -0400186 * Apply the configurations associated with all of the config classes that
187 * are imported and have not yet been applied.
Aaron Kruglikova598c9e2015-07-23 16:56:27 -0700188 */
Jonathan Hart4cb39882015-08-12 23:50:55 -0400189 private void applyConfigurations() {
Jonathan Harted4fdcd2015-09-08 14:13:37 -0700190 Iterator<Map.Entry<InnerConfigPosition, JsonNode>> iter = jsons.entrySet().iterator();
Aaron Kruglikova598c9e2015-07-23 16:56:27 -0700191
Jonathan Harted4fdcd2015-09-08 14:13:37 -0700192 Map.Entry<InnerConfigPosition, JsonNode> entry;
Aaron Kruglikova598c9e2015-07-23 16:56:27 -0700193 InnerConfigPosition key;
Jonathan Harted4fdcd2015-09-08 14:13:37 -0700194 JsonNode node;
Aaron Kruglikova598c9e2015-07-23 16:56:27 -0700195 String subjectKey;
Jonathan Hart4cb39882015-08-12 23:50:55 -0400196 String subjectString;
197 String configKey;
Aaron Kruglikova598c9e2015-07-23 16:56:27 -0700198
Aaron Kruglikovbd1eb3f2015-07-21 10:39:06 -0700199 while (iter.hasNext()) {
200 entry = iter.next();
Aaron Kruglikova598c9e2015-07-23 16:56:27 -0700201 node = entry.getValue();
202 key = entry.getKey();
Jonathan Hart4cb39882015-08-12 23:50:55 -0400203 subjectKey = key.subjectKey();
204 subjectString = key.subject();
205 configKey = key.configKey();
206
207 Class<? extends Config> configClass =
208 networkConfigService.getConfigClass(subjectKey, configKey);
Aaron Kruglikova598c9e2015-07-23 16:56:27 -0700209 //Check that the config class has been imported
Jonathan Hart4cb39882015-08-12 23:50:55 -0400210 if (configClass != null) {
211
212 Object subject = networkConfigService.getSubjectFactory(subjectKey).
213 createSubject(subjectString);
Aaron Kruglikova598c9e2015-07-23 16:56:27 -0700214
215 //Apply the configuration
Jonathan Hart4cb39882015-08-12 23:50:55 -0400216 networkConfigService.applyConfig(subject, configClass, node);
Aaron Kruglikova598c9e2015-07-23 16:56:27 -0700217
218 //Now that it has been applied the corresponding JSON entry is no longer needed
Jonathan Hart4cb39882015-08-12 23:50:55 -0400219 iter.remove();
Aaron Kruglikovbd1eb3f2015-07-21 10:39:06 -0700220 }
Aaron Kruglikovbd1eb3f2015-07-21 10:39:06 -0700221 }
Thomas Vachuskae6360222015-07-21 10:10:36 -0700222 }
223
224}