Fixed annotation handling.
- Store as SparseAnnotations internally and convert to Annotations when merging multiple provider supplied annotations. Change-Id: I82fe159b536b3e7344a33e09792f6a3473fb3500
Showing
10 changed files
with
75 additions
and
29 deletions
... | @@ -73,31 +73,63 @@ public final class DefaultAnnotations implements SparseAnnotations { | ... | @@ -73,31 +73,63 @@ public final class DefaultAnnotations implements SparseAnnotations { |
73 | } | 73 | } |
74 | 74 | ||
75 | /** | 75 | /** |
76 | - * Convert Annotations to DefaultAnnotations if needed and merges. | 76 | + * Creates the union of two given SparseAnnotations. |
77 | + * Unlike the {@link #merge(DefaultAnnotations, SparseAnnotations)} method, | ||
78 | + * result will be {@link SparseAnnotations} instead of {@link Annotations}. | ||
77 | * | 79 | * |
78 | - * @see #merge(DefaultAnnotations, SparseAnnotations) | 80 | + * A key tagged for removal will remain in the output SparseAnnotations, |
81 | + * if the counterpart of the input does not contain the same key. | ||
79 | * | 82 | * |
80 | * @param annotations base annotations | 83 | * @param annotations base annotations |
81 | * @param sparseAnnotations additional sparse annotations | 84 | * @param sparseAnnotations additional sparse annotations |
82 | * @return combined annotations or the original base annotations if there | 85 | * @return combined annotations or the original base annotations if there |
83 | * are not additional annotations | 86 | * are not additional annotations |
84 | */ | 87 | */ |
85 | - public static DefaultAnnotations merge(Annotations annotations, | 88 | + public static SparseAnnotations union(SparseAnnotations annotations, |
86 | - SparseAnnotations sparseAnnotations) { | 89 | + SparseAnnotations sparseAnnotations) { |
90 | + | ||
91 | + if (sparseAnnotations == null || sparseAnnotations.keys().isEmpty()) { | ||
92 | + return annotations; | ||
93 | + } | ||
94 | + | ||
95 | + final HashMap<String, String> newMap; | ||
87 | if (annotations instanceof DefaultAnnotations) { | 96 | if (annotations instanceof DefaultAnnotations) { |
88 | - return merge((DefaultAnnotations) annotations, sparseAnnotations); | 97 | + newMap = copy(((DefaultAnnotations) annotations).map); |
98 | + } else { | ||
99 | + newMap = new HashMap<>(annotations.keys().size() + | ||
100 | + sparseAnnotations.keys().size()); | ||
101 | + putAllSparseAnnotations(newMap, annotations); | ||
89 | } | 102 | } |
90 | 103 | ||
91 | - DefaultAnnotations.Builder builder = DefaultAnnotations.builder(); | 104 | + putAllSparseAnnotations(newMap, sparseAnnotations); |
92 | - for (String key : annotations.keys()) { | 105 | + return new DefaultAnnotations(newMap); |
93 | - builder.set(key, annotations.value(key)); | 106 | + } |
107 | + | ||
108 | + // adds the key-values contained in sparseAnnotations to | ||
109 | + // newMap, if sparseAnnotations had a key tagged for removal, | ||
110 | + // and corresponding key exist in newMap, entry will be removed. | ||
111 | + // if corresponding key does not exist, removal tag will be added to | ||
112 | + // the newMap. | ||
113 | + private static void putAllSparseAnnotations( | ||
114 | + final HashMap<String, String> newMap, | ||
115 | + SparseAnnotations sparseAnnotations) { | ||
116 | + | ||
117 | + for (String key : sparseAnnotations.keys()) { | ||
118 | + if (sparseAnnotations.isRemoved(key)) { | ||
119 | + if (newMap.containsKey(key)) { | ||
120 | + newMap.remove(key); | ||
121 | + } else { | ||
122 | + newMap.put(key, Builder.REMOVED); | ||
123 | + } | ||
124 | + } else { | ||
125 | + String value = sparseAnnotations.value(key); | ||
126 | + newMap.put(key, value); | ||
127 | + } | ||
94 | } | 128 | } |
95 | - return merge(builder.build(), sparseAnnotations); | ||
96 | } | 129 | } |
97 | 130 | ||
98 | @Override | 131 | @Override |
99 | public Set<String> keys() { | 132 | public Set<String> keys() { |
100 | - // TODO: unmodifiable to be removed after switching to ImmutableMap; | ||
101 | return Collections.unmodifiableSet(map.keySet()); | 133 | return Collections.unmodifiableSet(map.keySet()); |
102 | } | 134 | } |
103 | 135 | ||
... | @@ -115,7 +147,7 @@ public final class DefaultAnnotations implements SparseAnnotations { | ... | @@ -115,7 +147,7 @@ public final class DefaultAnnotations implements SparseAnnotations { |
115 | @SuppressWarnings("unchecked") | 147 | @SuppressWarnings("unchecked") |
116 | private static HashMap<String, String> copy(Map<String, String> original) { | 148 | private static HashMap<String, String> copy(Map<String, String> original) { |
117 | if (original instanceof HashMap) { | 149 | if (original instanceof HashMap) { |
118 | - return (HashMap) ((HashMap) original).clone(); | 150 | + return (HashMap<String, String>) ((HashMap<?, ?>) original).clone(); |
119 | } | 151 | } |
120 | throw new IllegalArgumentException("Expecting HashMap instance"); | 152 | throw new IllegalArgumentException("Expecting HashMap instance"); |
121 | } | 153 | } | ... | ... |
... | @@ -33,4 +33,4 @@ public class ConnectPointTest { | ... | @@ -33,4 +33,4 @@ public class ConnectPointTest { |
33 | .addEqualityGroup(new ConnectPoint(DID2, P1), new ConnectPoint(DID2, P1)) | 33 | .addEqualityGroup(new ConnectPoint(DID2, P1), new ConnectPoint(DID2, P1)) |
34 | .testEquals(); | 34 | .testEquals(); |
35 | } | 35 | } |
36 | -} | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
36 | +} | ... | ... |
... | @@ -36,6 +36,23 @@ public class DefaultAnnotationsTest { | ... | @@ -36,6 +36,23 @@ public class DefaultAnnotationsTest { |
36 | } | 36 | } |
37 | 37 | ||
38 | @Test | 38 | @Test |
39 | + public void union() { | ||
40 | + annotations = builder().set("foo", "1").set("bar", "2").remove("buz").build(); | ||
41 | + assertEquals("incorrect keys", of("foo", "bar", "buz"), annotations.keys()); | ||
42 | + | ||
43 | + SparseAnnotations updates = builder().remove("foo").set("bar", "3").set("goo", "4").remove("fuzz").build(); | ||
44 | + | ||
45 | + SparseAnnotations result = DefaultAnnotations.union(annotations, updates); | ||
46 | + | ||
47 | + assertTrue("remove instruction in original remains", result.isRemoved("buz")); | ||
48 | + assertTrue("remove instruction in update remains", result.isRemoved("fuzz")); | ||
49 | + assertEquals("incorrect keys", of("buz", "goo", "bar", "fuzz"), result.keys()); | ||
50 | + assertNull("incorrect value", result.value("foo")); | ||
51 | + assertEquals("incorrect value", "3", result.value("bar")); | ||
52 | + assertEquals("incorrect value", "4", result.value("goo")); | ||
53 | + } | ||
54 | + | ||
55 | + @Test | ||
39 | public void merge() { | 56 | public void merge() { |
40 | annotations = builder().set("foo", "1").set("bar", "2").build(); | 57 | annotations = builder().set("foo", "1").set("bar", "2").build(); |
41 | assertEquals("incorrect keys", of("foo", "bar"), annotations.keys()); | 58 | assertEquals("incorrect keys", of("foo", "bar"), annotations.keys()); |
... | @@ -65,4 +82,4 @@ public class DefaultAnnotationsTest { | ... | @@ -65,4 +82,4 @@ public class DefaultAnnotationsTest { |
65 | DefaultAnnotations.merge(null, null); | 82 | DefaultAnnotations.merge(null, null); |
66 | } | 83 | } |
67 | 84 | ||
68 | -} | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
85 | +} | ... | ... |
... | @@ -58,7 +58,5 @@ public class DefaultDeviceTest { | ... | @@ -58,7 +58,5 @@ public class DefaultDeviceTest { |
58 | assertEquals("incorrect hw", HW, device.hwVersion()); | 58 | assertEquals("incorrect hw", HW, device.hwVersion()); |
59 | assertEquals("incorrect sw", SW, device.swVersion()); | 59 | assertEquals("incorrect sw", SW, device.swVersion()); |
60 | assertEquals("incorrect serial", SN1, device.serialNumber()); | 60 | assertEquals("incorrect serial", SN1, device.serialNumber()); |
61 | - assertEquals("incorrect serial", SN1, device.serialNumber()); | ||
62 | } | 61 | } |
63 | - | ||
64 | -} | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
62 | +} | ... | ... |
... | @@ -37,5 +37,4 @@ public class DefaultGraphDescriptionTest { | ... | @@ -37,5 +37,4 @@ public class DefaultGraphDescriptionTest { |
37 | new DefaultGraphDescription(4321L, ImmutableSet.of(DEV1, DEV3), | 37 | new DefaultGraphDescription(4321L, ImmutableSet.of(DEV1, DEV3), |
38 | ImmutableSet.of(L1, L2)); | 38 | ImmutableSet.of(L1, L2)); |
39 | } | 39 | } |
40 | - | ||
41 | -} | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
40 | +} | ... | ... |
... | @@ -50,5 +50,4 @@ public class DefaultTopologyEdgeTest { | ... | @@ -50,5 +50,4 @@ public class DefaultTopologyEdgeTest { |
50 | new DefaultTopologyEdge(V2, V1, L2)) | 50 | new DefaultTopologyEdge(V2, V1, L2)) |
51 | .testEquals(); | 51 | .testEquals(); |
52 | } | 52 | } |
53 | - | ||
54 | -} | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
53 | +} | ... | ... |
... | @@ -26,5 +26,4 @@ public class DefaultTopologyVertexTest { | ... | @@ -26,5 +26,4 @@ public class DefaultTopologyVertexTest { |
26 | .addEqualityGroup(new DefaultTopologyVertex(D2), | 26 | .addEqualityGroup(new DefaultTopologyVertex(D2), |
27 | new DefaultTopologyVertex(D2)).testEquals(); | 27 | new DefaultTopologyVertex(D2)).testEquals(); |
28 | } | 28 | } |
29 | - | ||
30 | -} | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
29 | +} | ... | ... |
... | @@ -56,6 +56,7 @@ import static org.onlab.onos.net.device.DeviceEvent.Type.*; | ... | @@ -56,6 +56,7 @@ import static org.onlab.onos.net.device.DeviceEvent.Type.*; |
56 | import static org.slf4j.LoggerFactory.getLogger; | 56 | import static org.slf4j.LoggerFactory.getLogger; |
57 | import static org.apache.commons.lang3.concurrent.ConcurrentUtils.createIfAbsentUnchecked; | 57 | import static org.apache.commons.lang3.concurrent.ConcurrentUtils.createIfAbsentUnchecked; |
58 | import static org.onlab.onos.net.DefaultAnnotations.merge; | 58 | import static org.onlab.onos.net.DefaultAnnotations.merge; |
59 | +import static org.onlab.onos.net.DefaultAnnotations.union; | ||
59 | import static com.google.common.base.Verify.verify; | 60 | import static com.google.common.base.Verify.verify; |
60 | 61 | ||
61 | // TODO: implement remove event handling and call *Internal | 62 | // TODO: implement remove event handling and call *Internal |
... | @@ -603,7 +604,7 @@ public class GossipDeviceStore | ... | @@ -603,7 +604,7 @@ public class GossipDeviceStore |
603 | Timestamped<DeviceDescription> oldOne = deviceDesc.get(); | 604 | Timestamped<DeviceDescription> oldOne = deviceDesc.get(); |
604 | Timestamped<DeviceDescription> newOne = newDesc; | 605 | Timestamped<DeviceDescription> newOne = newDesc; |
605 | if (oldOne != null) { | 606 | if (oldOne != null) { |
606 | - SparseAnnotations merged = merge(oldOne.value().annotations(), | 607 | + SparseAnnotations merged = union(oldOne.value().annotations(), |
607 | newDesc.value().annotations()); | 608 | newDesc.value().annotations()); |
608 | newOne = new Timestamped<DeviceDescription>( | 609 | newOne = new Timestamped<DeviceDescription>( |
609 | new DefaultDeviceDescription(newDesc.value(), merged), | 610 | new DefaultDeviceDescription(newDesc.value(), merged), |
... | @@ -622,7 +623,7 @@ public class GossipDeviceStore | ... | @@ -622,7 +623,7 @@ public class GossipDeviceStore |
622 | Timestamped<PortDescription> oldOne = portDescs.get(newDesc.value().portNumber()); | 623 | Timestamped<PortDescription> oldOne = portDescs.get(newDesc.value().portNumber()); |
623 | Timestamped<PortDescription> newOne = newDesc; | 624 | Timestamped<PortDescription> newOne = newDesc; |
624 | if (oldOne != null) { | 625 | if (oldOne != null) { |
625 | - SparseAnnotations merged = merge(oldOne.value().annotations(), | 626 | + SparseAnnotations merged = union(oldOne.value().annotations(), |
626 | newDesc.value().annotations()); | 627 | newDesc.value().annotations()); |
627 | newOne = new Timestamped<PortDescription>( | 628 | newOne = new Timestamped<PortDescription>( |
628 | new DefaultPortDescription(newDesc.value(), merged), | 629 | new DefaultPortDescription(newDesc.value(), merged), | ... | ... |
... | @@ -51,6 +51,7 @@ import static com.google.common.base.Predicates.notNull; | ... | @@ -51,6 +51,7 @@ import static com.google.common.base.Predicates.notNull; |
51 | import static org.onlab.onos.net.device.DeviceEvent.Type.*; | 51 | import static org.onlab.onos.net.device.DeviceEvent.Type.*; |
52 | import static org.slf4j.LoggerFactory.getLogger; | 52 | import static org.slf4j.LoggerFactory.getLogger; |
53 | import static org.apache.commons.lang3.concurrent.ConcurrentUtils.createIfAbsentUnchecked; | 53 | import static org.apache.commons.lang3.concurrent.ConcurrentUtils.createIfAbsentUnchecked; |
54 | +import static org.onlab.onos.net.DefaultAnnotations.union; | ||
54 | import static org.onlab.onos.net.DefaultAnnotations.merge; | 55 | import static org.onlab.onos.net.DefaultAnnotations.merge; |
55 | 56 | ||
56 | /** | 57 | /** |
... | @@ -488,7 +489,7 @@ public class SimpleDeviceStore | ... | @@ -488,7 +489,7 @@ public class SimpleDeviceStore |
488 | DeviceDescription oldOne = deviceDesc.get(); | 489 | DeviceDescription oldOne = deviceDesc.get(); |
489 | DeviceDescription newOne = newDesc; | 490 | DeviceDescription newOne = newDesc; |
490 | if (oldOne != null) { | 491 | if (oldOne != null) { |
491 | - SparseAnnotations merged = merge(oldOne.annotations(), | 492 | + SparseAnnotations merged = union(oldOne.annotations(), |
492 | newDesc.annotations()); | 493 | newDesc.annotations()); |
493 | newOne = new DefaultDeviceDescription(newOne, merged); | 494 | newOne = new DefaultDeviceDescription(newOne, merged); |
494 | } | 495 | } |
... | @@ -505,7 +506,7 @@ public class SimpleDeviceStore | ... | @@ -505,7 +506,7 @@ public class SimpleDeviceStore |
505 | PortDescription oldOne = portDescs.get(newDesc.portNumber()); | 506 | PortDescription oldOne = portDescs.get(newDesc.portNumber()); |
506 | PortDescription newOne = newDesc; | 507 | PortDescription newOne = newDesc; |
507 | if (oldOne != null) { | 508 | if (oldOne != null) { |
508 | - SparseAnnotations merged = merge(oldOne.annotations(), | 509 | + SparseAnnotations merged = union(oldOne.annotations(), |
509 | newDesc.annotations()); | 510 | newDesc.annotations()); |
510 | newOne = new DefaultPortDescription(newOne, merged); | 511 | newOne = new DefaultPortDescription(newOne, merged); |
511 | } | 512 | } | ... | ... |
... | @@ -11,7 +11,6 @@ import org.apache.felix.scr.annotations.Activate; | ... | @@ -11,7 +11,6 @@ import org.apache.felix.scr.annotations.Activate; |
11 | import org.apache.felix.scr.annotations.Component; | 11 | import org.apache.felix.scr.annotations.Component; |
12 | import org.apache.felix.scr.annotations.Deactivate; | 12 | import org.apache.felix.scr.annotations.Deactivate; |
13 | import org.apache.felix.scr.annotations.Service; | 13 | import org.apache.felix.scr.annotations.Service; |
14 | -import org.onlab.onos.net.Annotations; | ||
15 | import org.onlab.onos.net.AnnotationsUtil; | 14 | import org.onlab.onos.net.AnnotationsUtil; |
16 | import org.onlab.onos.net.ConnectPoint; | 15 | import org.onlab.onos.net.ConnectPoint; |
17 | import org.onlab.onos.net.DefaultAnnotations; | 16 | import org.onlab.onos.net.DefaultAnnotations; |
... | @@ -39,6 +38,7 @@ import java.util.Map.Entry; | ... | @@ -39,6 +38,7 @@ import java.util.Map.Entry; |
39 | import java.util.concurrent.ConcurrentHashMap; | 38 | import java.util.concurrent.ConcurrentHashMap; |
40 | import java.util.concurrent.ConcurrentMap; | 39 | import java.util.concurrent.ConcurrentMap; |
41 | 40 | ||
41 | +import static org.onlab.onos.net.DefaultAnnotations.union; | ||
42 | import static org.onlab.onos.net.DefaultAnnotations.merge; | 42 | import static org.onlab.onos.net.DefaultAnnotations.merge; |
43 | import static org.onlab.onos.net.Link.Type.DIRECT; | 43 | import static org.onlab.onos.net.Link.Type.DIRECT; |
44 | import static org.onlab.onos.net.Link.Type.INDIRECT; | 44 | import static org.onlab.onos.net.Link.Type.INDIRECT; |
... | @@ -173,7 +173,7 @@ public class SimpleLinkStore | ... | @@ -173,7 +173,7 @@ public class SimpleLinkStore |
173 | LinkDescription oldDesc = descs.get(providerId); | 173 | LinkDescription oldDesc = descs.get(providerId); |
174 | LinkDescription newDesc = linkDescription; | 174 | LinkDescription newDesc = linkDescription; |
175 | if (oldDesc != null) { | 175 | if (oldDesc != null) { |
176 | - SparseAnnotations merged = merge(oldDesc.annotations(), | 176 | + SparseAnnotations merged = union(oldDesc.annotations(), |
177 | linkDescription.annotations()); | 177 | linkDescription.annotations()); |
178 | newDesc = new DefaultLinkDescription( | 178 | newDesc = new DefaultLinkDescription( |
179 | linkDescription.src(), | 179 | linkDescription.src(), |
... | @@ -268,7 +268,7 @@ public class SimpleLinkStore | ... | @@ -268,7 +268,7 @@ public class SimpleLinkStore |
268 | ConnectPoint src = base.src(); | 268 | ConnectPoint src = base.src(); |
269 | ConnectPoint dst = base.dst(); | 269 | ConnectPoint dst = base.dst(); |
270 | Type type = base.type(); | 270 | Type type = base.type(); |
271 | - Annotations annotations = DefaultAnnotations.builder().build(); | 271 | + DefaultAnnotations annotations = DefaultAnnotations.builder().build(); |
272 | annotations = merge(annotations, base.annotations()); | 272 | annotations = merge(annotations, base.annotations()); |
273 | 273 | ||
274 | for (Entry<ProviderId, LinkDescription> e : descs.entrySet()) { | 274 | for (Entry<ProviderId, LinkDescription> e : descs.entrySet()) { | ... | ... |
-
Please register or login to post a comment