Aaron Kruglikov

Adding support for configurations added after the Net Config Loader has loaded.

Change-Id: I611f3b8f36805e2854485b694edffc8d93581c7e
...@@ -17,16 +17,22 @@ package org.onosproject.incubator.net.config.impl; ...@@ -17,16 +17,22 @@ package org.onosproject.incubator.net.config.impl;
17 17
18 import com.fasterxml.jackson.databind.ObjectMapper; 18 import com.fasterxml.jackson.databind.ObjectMapper;
19 import com.fasterxml.jackson.databind.node.ObjectNode; 19 import com.fasterxml.jackson.databind.node.ObjectNode;
20 +import com.google.common.collect.Maps;
20 import org.apache.felix.scr.annotations.Activate; 21 import org.apache.felix.scr.annotations.Activate;
21 import org.apache.felix.scr.annotations.Component; 22 import org.apache.felix.scr.annotations.Component;
23 +import org.apache.felix.scr.annotations.Deactivate;
22 import org.apache.felix.scr.annotations.Reference; 24 import org.apache.felix.scr.annotations.Reference;
23 import org.apache.felix.scr.annotations.ReferenceCardinality; 25 import org.apache.felix.scr.annotations.ReferenceCardinality;
26 +import org.onosproject.incubator.net.config.NetworkConfigEvent;
27 +import org.onosproject.incubator.net.config.NetworkConfigListener;
24 import org.onosproject.incubator.net.config.NetworkConfigService; 28 import org.onosproject.incubator.net.config.NetworkConfigService;
25 -import org.onosproject.incubator.net.config.SubjectFactory;
26 import org.slf4j.Logger; 29 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory; 30 import org.slf4j.LoggerFactory;
28 31
29 import java.io.File; 32 import java.io.File;
33 +import java.util.Iterator;
34 +import java.util.Map;
35 +import java.util.Objects;
30 36
31 /** 37 /**
32 * Component for loading the initial network configuration. 38 * Component for loading the initial network configuration.
...@@ -43,59 +49,132 @@ public class NetworkConfigLoader { ...@@ -43,59 +49,132 @@ public class NetworkConfigLoader {
43 49
44 // FIXME: Add mutual exclusion to make sure this happens only once per startup. 50 // FIXME: Add mutual exclusion to make sure this happens only once per startup.
45 51
46 - // TODO: add a field to track the collection of pending JSONS 52 + private Map<InnerConfigPosition, ObjectNode> jsons = Maps.newHashMap();
53 +
54 + private final NetworkConfigListener configListener = new InnerConfigListener();
55 +
56 + ObjectNode root;
47 57
48 @Activate 58 @Activate
49 public void activate() { 59 public void activate() {
50 - // Add listener to net config events 60 + //TODO Maybe this should be at the bottom to avoid a potential race
61 + networkConfigService.addListener(configListener);
51 try { 62 try {
52 if (CFG_FILE.exists()) { 63 if (CFG_FILE.exists()) {
53 - ObjectNode root = (ObjectNode) new ObjectMapper().readTree(CFG_FILE); 64 + root = (ObjectNode) new ObjectMapper().readTree(CFG_FILE);
54 - // Parse this JSON structure and accumulate a collection of all leaf config JSONs 65 +
66 + populateConfigurations();
55 67
56 - // Perform initial iteration over all leaf configs and attempt to apply them, 68 + applyConfigurations();
57 - // but do this only if they are valid.
58 -// networkConfigService.getConfigClass("foo");
59 69
60 - // This code can be used for building the collection of jsons
61 - root.fieldNames().forEachRemaining(sk ->
62 - consumeJson(networkConfigService, (ObjectNode) root.path(sk),
63 - networkConfigService.getSubjectFactory(sk)));
64 log.info("Loaded initial network configuration from {}", CFG_FILE); 70 log.info("Loaded initial network configuration from {}", CFG_FILE);
65 } 71 }
66 } catch (Exception e) { 72 } catch (Exception e) {
67 log.warn("Unable to load initial network configuration from {}", 73 log.warn("Unable to load initial network configuration from {}",
68 - CFG_FILE, e); 74 + CFG_FILE, e);
69 } 75 }
70 } 76 }
71 77
78 + @Deactivate
79 + public void deactivate() {
80 + networkConfigService.removeListener(configListener);
81 + }
82 + // sweep through pending config jsons and try to add them
72 83
73 - // TODO: add deactivate which will remove listener 84 + /**
85 + * Inner class that allows for handling of newly added NetConfig types.
86 + */
87 + private final class InnerConfigListener implements NetworkConfigListener {
88 +
89 + @Override
90 + public void event(NetworkConfigEvent event) {
91 + //TODO should this be done for other types of NetworkConfigEvents?
92 + if (event.type() == NetworkConfigEvent.Type.CONFIG_REGISTERED ||
93 + event.type() == NetworkConfigEvent.Type.CONFIG_ADDED) {
94 + applyConfigurations();
95 + }
74 96
75 - // TODO: implement event listener and as each config is registered, 97 + }
76 - // sweep through pending config jsons and try to add them 98 + }
77 99
78 /** 100 /**
79 - * Consumes configuration JSON for the specified subject factory. 101 + * Inner class that allows for tracking of JSON class configurations.
80 - *
81 - * @param service network configuration service
82 - * @param classNode subject class JSON node
83 - * @param subjectFactory subject factory
84 */ 102 */
85 - static void consumeJson(NetworkConfigService service, ObjectNode classNode, 103 + private final class InnerConfigPosition {
86 - SubjectFactory subjectFactory) { 104 + private String subjectKey, subject, classKey;
87 - classNode.fieldNames().forEachRemaining(s -> 105 +
88 - consumeSubjectJson(service, (ObjectNode) classNode.path(s), 106 + private String getSubjectKey() {
89 - subjectFactory.createSubject(s), 107 + return subjectKey;
90 - subjectFactory.subjectKey())); 108 + }
109 +
110 + private String getSubject() {
111 + return subject;
112 + }
113 +
114 + private String getClassKey() {
115 + return classKey;
116 + }
117 +
118 + private InnerConfigPosition(String subjectKey, String subject, String classKey) {
119 + this.subjectKey = subjectKey;
120 + this.subject = subject;
121 + this.classKey = classKey;
122 + }
123 +
124 + @Override
125 + public boolean equals(Object obj) {
126 + if (this == obj) {
127 + return true;
128 + }
129 + if (obj instanceof InnerConfigPosition) {
130 + final InnerConfigPosition that = (InnerConfigPosition) obj;
131 + return Objects.equals(this.subjectKey, that.subjectKey) && Objects.equals(this.subject, that.subject)
132 + && Objects.equals(this.classKey, that.classKey);
133 + }
134 + return false;
135 + }
136 +
137 + @Override
138 + public int hashCode() {
139 + return Objects.hash(subjectKey, subject, classKey);
140 + }
141 + }
142 +
143 + private void saveJson(String sk, ObjectNode node) {
144 + node.fieldNames().forEachRemaining(s ->
145 + saveSubjectJson(sk, s, (ObjectNode) node.path(s)));
91 } 146 }
92 147
93 - private static void consumeSubjectJson(NetworkConfigService service, 148 + private void saveSubjectJson(String sk,
94 - ObjectNode subjectNode, Object subject, String subjectKey) { 149 + String s, ObjectNode node) {
95 - subjectNode.fieldNames().forEachRemaining(c -> 150 + node.fieldNames().forEachRemaining(c ->
96 - service.applyConfig(subject, 151 + this.jsons.put(new InnerConfigPosition(sk, s, c), (ObjectNode) node.path(c)));
97 - service.getConfigClass(subjectKey, c), 152 + }
98 - (ObjectNode) subjectNode.path(c))); 153 +
154 + private void populateConfigurations() {
155 + root.fieldNames().forEachRemaining(sk ->
156 + saveJson(sk, (ObjectNode) root.path(sk)));
157 +
158 + }
159 +
160 + protected void applyConfigurations() {
161 + Iterator<Map.Entry<InnerConfigPosition, ObjectNode>> iter = jsons.entrySet().iterator();
162 + Map.Entry<InnerConfigPosition, ObjectNode> entry;
163 + while (iter.hasNext()) {
164 + entry = iter.next();
165 + if (networkConfigService.getConfigClass(networkConfigService.getSubjectFactory(entry.getKey().
166 + getSubjectKey()).subjectKey(), entry.getKey().getSubject()) != null) {
167 + networkConfigService.applyConfig(networkConfigService.getSubjectFactory(
168 + entry.getKey().getSubjectKey()).createSubject(entry.getKey().getSubject()),
169 + networkConfigService.getConfigClass(networkConfigService.getSubjectFactory(entry.getKey().
170 + getSubjectKey()).subjectKey(), entry.getKey().getClassKey()),
171 + (ObjectNode) root.path(entry.getKey().getSubjectKey()).
172 + path(entry.getKey().getSubject()).
173 + path(entry.getKey().getClassKey()));
174 + jsons.remove(entry.getKey());
175 + }
176 +
177 + }
99 } 178 }
100 179
101 } 180 }
......