Adding support for configurations added after the Net Config Loader has loaded.
Change-Id: I611f3b8f36805e2854485b694edffc8d93581c7e
Showing
1 changed file
with
112 additions
and
33 deletions
| ... | @@ -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 | } | ... | ... |
-
Please register or login to post a comment