SimpleLinkStore with annotation and multi-provider support
Change-Id: I98a35c4497363c6115fd0c61d140dfe7790e6cee
Showing
8 changed files
with
181 additions
and
62 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,32 +438,11 @@ public class GossipDeviceStore | ... | @@ -438,32 +438,11 @@ public class GossipDeviceStore |
438 | 438 | ||
439 | @Override | 439 | @Override |
440 | public DeviceEvent removeDevice(DeviceId deviceId) { | 440 | public DeviceEvent removeDevice(DeviceId deviceId) { |
441 | - synchronized (this) { | ||
442 | Device device = devices.remove(deviceId); | 441 | 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 | } | 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 | - } | ||
467 | 446 | ||
468 | /** | 447 | /** |
469 | * Returns a Device, merging description given from multiple Providers. | 448 | * Returns a Device, merging description given from multiple Providers. | ... | ... |
... | @@ -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