Yuta HIGUCHI

Fixed annotation handling.

- Store as SparseAnnotations internally and convert to Annotations
  when merging multiple provider supplied annotations.

Change-Id: I82fe159b536b3e7344a33e09792f6a3473fb3500
...@@ -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);
102 + }
103 +
104 + putAllSparseAnnotations(newMap, sparseAnnotations);
105 + return new DefaultAnnotations(newMap);
89 } 106 }
90 107
91 - DefaultAnnotations.Builder builder = DefaultAnnotations.builder(); 108 + // adds the key-values contained in sparseAnnotations to
92 - for (String key : annotations.keys()) { 109 + // newMap, if sparseAnnotations had a key tagged for removal,
93 - builder.set(key, annotations.value(key)); 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 }
......
...@@ -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());
......
...@@ -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 } 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 } 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 } 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 } 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()) {
......