SpeakerIdMapping is immutable 70/98570/3
authorRobert Varga <robert.varga@pantheon.tech>
Tue, 16 Nov 2021 10:32:08 +0000 (11:32 +0100)
committerRobert Varga <robert.varga@pantheon.tech>
Tue, 16 Nov 2021 11:18:23 +0000 (12:18 +0100)
The intent here is to provide an immutable view of which address maps
to which ID. Do not subclass HashMap for that, as that just wrecks the
ability to reason about what is going on.

JIRA: BGPCEP-983
Change-Id: I8f41e22e5b3b64c7dc49a0219eeeeb673bd5c111
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
pcep/api/src/main/java/org/opendaylight/protocol/pcep/SpeakerIdMapping.java
pcep/pcc-mock/src/test/java/org/opendaylight/protocol/pcep/pcc/mock/PCCMockCommon.java
pcep/testtool/src/main/java/org/opendaylight/protocol/pcep/testtool/TestToolPCEPDispatcherDependencies.java
pcep/topology/topology-provider/src/main/java/org/opendaylight/bgpcep/pcep/topology/provider/ServerSessionManager.java
pcep/topology/topology-provider/src/main/java/org/opendaylight/bgpcep/pcep/topology/provider/config/PCEPTopologyConfiguration.java
pcep/topology/topology-provider/src/main/java/org/opendaylight/bgpcep/pcep/topology/provider/config/PCEPTopologyProviderUtil.java

index f31736295e23983c5dda0f809699d938587f8274..23dbcb01cfdf4505e4897dea36e13a64ad7ca790 100644 (file)
@@ -5,20 +5,38 @@
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
-
 package org.opendaylight.protocol.pcep;
 
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
 import java.net.InetAddress;
