SimpleLinkStore with annotation and multi-provider support
Change-Id: I98a35c4497363c6115fd0c61d140dfe7790e6cee
Showing
8 changed files
with
184 additions
and
65 deletions
| 1 | +package org.onlab.onos.net; | ||
| 2 | + | ||
| 3 | +public final class AnnotationsUtil { | ||
| 4 | + | ||
| 5 | + public static boolean isEqual(Annotations lhs, Annotations rhs) { | ||
| 6 | + if (lhs == rhs) { | ||
| 7 | + return true; | ||
| 8 | + } | ||
| 9 | + if (lhs == null || rhs == null) { | ||
| 10 | + return false; | ||
| 11 | + } | ||
| 12 | + | ||
| 13 | + if (!lhs.keys().equals(rhs.keys())) { | ||
| 14 | + return false; | ||
| 15 | + } | ||
| 16 | + | ||
| 17 | + for (String key : lhs.keys()) { | ||
| 18 | + if (!lhs.value(key).equals(rhs.value(key))) { | ||
| 19 | + return false; | ||
| 20 | + } | ||
| 21 | + } | ||
| 22 | + return true; | ||
| 23 | + } | ||
| 24 | + | ||
| 25 | + // not to be instantiated | ||
| 26 | + private AnnotationsUtil() {} | ||
| 27 | +} |
| 1 | package org.onlab.onos.net.link; | 1 | package org.onlab.onos.net.link; |
| 2 | 2 | ||
| 3 | import org.onlab.onos.net.ConnectPoint; | 3 | import org.onlab.onos.net.ConnectPoint; |
| 4 | +import org.onlab.onos.net.Description; | ||
| 4 | import org.onlab.onos.net.Link; | 5 | import org.onlab.onos.net.Link; |
| 5 | 6 | ||
| 6 | /** | 7 | /** |
| 7 | * Describes an infrastructure link. | 8 | * Describes an infrastructure link. |
| 8 | */ | 9 | */ |
| 9 | -public interface LinkDescription { | 10 | +public interface LinkDescription extends Description { |
| 10 | 11 | ||
| 11 | /** | 12 | /** |
| 12 | * Returns the link source. | 13 | * Returns the link source. | ... | ... |
| ... | @@ -11,7 +11,7 @@ import org.apache.felix.scr.annotations.Deactivate; | ... | @@ -11,7 +11,7 @@ import org.apache.felix.scr.annotations.Deactivate; |
| 11 | import org.apache.felix.scr.annotations.Reference; | 11 | import org.apache.felix.scr.annotations.Reference; |
| 12 | import org.apache.felix.scr.annotations.ReferenceCardinality; | 12 | import org.apache.felix.scr.annotations.ReferenceCardinality; |
| 13 | import org.apache.felix.scr.annotations.Service; | 13 | import org.apache.felix.scr.annotations.Service; |
| 14 | -import org.onlab.onos.net.Annotations; | 14 | +import org.onlab.onos.net.AnnotationsUtil; |
| 15 | import org.onlab.onos.net.DefaultAnnotations; | 15 | import org.onlab.onos.net.DefaultAnnotations; |
| 16 | import org.onlab.onos.net.DefaultDevice; | 16 | import org.onlab.onos.net.DefaultDevice; |
| 17 | import org.onlab.onos.net.DefaultPort; | 17 | import org.onlab.onos.net.DefaultPort; |
| ... | @@ -196,7 +196,7 @@ public class GossipDeviceStore | ... | @@ -196,7 +196,7 @@ public class GossipDeviceStore |
| 196 | // We allow only certain attributes to trigger update | 196 | // We allow only certain attributes to trigger update |
| 197 | if (!Objects.equals(oldDevice.hwVersion(), newDevice.hwVersion()) || | 197 | if (!Objects.equals(oldDevice.hwVersion(), newDevice.hwVersion()) || |
| 198 | !Objects.equals(oldDevice.swVersion(), newDevice.swVersion()) || | 198 | !Objects.equals(oldDevice.swVersion(), newDevice.swVersion()) || |
| 199 | - !isAnnotationsEqual(oldDevice.annotations(), newDevice.annotations())) { | 199 | + !AnnotationsUtil.isEqual(oldDevice.annotations(), newDevice.annotations())) { |
| 200 | 200 | ||
| 201 | boolean replaced = devices.replace(newDevice.id(), oldDevice, newDevice); | 201 | boolean replaced = devices.replace(newDevice.id(), oldDevice, newDevice); |
| 202 | if (!replaced) { | 202 | if (!replaced) { |
| ... | @@ -327,7 +327,7 @@ public class GossipDeviceStore | ... | @@ -327,7 +327,7 @@ public class GossipDeviceStore |
| 327 | Port newPort, | 327 | Port newPort, |
| 328 | Map<PortNumber, Port> ports) { | 328 | Map<PortNumber, Port> ports) { |
| 329 | if (oldPort.isEnabled() != newPort.isEnabled() || | 329 | if (oldPort.isEnabled() != newPort.isEnabled() || |
| 330 | - !isAnnotationsEqual(oldPort.annotations(), newPort.annotations())) { | 330 | + !AnnotationsUtil.isEqual(oldPort.annotations(), newPort.annotations())) { |
| 331 | 331 | ||
| 332 | ports.put(oldPort.number(), newPort); | 332 | ports.put(oldPort.number(), newPort); |
| 333 | return new DeviceEvent(PORT_UPDATED, device, newPort); | 333 | return new DeviceEvent(PORT_UPDATED, device, newPort); |
| ... | @@ -438,31 +438,10 @@ public class GossipDeviceStore | ... | @@ -438,31 +438,10 @@ public class GossipDeviceStore |
| 438 | 438 | ||
| 439 | @Override | 439 | @Override |
| 440 | public DeviceEvent removeDevice(DeviceId deviceId) { | 440 | public DeviceEvent removeDevice(DeviceId deviceId) { |
| 441 | - synchronized (this) { | 441 | + Device device = devices.remove(deviceId); |
| 442 | - Device device = devices.remove(deviceId); | 442 | + // FIXME: should we be removing deviceDescs also? |
| 443 | - return device == null ? null : | 443 | + return device == null ? null : |
| 444 | - new DeviceEvent(DEVICE_REMOVED, device, null); | 444 | + new DeviceEvent(DEVICE_REMOVED, device, null); |
| 445 | - } | ||
| 446 | - } | ||
| 447 | - | ||
| 448 | - private static boolean isAnnotationsEqual(Annotations lhs, Annotations rhs) { | ||
| 449 | - if (lhs == rhs) { | ||
| 450 | - return true; | ||
| 451 | - } | ||
| 452 | - if (lhs == null || rhs == null) { | ||
| 453 | - return false; | ||
| 454 | - } | ||
| 455 | - | ||
| 456 | - if (!lhs.keys().equals(rhs.keys())) { | ||
| 457 | - return false; | ||
| 458 | - } | ||
| 459 | - | ||
| 460 | - for (String key : lhs.keys()) { | ||
| 461 | - if (!lhs.value(key).equals(rhs.value(key))) { | ||
| 462 | - return false; | ||
| 463 | - } | ||
| 464 | - } | ||
| 465 | - return true; | ||
| 466 | } | 445 | } |
| 467 | 446 | ||
| 468 | /** | 447 | /** | ... | ... |
| ... | @@ -9,7 +9,7 @@ import org.apache.felix.scr.annotations.Activate; | ... | @@ -9,7 +9,7 @@ import org.apache.felix.scr.annotations.Activate; |
| 9 | import org.apache.felix.scr.annotations.Component; | 9 | import org.apache.felix.scr.annotations.Component; |
| 10 | import org.apache.felix.scr.annotations.Deactivate; | 10 | import org.apache.felix.scr.annotations.Deactivate; |
| 11 | import org.apache.felix.scr.annotations.Service; | 11 | import org.apache.felix.scr.annotations.Service; |
| 12 | -import org.onlab.onos.net.Annotations; | 12 | +import org.onlab.onos.net.AnnotationsUtil; |
| 13 | import org.onlab.onos.net.DefaultAnnotations; | 13 | import org.onlab.onos.net.DefaultAnnotations; |
| 14 | import org.onlab.onos.net.DefaultDevice; | 14 | import org.onlab.onos.net.DefaultDevice; |
| 15 | import org.onlab.onos.net.DefaultPort; | 15 | import org.onlab.onos.net.DefaultPort; |
| ... | @@ -28,6 +28,7 @@ import org.onlab.onos.net.device.DeviceStoreDelegate; | ... | @@ -28,6 +28,7 @@ import org.onlab.onos.net.device.DeviceStoreDelegate; |
| 28 | import org.onlab.onos.net.device.PortDescription; | 28 | import org.onlab.onos.net.device.PortDescription; |
| 29 | import org.onlab.onos.net.provider.ProviderId; | 29 | import org.onlab.onos.net.provider.ProviderId; |
| 30 | import org.onlab.onos.store.AbstractStore; | 30 | import org.onlab.onos.store.AbstractStore; |
| 31 | +import org.onlab.util.NewConcurrentHashMap; | ||
| 31 | import org.slf4j.Logger; | 32 | import org.slf4j.Logger; |
| 32 | 33 | ||
| 33 | import java.util.ArrayList; | 34 | import java.util.ArrayList; |
| ... | @@ -109,8 +110,7 @@ public class SimpleDeviceStore | ... | @@ -109,8 +110,7 @@ public class SimpleDeviceStore |
| 109 | public synchronized DeviceEvent createOrUpdateDevice(ProviderId providerId, DeviceId deviceId, | 110 | public synchronized DeviceEvent createOrUpdateDevice(ProviderId providerId, DeviceId deviceId, |
| 110 | DeviceDescription deviceDescription) { | 111 | DeviceDescription deviceDescription) { |
| 111 | ConcurrentMap<ProviderId, DeviceDescriptions> providerDescs | 112 | ConcurrentMap<ProviderId, DeviceDescriptions> providerDescs |
| 112 | - = createIfAbsentUnchecked(deviceDescs, deviceId, | 113 | + = getDeviceDescriptions(deviceId); |
| 113 | - new InitConcurrentHashMap<ProviderId, DeviceDescriptions>()); | ||
| 114 | 114 | ||
| 115 | Device oldDevice = devices.get(deviceId); | 115 | Device oldDevice = devices.get(deviceId); |
| 116 | 116 | ||
| ... | @@ -151,7 +151,7 @@ public class SimpleDeviceStore | ... | @@ -151,7 +151,7 @@ public class SimpleDeviceStore |
| 151 | // We allow only certain attributes to trigger update | 151 | // We allow only certain attributes to trigger update |
| 152 | if (!Objects.equals(oldDevice.hwVersion(), newDevice.hwVersion()) || | 152 | if (!Objects.equals(oldDevice.hwVersion(), newDevice.hwVersion()) || |
| 153 | !Objects.equals(oldDevice.swVersion(), newDevice.swVersion()) || | 153 | !Objects.equals(oldDevice.swVersion(), newDevice.swVersion()) || |
| 154 | - !isAnnotationsEqual(oldDevice.annotations(), newDevice.annotations())) { | 154 | + !AnnotationsUtil.isEqual(oldDevice.annotations(), newDevice.annotations())) { |
| 155 | 155 | ||
| 156 | synchronized (this) { | 156 | synchronized (this) { |
| 157 | devices.replace(newDevice.id(), oldDevice, newDevice); | 157 | devices.replace(newDevice.id(), oldDevice, newDevice); |
| ... | @@ -238,7 +238,7 @@ public class SimpleDeviceStore | ... | @@ -238,7 +238,7 @@ public class SimpleDeviceStore |
| 238 | Port newPort, | 238 | Port newPort, |
| 239 | ConcurrentMap<PortNumber, Port> ports) { | 239 | ConcurrentMap<PortNumber, Port> ports) { |
| 240 | if (oldPort.isEnabled() != newPort.isEnabled() || | 240 | if (oldPort.isEnabled() != newPort.isEnabled() || |
| 241 | - !isAnnotationsEqual(oldPort.annotations(), newPort.annotations())) { | 241 | + !AnnotationsUtil.isEqual(oldPort.annotations(), newPort.annotations())) { |
| 242 | 242 | ||
| 243 | ports.put(oldPort.number(), newPort); | 243 | ports.put(oldPort.number(), newPort); |
| 244 | return new DeviceEvent(PORT_UPDATED, device, newPort); | 244 | return new DeviceEvent(PORT_UPDATED, device, newPort); |
| ... | @@ -264,11 +264,17 @@ public class SimpleDeviceStore | ... | @@ -264,11 +264,17 @@ public class SimpleDeviceStore |
| 264 | return events; | 264 | return events; |
| 265 | } | 265 | } |
| 266 | 266 | ||
| 267 | + private ConcurrentMap<ProviderId, DeviceDescriptions> getDeviceDescriptions( | ||
| 268 | + DeviceId deviceId) { | ||
| 269 | + return createIfAbsentUnchecked(deviceDescs, deviceId, | ||
| 270 | + NewConcurrentHashMap.<ProviderId, DeviceDescriptions>ifNeeded()); | ||
| 271 | + } | ||
| 272 | + | ||
| 267 | // Gets the map of ports for the specified device; if one does not already | 273 | // Gets the map of ports for the specified device; if one does not already |
| 268 | // exist, it creates and registers a new one. | 274 | // exist, it creates and registers a new one. |
| 269 | private ConcurrentMap<PortNumber, Port> getPortMap(DeviceId deviceId) { | 275 | private ConcurrentMap<PortNumber, Port> getPortMap(DeviceId deviceId) { |
| 270 | return createIfAbsentUnchecked(devicePorts, deviceId, | 276 | return createIfAbsentUnchecked(devicePorts, deviceId, |
| 271 | - new InitConcurrentHashMap<PortNumber, Port>()); | 277 | + NewConcurrentHashMap.<PortNumber, Port>ifNeeded()); |
| 272 | } | 278 | } |
| 273 | 279 | ||
| 274 | @Override | 280 | @Override |
| ... | @@ -325,31 +331,12 @@ public class SimpleDeviceStore | ... | @@ -325,31 +331,12 @@ public class SimpleDeviceStore |
| 325 | public DeviceEvent removeDevice(DeviceId deviceId) { | 331 | public DeviceEvent removeDevice(DeviceId deviceId) { |
| 326 | synchronized (this) { | 332 | synchronized (this) { |
| 327 | Device device = devices.remove(deviceId); | 333 | Device device = devices.remove(deviceId); |
| 334 | + // FIXME: should we be removing deviceDescs also? | ||
| 328 | return device == null ? null : | 335 | return device == null ? null : |
| 329 | new DeviceEvent(DEVICE_REMOVED, device, null); | 336 | new DeviceEvent(DEVICE_REMOVED, device, null); |
| 330 | } | 337 | } |
| 331 | } | 338 | } |
| 332 | 339 | ||
| 333 | - private static boolean isAnnotationsEqual(Annotations lhs, Annotations rhs) { | ||
| 334 | - if (lhs == rhs) { | ||
| 335 | - return true; | ||
| 336 | - } | ||
| 337 | - if (lhs == null || rhs == null) { | ||
| 338 | - return false; | ||
| 339 | - } | ||
| 340 | - | ||
| 341 | - if (!lhs.keys().equals(rhs.keys())) { | ||
| 342 | - return false; | ||
| 343 | - } | ||
| 344 | - | ||
| 345 | - for (String key : lhs.keys()) { | ||
| 346 | - if (!lhs.value(key).equals(rhs.value(key))) { | ||
| 347 | - return false; | ||
| 348 | - } | ||
| 349 | - } | ||
| 350 | - return true; | ||
| 351 | - } | ||
| 352 | - | ||
| 353 | /** | 340 | /** |
| 354 | * Returns a Device, merging description given from multiple Providers. | 341 | * Returns a Device, merging description given from multiple Providers. |
| 355 | * | 342 | * |
| ... | @@ -445,15 +432,6 @@ public class SimpleDeviceStore | ... | @@ -445,15 +432,6 @@ public class SimpleDeviceStore |
| 445 | return fallBackPrimary; | 432 | return fallBackPrimary; |
| 446 | } | 433 | } |
| 447 | 434 | ||
| 448 | - // TODO: can be made generic | ||
| 449 | - private static final class InitConcurrentHashMap<K, V> implements | ||
| 450 | - ConcurrentInitializer<ConcurrentMap<K, V>> { | ||
| 451 | - @Override | ||
| 452 | - public ConcurrentMap<K, V> get() throws ConcurrentException { | ||
| 453 | - return new ConcurrentHashMap<>(); | ||
| 454 | - } | ||
| 455 | - } | ||
| 456 | - | ||
| 457 | public static final class InitDeviceDescs | 435 | public static final class InitDeviceDescs |
| 458 | implements ConcurrentInitializer<DeviceDescriptions> { | 436 | implements ConcurrentInitializer<DeviceDescriptions> { |
| 459 | private final DeviceDescription deviceDesc; | 437 | private final DeviceDescription deviceDesc; | ... | ... |
This diff is collapsed. Click to expand it.
| ... | @@ -126,6 +126,7 @@ public class SimpleDeviceStoreTest { | ... | @@ -126,6 +126,7 @@ public class SimpleDeviceStoreTest { |
| 126 | assertEquals(SN, device.serialNumber()); | 126 | assertEquals(SN, device.serialNumber()); |
| 127 | } | 127 | } |
| 128 | 128 | ||
| 129 | + // TODO slice this out somewhere | ||
| 129 | /** | 130 | /** |
| 130 | * Verifies that Annotations created by merging {@code annotations} is | 131 | * Verifies that Annotations created by merging {@code annotations} is |
| 131 | * equal to actual Annotations. | 132 | * equal to actual Annotations. |
| ... | @@ -133,7 +134,7 @@ public class SimpleDeviceStoreTest { | ... | @@ -133,7 +134,7 @@ public class SimpleDeviceStoreTest { |
| 133 | * @param actual Annotations to check | 134 | * @param actual Annotations to check |
| 134 | * @param annotations | 135 | * @param annotations |
| 135 | */ | 136 | */ |
| 136 | - private static void assertAnnotationsEquals(Annotations actual, SparseAnnotations... annotations) { | 137 | + public static void assertAnnotationsEquals(Annotations actual, SparseAnnotations... annotations) { |
| 137 | DefaultAnnotations expected = DefaultAnnotations.builder().build(); | 138 | DefaultAnnotations expected = DefaultAnnotations.builder().build(); |
| 138 | for (SparseAnnotations a : annotations) { | 139 | for (SparseAnnotations a : annotations) { |
| 139 | expected = DefaultAnnotations.merge(expected, a); | 140 | expected = DefaultAnnotations.merge(expected, a); |
| ... | @@ -347,6 +348,7 @@ public class SimpleDeviceStoreTest { | ... | @@ -347,6 +348,7 @@ public class SimpleDeviceStoreTest { |
| 347 | assertFalse("Port is disabled", event.port().isEnabled()); | 348 | assertFalse("Port is disabled", event.port().isEnabled()); |
| 348 | 349 | ||
| 349 | } | 350 | } |
| 351 | + | ||
| 350 | @Test | 352 | @Test |
| 351 | public final void testUpdatePortStatusAncillary() { | 353 | public final void testUpdatePortStatusAncillary() { |
| 352 | putDeviceAncillary(DID1, SW1); | 354 | putDeviceAncillary(DID1, SW1); | ... | ... |
| ... | @@ -4,7 +4,9 @@ import static org.junit.Assert.*; | ... | @@ -4,7 +4,9 @@ import static org.junit.Assert.*; |
| 4 | import static org.onlab.onos.net.DeviceId.deviceId; | 4 | import static org.onlab.onos.net.DeviceId.deviceId; |
| 5 | import static org.onlab.onos.net.Link.Type.*; | 5 | import static org.onlab.onos.net.Link.Type.*; |
| 6 | import static org.onlab.onos.net.link.LinkEvent.Type.*; | 6 | import static org.onlab.onos.net.link.LinkEvent.Type.*; |
| 7 | +import static org.onlab.onos.store.trivial.impl.SimpleDeviceStoreTest.assertAnnotationsEquals; | ||
| 7 | 8 | ||
| 9 | +import java.util.Collections; | ||
| 8 | import java.util.HashMap; | 10 | import java.util.HashMap; |
| 9 | import java.util.Map; | 11 | import java.util.Map; |
| 10 | import java.util.Set; | 12 | import java.util.Set; |
| ... | @@ -18,10 +20,12 @@ import org.junit.BeforeClass; | ... | @@ -18,10 +20,12 @@ import org.junit.BeforeClass; |
| 18 | import org.junit.Ignore; | 20 | import org.junit.Ignore; |
| 19 | import org.junit.Test; | 21 | import org.junit.Test; |
| 20 | import org.onlab.onos.net.ConnectPoint; | 22 | import org.onlab.onos.net.ConnectPoint; |
| 23 | +import org.onlab.onos.net.DefaultAnnotations; | ||
| 21 | import org.onlab.onos.net.DeviceId; | 24 | import org.onlab.onos.net.DeviceId; |
| 22 | import org.onlab.onos.net.Link; | 25 | import org.onlab.onos.net.Link; |
| 23 | import org.onlab.onos.net.LinkKey; | 26 | import org.onlab.onos.net.LinkKey; |
| 24 | import org.onlab.onos.net.PortNumber; | 27 | import org.onlab.onos.net.PortNumber; |
| 28 | +import org.onlab.onos.net.SparseAnnotations; | ||
| 25 | import org.onlab.onos.net.Link.Type; | 29 | import org.onlab.onos.net.Link.Type; |
| 26 | import org.onlab.onos.net.link.DefaultLinkDescription; | 30 | import org.onlab.onos.net.link.DefaultLinkDescription; |
| 27 | import org.onlab.onos.net.link.LinkEvent; | 31 | import org.onlab.onos.net.link.LinkEvent; |
| ... | @@ -37,6 +41,7 @@ import com.google.common.collect.Iterables; | ... | @@ -37,6 +41,7 @@ import com.google.common.collect.Iterables; |
| 37 | public class SimpleLinkStoreTest { | 41 | public class SimpleLinkStoreTest { |
| 38 | 42 | ||
| 39 | private static final ProviderId PID = new ProviderId("of", "foo"); | 43 | private static final ProviderId PID = new ProviderId("of", "foo"); |
| 44 | + private static final ProviderId PIDA = new ProviderId("of", "bar", true); | ||
| 40 | private static final DeviceId DID1 = deviceId("of:foo"); | 45 | private static final DeviceId DID1 = deviceId("of:foo"); |
| 41 | private static final DeviceId DID2 = deviceId("of:bar"); | 46 | private static final DeviceId DID2 = deviceId("of:bar"); |
| 42 | 47 | ||
| ... | @@ -44,6 +49,23 @@ public class SimpleLinkStoreTest { | ... | @@ -44,6 +49,23 @@ public class SimpleLinkStoreTest { |
| 44 | private static final PortNumber P2 = PortNumber.portNumber(2); | 49 | private static final PortNumber P2 = PortNumber.portNumber(2); |
| 45 | private static final PortNumber P3 = PortNumber.portNumber(3); | 50 | private static final PortNumber P3 = PortNumber.portNumber(3); |
| 46 | 51 | ||
| 52 | + private static final SparseAnnotations A1 = DefaultAnnotations.builder() | ||
| 53 | + .set("A1", "a1") | ||
| 54 | + .set("B1", "b1") | ||
| 55 | + .build(); | ||
| 56 | + private static final SparseAnnotations A1_2 = DefaultAnnotations.builder() | ||
| 57 | + .remove("A1") | ||
| 58 | + .set("B3", "b3") | ||
| 59 | + .build(); | ||
| 60 | + private static final SparseAnnotations A2 = DefaultAnnotations.builder() | ||
| 61 | + .set("A2", "a2") | ||
| 62 | + .set("B2", "b2") | ||
| 63 | + .build(); | ||
| 64 | + private static final SparseAnnotations A2_2 = DefaultAnnotations.builder() | ||
| 65 | + .remove("A2") | ||
| 66 | + .set("B4", "b4") | ||
| 67 | + .build(); | ||
| 68 | + | ||
| 47 | 69 | ||
| 48 | private SimpleLinkStore simpleLinkStore; | 70 | private SimpleLinkStore simpleLinkStore; |
| 49 | private LinkStore linkStore; | 71 | private LinkStore linkStore; |
| ... | @@ -270,6 +292,59 @@ public class SimpleLinkStoreTest { | ... | @@ -270,6 +292,59 @@ public class SimpleLinkStoreTest { |
| 270 | } | 292 | } |
| 271 | 293 | ||
| 272 | @Test | 294 | @Test |
| 295 | + public final void testCreateOrUpdateLinkAncillary() { | ||
| 296 | + ConnectPoint src = new ConnectPoint(DID1, P1); | ||
| 297 | + ConnectPoint dst = new ConnectPoint(DID2, P2); | ||
| 298 | + | ||
| 299 | + // add Ancillary link | ||
| 300 | + LinkEvent event = linkStore.createOrUpdateLink(PIDA, | ||
| 301 | + new DefaultLinkDescription(src, dst, INDIRECT, A1)); | ||
| 302 | + | ||
| 303 | + assertNull("Ancillary only link is ignored", event); | ||
| 304 | + | ||
| 305 | + // add Primary link | ||
| 306 | + LinkEvent event2 = linkStore.createOrUpdateLink(PID, | ||
| 307 | + new DefaultLinkDescription(src, dst, INDIRECT, A2)); | ||
| 308 | + | ||
| 309 | + assertLink(DID1, P1, DID2, P2, INDIRECT, event2.subject()); | ||
| 310 | + assertAnnotationsEquals(event2.subject().annotations(), A2, A1); | ||
| 311 | + assertEquals(LINK_ADDED, event2.type()); | ||
| 312 | + | ||
| 313 | + // update link type | ||
| 314 | + LinkEvent event3 = linkStore.createOrUpdateLink(PID, | ||
| 315 | + new DefaultLinkDescription(src, dst, DIRECT, A2)); | ||
| 316 | + assertLink(DID1, P1, DID2, P2, DIRECT, event3.subject()); | ||
| 317 | + assertAnnotationsEquals(event3.subject().annotations(), A2, A1); | ||
| 318 | + assertEquals(LINK_UPDATED, event3.type()); | ||
| 319 | + | ||
| 320 | + | ||
| 321 | + // no change | ||
| 322 | + LinkEvent event4 = linkStore.createOrUpdateLink(PID, | ||
| 323 | + new DefaultLinkDescription(src, dst, DIRECT)); | ||
| 324 | + assertNull("No change event expected", event4); | ||
| 325 | + | ||
| 326 | + // update link annotation (Primary) | ||
| 327 | + LinkEvent event5 = linkStore.createOrUpdateLink(PID, | ||
| 328 | + new DefaultLinkDescription(src, dst, DIRECT, A2_2)); | ||
| 329 | + assertLink(DID1, P1, DID2, P2, DIRECT, event5.subject()); | ||
| 330 | + assertAnnotationsEquals(event5.subject().annotations(), A2, A2_2, A1); | ||
| 331 | + assertEquals(LINK_UPDATED, event5.type()); | ||
| 332 | + | ||
| 333 | + // update link annotation (Ancillary) | ||
| 334 | + LinkEvent event6 = linkStore.createOrUpdateLink(PIDA, | ||
| 335 | + new DefaultLinkDescription(src, dst, DIRECT, A1_2)); | ||
| 336 | + assertLink(DID1, P1, DID2, P2, DIRECT, event6.subject()); | ||
| 337 | + assertAnnotationsEquals(event6.subject().annotations(), A2, A2_2, A1, A1_2); | ||
| 338 | + assertEquals(LINK_UPDATED, event6.type()); | ||
| 339 | + | ||
| 340 | + // update link type (Ancillary) : ignored | ||
| 341 | + LinkEvent event7 = linkStore.createOrUpdateLink(PIDA, | ||
| 342 | + new DefaultLinkDescription(src, dst, EDGE)); | ||
| 343 | + assertNull("Ancillary change other than annotation is ignored", event7); | ||
| 344 | + } | ||
| 345 | + | ||
| 346 | + | ||
| 347 | + @Test | ||
| 273 | public final void testRemoveLink() { | 348 | public final void testRemoveLink() { |
| 274 | final ConnectPoint d1P1 = new ConnectPoint(DID1, P1); | 349 | final ConnectPoint d1P1 = new ConnectPoint(DID1, P1); |
| 275 | final ConnectPoint d2P2 = new ConnectPoint(DID2, P2); | 350 | final ConnectPoint d2P2 = new ConnectPoint(DID2, P2); |
| ... | @@ -291,6 +366,30 @@ public class SimpleLinkStoreTest { | ... | @@ -291,6 +366,30 @@ public class SimpleLinkStoreTest { |
| 291 | assertLink(linkId2, DIRECT, linkStore.getLink(d2P2, d1P1)); | 366 | assertLink(linkId2, DIRECT, linkStore.getLink(d2P2, d1P1)); |
| 292 | } | 367 | } |
| 293 | 368 | ||
| 369 | + @Test | ||
| 370 | + public final void testAncillaryOnlyNotVisible() { | ||
| 371 | + ConnectPoint src = new ConnectPoint(DID1, P1); | ||
| 372 | + ConnectPoint dst = new ConnectPoint(DID2, P2); | ||
| 373 | + | ||
| 374 | + // add Ancillary link | ||
| 375 | + linkStore.createOrUpdateLink(PIDA, | ||
| 376 | + new DefaultLinkDescription(src, dst, INDIRECT, A1)); | ||
| 377 | + | ||
| 378 | + // Ancillary only link should not be visible | ||
| 379 | + assertEquals(0, linkStore.getLinkCount()); | ||
| 380 | + | ||
| 381 | + assertTrue(Iterables.isEmpty(linkStore.getLinks())); | ||
| 382 | + | ||
| 383 | + assertNull(linkStore.getLink(src, dst)); | ||
| 384 | + | ||
| 385 | + assertEquals(Collections.emptySet(), linkStore.getIngressLinks(dst)); | ||
| 386 | + | ||
| 387 | + assertEquals(Collections.emptySet(), linkStore.getEgressLinks(src)); | ||
| 388 | + | ||
| 389 | + assertEquals(Collections.emptySet(), linkStore.getDeviceEgressLinks(DID1)); | ||
| 390 | + assertEquals(Collections.emptySet(), linkStore.getDeviceIngressLinks(DID2)); | ||
| 391 | + } | ||
| 392 | + | ||
| 294 | // If Delegates should be called only on remote events, | 393 | // If Delegates should be called only on remote events, |
| 295 | // then Simple* should never call them, thus not test required. | 394 | // then Simple* should never call them, thus not test required. |
| 296 | @Ignore("Ignore until Delegate spec. is clear.") | 395 | @Ignore("Ignore until Delegate spec. is clear.") | ... | ... |
| 1 | +package org.onlab.util; | ||
| 2 | + | ||
| 3 | +import java.util.concurrent.ConcurrentHashMap; | ||
| 4 | +import java.util.concurrent.ConcurrentMap; | ||
| 5 | + | ||
| 6 | +import org.apache.commons.lang3.concurrent.ConcurrentException; | ||
| 7 | +import org.apache.commons.lang3.concurrent.ConcurrentInitializer; | ||
| 8 | + | ||
| 9 | +/** | ||
| 10 | + * Creates an instance of new ConcurrentHashMap on each {@link #get()} call. | ||
| 11 | + * <p> | ||
| 12 | + * To be used with | ||
| 13 | + * {@link org.apache.commons.lang3.concurrent.ConcurrentUtils#createIfAbsent() | ||
| 14 | + * ConcurrentUtils#createIfAbsent} | ||
| 15 | + * | ||
| 16 | + * @param <K> ConcurrentHashMap key type | ||
| 17 | + * @param <V> ConcurrentHashMap value type | ||
| 18 | + */ | ||
| 19 | +public final class NewConcurrentHashMap<K, V> | ||
| 20 | + implements ConcurrentInitializer<ConcurrentMap<K, V>> { | ||
| 21 | + | ||
| 22 | + public static final NewConcurrentHashMap<?, ?> INSTANCE = new NewConcurrentHashMap<>(); | ||
| 23 | + | ||
| 24 | + @SuppressWarnings("unchecked") | ||
| 25 | + public static <K, V> NewConcurrentHashMap<K, V> ifNeeded() { | ||
| 26 | + return (NewConcurrentHashMap<K, V>) INSTANCE; | ||
| 27 | + } | ||
| 28 | + | ||
| 29 | + @Override | ||
| 30 | + public ConcurrentMap<K, V> get() throws ConcurrentException { | ||
| 31 | + return new ConcurrentHashMap<>(); | ||
| 32 | + } | ||
| 33 | +} |
-
Please register or login to post a comment