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