-import java.util.HashMap;
+import java.util.Map;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.yangtools.concepts.Immutable;
+
+public final class SpeakerIdMapping implements Immutable {
+    private static final @NonNull SpeakerIdMapping EMPTY = new SpeakerIdMapping(ImmutableMap.of());
+
+    private final ImmutableMap<InetAddress, byte[]> map;
 
-public final class SpeakerIdMapping extends HashMap<InetAddress, byte[]> {
-    private static final long serialVersionUID = 1L;
+    private SpeakerIdMapping(final Map<InetAddress, byte[]> map) {
+        this.map = ImmutableMap.copyOf(map);
+    }
+
+    public static @NonNull SpeakerIdMapping of() {
+        return EMPTY;
+    }
 
-    private SpeakerIdMapping() {
-        super();
+    public static @NonNull SpeakerIdMapping copyOf(final Map<InetAddress, byte[]> map) {
+        return map.isEmpty() ? of()
+            // Defensive: disconnect byte[]s from caller
+            : new SpeakerIdMapping(Maps.transformValues(map, byte[]::clone));
     }
 
-    public static SpeakerIdMapping getSpeakerIdMap() {
-        return new SpeakerIdMapping();
+    public byte @Nullable [] speakerIdForAddress(final InetAddress address) {
+        final byte[] found = map.get(address);
+        // Defensive: do not leak byte[]
+        return found == null ? null : found.clone();
     }
 }
\ No newline at end of file
index d89afe6a63af1c0db3703b24c9701146befd000f..172d34cf824906a2c3e3ca765efd32953c857ed4 100644 (file)
@@ -68,9 +68,9 @@ public abstract class PCCMockCommon {
     private static final long SLEEP_FOR = 50;
     private final int port = InetSocketAddressUtil.getRandomPort();
     final InetSocketAddress remoteAddress = InetSocketAddressUtil
-            .getRandomLoopbackInetSocketAddress(this.port);
+            .getRandomLoopbackInetSocketAddress(port);
     final InetSocketAddress localAddress = InetSocketAddressUtil
-            .getRandomLoopbackInetSocketAddress(this.port);
+            .getRandomLoopbackInetSocketAddress(port);
     PCCSessionListener pccSessionListener;
     private PCEPDispatcher pceDispatcher;
     private final PCEPExtensionProviderContext extensionProvider = new SimplePCEPExtensionProviderContext();
@@ -86,8 +86,8 @@ public abstract class PCCMockCommon {
 
         ServiceLoader.load(PCEPExtensionProviderActivator.class).forEach(act -> act.start(extensionProvider));
 
-        this.messageRegistry = this.extensionProvider.getMessageHandlerRegistry();
-        this.pceDispatcher = new PCEPDispatcherImpl(this.messageRegistry, nf, new NioEventLoopGroup(),
+        messageRegistry = extensionProvider.getMessageHandlerRegistry();
+        pceDispatcher = new PCEPDispatcherImpl(messageRegistry, nf, new NioEventLoopGroup(),
                 new NioEventLoopGroup());
     }
 
@@ -126,10 +126,10 @@ public abstract class PCCMockCommon {
             serverAddress2, final PCEPPeerProposal peerProposal) {
         final StatefulActivator activator07 = new StatefulActivator();
         final SyncOptimizationsActivator optimizationsActivator = new SyncOptimizationsActivator();
-        activator07.start(this.extensionProvider);
-        optimizationsActivator.start(this.extensionProvider);
+        activator07.start(extensionProvider);
+        optimizationsActivator.start(extensionProvider);
 
-        final ChannelFuture future = this.pceDispatcher
+        final ChannelFuture future = pceDispatcher
                 .createServer(new DispatcherDependencies(serverAddress2, factory, peerProposal));
         waitFutureSuccess(future);
         return future.channel();
@@ -212,15 +212,15 @@ public abstract class PCCMockCommon {
     }
 
     Future<PCEPSession> createPCCSession(final Uint64 dbVersion) {
-        final PCCDispatcherImpl pccDispatcher = new PCCDispatcherImpl(this.messageRegistry);
+        final PCCDispatcherImpl pccDispatcher = new PCCDispatcherImpl(messageRegistry);
         final PCEPSessionNegotiatorFactory<PCEPSessionImpl> snf = getSessionNegotiatorFactory();
-        final PCCTunnelManager tunnelManager = new PCCTunnelManagerImpl(3, this.localAddress.getAddress(),
+        final PCCTunnelManager tunnelManager = new PCCTunnelManagerImpl(3, localAddress.getAddress(),
                 0, -1, new HashedWheelTimer(), Optional.empty());
 
-        return pccDispatcher.createClient(this.remoteAddress, -1, () -> {
-            this.pccSessionListener = new PCCSessionListener(1, tunnelManager, false);
-            return this.pccSessionListener;
-        }, snf, KeyMapping.getKeyMapping(), this.localAddress, dbVersion);
+        return pccDispatcher.createClient(remoteAddress, -1, () -> {
+            pccSessionListener = new PCCSessionListener(1, tunnelManager, false);
+            return pccSessionListener;
+        }, snf, KeyMapping.getKeyMapping(), localAddress, dbVersion);
     }
 
     private PCEPSessionNegotiatorFactory<PCEPSessionImpl> getSessionNegotiatorFactory() {
@@ -229,12 +229,11 @@ public abstract class PCCMockCommon {
     }
 
     TestingSessionListener getListener(final TestingSessionListenerFactory factory) {
-        return checkSessionListenerNotNull(factory, this.localAddress.getHostString());
+        return checkSessionListenerNotNull(factory, localAddress.getHostString());
     }
 
-    private class DispatcherDependencies implements PCEPDispatcherDependencies {
+    private static class DispatcherDependencies implements PCEPDispatcherDependencies {
         final KeyMapping keys = KeyMapping.getKeyMapping();
-        final SpeakerIdMapping ids = SpeakerIdMapping.getSpeakerIdMap();
         private final InetSocketAddress address;
         private final TestingSessionListenerFactory listenerFactory;
         private final PCEPPeerProposal peerProposal;
@@ -250,7 +249,7 @@ public abstract class PCCMockCommon {
 
         @Override
         public InetSocketAddress getAddress() {
-            return this.address;
+            return address;
         }
 
         @Override
@@ -260,17 +259,17 @@ public abstract class PCCMockCommon {
 
         @Override
         public SpeakerIdMapping getSpeakerIdMapping() {
-            return ids;
+            return SpeakerIdMapping.of();
         }
 
         @Override
         public PCEPSessionListenerFactory getListenerFactory() {
-            return this.listenerFactory;
+            return listenerFactory;
         }
 
         @Override
         public PCEPPeerProposal getPeerProposal() {
-            return this.peerProposal;
+            return peerProposal;
         }
     }
 }
index d697edc87103eae0c1fe7b66b672a057bbb3d320..5369402ffbd0533388d55df9424f859649178df9 100644 (file)
@@ -5,7 +5,6 @@
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
-
 package org.opendaylight.protocol.pcep.testtool;
 
 import java.net.InetSocketAddress;
@@ -18,7 +17,6 @@ public final class TestToolPCEPDispatcherDependencies implements PCEPDispatcherD
     private final PCEPSessionListenerFactory listenerFactory = new TestingSessionListenerFactory();
     private final InetSocketAddress address;
     private final KeyMapping keys = KeyMapping.getKeyMapping();
-    private final SpeakerIdMapping speakerIds = SpeakerIdMapping.getSpeakerIdMap();
 
     TestToolPCEPDispatcherDependencies(final InetSocketAddress address) {
         this.address = address;
@@ -26,21 +24,21 @@ public final class TestToolPCEPDispatcherDependencies implements PCEPDispatcherD
 
     @Override
     public InetSocketAddress getAddress() {
-        return this.address;
+        return address;
     }
 
     @Override
     public KeyMapping getKeys() {
-        return this.keys;
+        return keys;
     }
 
     @Override
     public SpeakerIdMapping getSpeakerIdMapping() {
-        return this.speakerIds;
+        return SpeakerIdMapping.of();
     }
 
     @Override
     public PCEPSessionListenerFactory getListenerFactory() {
-        return this.listenerFactory;
+        return listenerFactory;
     }
 }
index d8e212ead19cea99b0cf94b85e3c36ce7008a271..08161687c240033ae7f03bf802b7682db9e8903d 100644 (file)
@@ -257,8 +257,8 @@ final class ServerSessionManager implements PCEPSessionListenerFactory, Topology
     @Override
     public void setPeerSpecificProposal(final InetSocketAddress address, final TlvsBuilder openBuilder) {
         requireNonNull(address);
-        final byte[] speakerId = pcepDispatcherDependencies.getSpeakerIdMapping().get(address.getAddress());
-        peerProposal.setPeerProposal(createNodeId(address.getAddress()), openBuilder, speakerId);
+        peerProposal.setPeerProposal(createNodeId(address.getAddress()), openBuilder,
+            pcepDispatcherDependencies.getSpeakerIdMapping().speakerIdForAddress(address.getAddress()));
     }
 
     short getRpcTimeout() {
index 2023032c27b8477a7e2cb237660c7738ace59af8..cef1cab4c98795ac0b7adbc565f444f724309040 100644 (file)
@@ -9,15 +9,24 @@ package org.opendaylight.bgpcep.pcep.topology.provider.config;
 
 import static java.util.Objects.requireNonNull;
 
+import com.google.common.collect.ImmutableMap;
+import com.google.common.net.InetAddresses;
+import java.net.InetAddress;
 import java.net.InetSocketAddress;
+import java.util.Map;
 import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
 import org.opendaylight.protocol.concepts.KeyMapping;
 import org.opendaylight.protocol.pcep.SpeakerIdMapping;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.config.rev200120.pcep.config.SessionConfig;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.config.rev181109.PcepNodeConfig;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.sync.optimizations.config.rev181109.PcepNodeSyncConfig;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 
 public final class PCEPTopologyConfiguration {
@@ -25,42 +34,69 @@ public final class PCEPTopologyConfiguration {
     private final KeyMapping keys;
     private final TopologyId topologyId;
     private final short rpcTimeout;
-    private final SpeakerIdMapping speakerIds;
+    private final @NonNull SpeakerIdMapping speakerIds;
     private final InstanceIdentifier<Topology> topology;
 
     public PCEPTopologyConfiguration(final @NonNull SessionConfig config, final @NonNull Topology topology) {
         requireNonNull(topology);
-        this.address = PCEPTopologyProviderUtil.getInetSocketAddress(requireNonNull(config.getListenAddress()),
+        address = PCEPTopologyProviderUtil.getInetSocketAddress(requireNonNull(config.getListenAddress()),
                 requireNonNull(config.getListenPort()));
-        this.keys = requireNonNull(PCEPTopologyProviderUtil.contructKeys(topology));
-        this.speakerIds = requireNonNull(PCEPTopologyProviderUtil.contructSpeakersId(topology));
-        this.topologyId = requireNonNull(topology.getTopologyId());
-        this.rpcTimeout = config.getRpcTimeout();
+        keys = requireNonNull(PCEPTopologyProviderUtil.contructKeys(topology));
+        speakerIds = contructSpeakersId(topology.getNode());
+        topologyId = requireNonNull(topology.getTopologyId());
+        rpcTimeout = config.getRpcTimeout();
         this.topology = InstanceIdentifier.builder(NetworkTopology.class)
-                .child(Topology.class, new TopologyKey(this.topologyId)).build();
+                .child(Topology.class, new TopologyKey(topologyId)).build();
     }
 
     public @NonNull TopologyId getTopologyId() {
-        return this.topologyId;
+        return topologyId;
     }
 
     public @NonNull InstanceIdentifier<Topology> getTopology() {
-        return this.topology;
+        return topology;
     }
 
     public short getRpcTimeout() {
-        return this.rpcTimeout;
+        return rpcTimeout;
     }
 
     public @NonNull InetSocketAddress getAddress() {
-        return this.address;
+        return address;
     }
 
     public @NonNull KeyMapping getKeys() {
-        return this.keys;
+        return keys;
     }
 
     public @NonNull SpeakerIdMapping getSpeakerIds() {
-        return this.speakerIds;
+        return speakerIds;
+    }
+
+    private static @NonNull SpeakerIdMapping contructSpeakersId(final @Nullable Map<NodeKey, Node> nodes) {
+        if (nodes == null) {
+            return SpeakerIdMapping.of();
+        }
+
+        final var builder = ImmutableMap.<InetAddress, byte[]>builder();
+        for (var node : nodes.values()) {
+            if (node != null) {
+                final var nodeConfig = node.augmentation(PcepNodeConfig.class);
+                if (nodeConfig != null) {
+                    final var sessionConfig = nodeConfig.getSessionConfig();
+                    if (sessionConfig != null) {
+                        final var nodeSyncConfig = sessionConfig.augmentation(PcepNodeSyncConfig.class);
+                        if (nodeSyncConfig != null) {
+                            final var speakerEntityId = nodeSyncConfig.getSpeakerEntityIdValue();
+                            if (speakerEntityId != null) {
+                                builder.put(InetAddresses.forString(node.getNodeId().getValue()), speakerEntityId);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        return SpeakerIdMapping.copyOf(builder.build());
     }
 }
index f29cbfd3586a8bb06ebfd58f5a7bda8fb56e63a9..e1bcf356f6298bd1f4fcdf0e219f305229358497 100644 (file)
@@ -14,13 +14,11 @@ import java.nio.charset.StandardCharsets;
 import java.util.Objects;
 import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.protocol.concepts.KeyMapping;
-import org.opendaylight.protocol.pcep.SpeakerIdMapping;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IetfInetUtil;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddressNoZone;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.rfc2385.cfg.rev160324.Rfc2385Key;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.config.rev181109.PcepNodeConfig;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.sync.optimizations.config.rev181109.PcepNodeSyncConfig;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
 
 final class PCEPTopologyProviderUtil {
@@ -55,26 +53,4 @@ final class PCEPTopologyProviderUtil {
             final @NonNull PortNumber port) {
         return new InetSocketAddress(IetfInetUtil.INSTANCE.inetAddressForNoZone(address), port.getValue().toJava());
     }
-
-    static SpeakerIdMapping contructSpeakersId(final Topology topology) {
-        final SpeakerIdMapping ret = SpeakerIdMapping.getSpeakerIdMap();
-        if (topology.getNode() == null) {
-            return ret;
-        }
-        topology.nonnullNode().values().stream()
-                .filter(Objects::nonNull)
-                .filter(node -> node.augmentation(PcepNodeConfig.class) != null)
-                .filter(node -> node.augmentation(PcepNodeConfig.class).getSessionConfig() != null)
-                .filter(node -> node.augmentation(PcepNodeConfig.class).getSessionConfig()
-                        .augmentation(PcepNodeSyncConfig.class) != null)
-                .forEach(node -> {
-                    final PcepNodeConfig config = node.augmentation(PcepNodeConfig.class);
-                    final PcepNodeSyncConfig nodeSyncConfig = config.getSessionConfig()
-                            .augmentation(PcepNodeSyncConfig.class);
-                    final InetAddress address = InetAddresses.forString(node.getNodeId().getValue());
-                    ret.put(address, nodeSyncConfig.getSpeakerEntityIdValue());
-                });
-
-        return ret;
-    }
 }