Expose DeviceFlowRegistry.createKey() 65/110165/9
authorRobert Varga <robert.varga@pantheon.tech>
Tue, 6 Feb 2024 21:20:20 +0000 (22:20 +0100)
committerRobert Varga <nite@hq.sk>
Thu, 8 Feb 2024 17:34:16 +0000 (17:34 +0000)
We are lugging around protocol version, which is already known to
DeviceFlowRegistry implementation only to circle back to a utility
method, which then performs lookup and static dispatch.

Short circuit this dance by exposing createKey(), which allows
DeviceFlowRegistryImpl to cleanly integrate with rest of the world.

All sorts of aspects are addressed as well:
- use a record for the canonical key implementation
- use well-known constants for FlowRegistryKeyFactory and simple if/else
  dispatch
- make MatchNormalizationUtil a class capturing its associated version
- AddressNormalizationUtil is turned into an enum

Future improvements are marked with FIXMEs, as these will further
reduce reliance on constant protocol version passing.

Change-Id: I70d22f0db65b97df4b63c2bc1bf4cff457a11785
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
26 files changed:
openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/OFConstants.java
openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/md/util/OpenflowVersion.java
openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/registry/flow/DeviceFlowRegistry.java
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/datastore/MultipartWriterProviderFactory.java
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/datastore/multipart/FlowStatsMultipartWriter.java
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/registry/flow/DeviceFlowRegistryImpl.java
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/registry/flow/FlowRegistryKeyFactory.java
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/registry/flow/FlowRegistryKeyImpl.java [new file with mode: 0644]
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/services/sal/AbstractAddFlow.java
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/services/sal/AbstractRemoveFlow.java
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/services/sal/AbstractUpdateFlow.java
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/services/sal/RemoveFlowCallback.java
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/services/sal/UpdateFlowCallback.java
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/statistics/services/direct/AbstractDirectStatisticsService.java
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/statistics/services/direct/AbstractGetFlowStatistics.java
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/util/AddressNormalizationUtil.java
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/util/FlowCreatorUtil.java
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/util/MatchNormalizationUtil.java
openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/device/DeviceContextImplTest.java
openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/registry/flow/DeviceFlowRegistryImplTest.java
openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/registry/flow/FlowRegistryKeyFactoryTest.java
openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/services/MultipartRequestOnTheFlyCallbackTest.java
openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/services/sal/SalFlowServiceImplTest.java
openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/statistics/StatisticsGatheringUtilsTest.java
openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/util/AddressNormalizationUtilTest.java
openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/util/MatchNormalizationUtilTest.java

index 37aac3072444d78034c821f4ace7f058b3cb27b0..7fa5561a7a84441a2a4ce854f03a36d2edae24d9 100644 (file)
@@ -8,6 +8,7 @@
 package org.opendaylight.openflowplugin.api;
 
 import java.util.List;
+import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowCookie;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
@@ -29,9 +30,9 @@ public final class OFConstants {
     public static final short OFPP_LOCAL = (short)0xfffe;
 
     /** openflow protocol 1.0 - version identifier. */
-    public static final Uint8 OFP_VERSION_1_0 = Uint8.ONE;
+    public static final @NonNull Uint8 OFP_VERSION_1_0 = Uint8.ONE;
     /** openflow protocol 1.3 - version identifier. */
-    public static final Uint8 OFP_VERSION_1_3 = Uint8.valueOf(0x04);
+    public static final @NonNull Uint8 OFP_VERSION_1_3 = Uint8.valueOf(0x04);
 
     public static final String OF_URI_PREFIX = "openflow:";
 
index fa27f93255d422e9b2ae58ed79a3569312798226..0289ea899bacd24a6c0dcdfbc841f2118bcf4902 100644 (file)
@@ -9,9 +9,8 @@ package org.opendaylight.openflowplugin.api.openflow.md.util;
 
 import static java.util.Objects.requireNonNull;
 
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Maps;
-import java.util.Arrays;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.opendaylight.openflowplugin.api.OFConstants;
 import org.opendaylight.yangtools.yang.common.Uint8;
 
 /**
@@ -21,24 +20,33 @@ import org.opendaylight.yangtools.yang.common.Uint8;
  * Note: If you add a version here, make sure to update
  *       org.opendaylight.openflowplugin.openflow.md.util.OpenflowPortsUtil as well.
  */
-// FIXME: enum in api is not something what we would like to see in case it is evolving.
+// FIXME: enum in api is not something what we would like to see in case it is evolving. On the other hand we have
+//        static constants for well-known versions, so this is not *that* bad.
+@NonNullByDefault
 public enum OpenflowVersion {
-    OF10(Uint8.ONE),
-    OF13(Uint8.valueOf(4)),
+    OF10(OFConstants.OFP_VERSION_1_0),
+    OF13(OFConstants.OFP_VERSION_1_3),
     UNSUPPORTED(Uint8.ZERO);
 
-    private static final ImmutableMap<Uint8, OpenflowVersion> VERSIONS = Maps.uniqueIndex(Arrays.asList(values()),
-        OpenflowVersion::getVersion);
-
-    private Uint8 version;
+    private final Uint8 version;
 
     OpenflowVersion(final Uint8 version) {
         this.version = requireNonNull(version);
     }
 
+    @Deprecated
     public static OpenflowVersion get(final Uint8 version) {
-        final OpenflowVersion ver = VERSIONS.get(version);
-        return ver != null ? ver : UNSUPPORTED;
+        return ofVersion(version);
+    }
+
+    public static OpenflowVersion ofVersion(final Uint8 version) {
+        if (OFConstants.OFP_VERSION_1_3.equals(version)) {
+            return OF13;
+        } else if (OFConstants.OFP_VERSION_1_0.equals(version)) {
+            return OF10;
+        } else {
+            return UNSUPPORTED;
+        }
     }
 
     /**
index 1fdbf4fb36bb1b21ff13f7bbe89d685436816921..057fc71fd6997861511383f53326c17fbd6af6c6 100644 (file)
@@ -17,6 +17,7 @@ import org.opendaylight.openflowplugin.api.openflow.FlowGroupStatus;
 import org.opendaylight.openflowplugin.api.openflow.registry.CommonDeviceRegistry;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.Flow;
 import org.opendaylight.yangtools.yang.common.Uint8;
 
 /**
@@ -25,12 +26,13 @@ import org.opendaylight.yangtools.yang.common.Uint8;
  */
 public interface DeviceFlowRegistry extends CommonDeviceRegistry<FlowRegistryKey> {
 
+    @NonNull FlowRegistryKey createKey(@NonNull Flow flow);
+
     ListenableFuture<List<Optional<FlowCapableNode>>> fill();
 
     void storeDescriptor(@NonNull FlowRegistryKey flowRegistryKey, @NonNull FlowDescriptor flowDescriptor);
 
-    @Nullable
-    FlowDescriptor retrieveDescriptor(@NonNull FlowRegistryKey flowRegistryKey);
+    @Nullable FlowDescriptor retrieveDescriptor(@NonNull FlowRegistryKey flowRegistryKey);
 
     void clearFlowRegistry();
 
index aa0c693de1b38a06b698e23a9ae7ed79946b43ba..531422c3e3f6ca91fa904d37631862cd1e37b5b4 100644 (file)
@@ -53,7 +53,7 @@ public final class MultipartWriterProviderFactory {
         provider.register(MultipartType.OFPMPQUEUE, new QueueStatsMultipartWriter(deviceContext,
                 instanceIdentifier, deviceContext.getPrimaryConnectionContext().getFeatures()));
         provider.register(MultipartType.OFPMPFLOW, new FlowStatsMultipartWriter(deviceContext, instanceIdentifier,
-                deviceContext, deviceContext.getDeviceInfo().getVersion()));
+                deviceContext));
         provider.register(MultipartType.OFPMPGROUPDESC, new GroupDescMultipartWriter(deviceContext,
                 instanceIdentifier, deviceContext));
         provider.register(MultipartType.OFPMPMETERCONFIG, new MeterConfigMultipartWriter(deviceContext,
index 3021348d894991091dbb165c979cae4dd0365e69..2257aa5ba49dfb5857c9169ea093f823a1f03280 100644 (file)
@@ -7,12 +7,8 @@
  */
 package org.opendaylight.openflowplugin.impl.datastore.multipart;
 
-import static java.util.Objects.requireNonNull;
-
 import org.opendaylight.openflowplugin.api.openflow.device.DeviceRegistry;
 import org.opendaylight.openflowplugin.api.openflow.device.TxFacade;
-import org.opendaylight.openflowplugin.api.openflow.registry.flow.FlowDescriptor;
-import org.opendaylight.openflowplugin.api.openflow.registry.flow.FlowRegistryKey;
 import org.opendaylight.openflowplugin.impl.registry.flow.FlowRegistryKeyFactory;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
@@ -25,19 +21,15 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.F
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.statistics.FlowStatisticsBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.common.Uint8;
 
 public class FlowStatsMultipartWriter extends AbstractMultipartWriter<FlowAndStatisticsMapList> {
     private final DeviceRegistry registry;
-    private final Uint8 version;
 
     public FlowStatsMultipartWriter(final TxFacade txFacade,
                                     final InstanceIdentifier<Node> instanceIdentifier,
-                                    final DeviceRegistry registry,
-                                    final Uint8 version) {
+                                    final DeviceRegistry registry) {
         super(txFacade, instanceIdentifier);
         this.registry = registry;
-        this.version = requireNonNull(version);
     }
 
     @Override
@@ -49,19 +41,17 @@ public class FlowStatsMultipartWriter extends AbstractMultipartWriter<FlowAndSta
     public void storeStatistics(final FlowAndStatisticsMapList statistics, final boolean withParents) {
         statistics.nonnullFlowAndStatisticsMapList()
             .forEach(stat -> {
-                final FlowBuilder flow = new FlowBuilder(stat)
+                final var flowBuilder = new FlowBuilder(stat)
                         .withKey(FlowRegistryKeyFactory.DUMMY_FLOW_KEY)
                         .addAugmentation(new FlowStatisticsDataBuilder()
                             .setFlowStatistics(new FlowStatisticsBuilder(stat).build())
                             .build());
 
-                final FlowRegistryKey flowRegistryKey = FlowRegistryKeyFactory.create(version, flow.build());
-                registry.getDeviceFlowRegistry().store(flowRegistryKey);
-
-                final FlowDescriptor flowDescriptor = registry
-                        .getDeviceFlowRegistry()
-                        .retrieveDescriptor(flowRegistryKey);
+                final var flowRegistry = registry.getDeviceFlowRegistry();
+                final var flowRegistryKey = flowRegistry.createKey(flowBuilder.build());
+                flowRegistry.store(flowRegistryKey);
 
+                final var flowDescriptor = flowRegistry.retrieveDescriptor(flowRegistryKey);
                 if (flowDescriptor != null) {
                     final FlowKey key = new FlowKey(flowDescriptor.getFlowId());
 
@@ -70,7 +60,7 @@ public class FlowStatsMultipartWriter extends AbstractMultipartWriter<FlowAndSta
                                     .augmentation(FlowCapableNode.class)
                                     .child(Table.class, new TableKey(stat.getTableId()))
                                     .child(Flow.class, key),
-                            flow
+                            flowBuilder
                                     .setId(key.getId())
                                     .withKey(key)
                                     .build(),
index e71e10bd887b6becb6dfea96469b8aa2fd08b3e4..79596fcf22088295a73b80040d01e29fcc01ba76 100644 (file)
@@ -39,7 +39,6 @@ import org.opendaylight.openflowplugin.api.openflow.registry.flow.FlowRegistryKe
 import org.opendaylight.openflowplugin.impl.device.history.FlowGroupInfoHistoryAppender;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.general.rev140714.GeneralAugMatchNodesNodeTableFlow;
@@ -59,7 +58,7 @@ public class DeviceFlowRegistryImpl implements DeviceFlowRegistry {
     private final BiMap<FlowRegistryKey, FlowDescriptor> flowRegistry = Maps.synchronizedBiMap(HashBiMap.create());
     private final KeyedInstanceIdentifier<Node, NodeKey> instanceIdentifier;
     private final FlowGroupInfoHistoryAppender history;
-    private final Consumer<Flow> flowConsumer;
+    private final FlowRegistryKeyFactory keyFactory;
     private final DataBroker dataBroker;
 
     public DeviceFlowRegistryImpl(final Uint8 version, final DataBroker dataBroker,
@@ -68,16 +67,13 @@ public class DeviceFlowRegistryImpl implements DeviceFlowRegistry {
         this.dataBroker = requireNonNull(dataBroker);
         this.instanceIdentifier = requireNonNull(instanceIdentifier);
         this.history = requireNonNull(history);
+        keyFactory = FlowRegistryKeyFactory.ofVersion(version);
+    }
 
-        // Specifies what to do with flow read from data store
-        flowConsumer = flow -> {
-            final FlowRegistryKey flowRegistryKey = FlowRegistryKeyFactory.create(version, flow);
-
-            if (getExistingKey(flowRegistryKey) == null) {
-                // Now, we will update the registry
-                storeDescriptor(flowRegistryKey, FlowDescriptorFactory.create(flow.getTableId(), flow.getId()));
-            }
-        };
+    @Override
+    public FlowRegistryKey createKey(
+        final org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.Flow flow) {
+        return keyFactory.create(flow);
     }
 
     @Override
@@ -122,11 +118,18 @@ public class DeviceFlowRegistryImpl implements DeviceFlowRegistry {
             public void onSuccess(final Optional<FlowCapableNode> result) {
                 result.ifPresent(flowCapableNode -> {
                     flowCapableNode.nonnullTable().values().stream()
-                    .filter(Objects::nonNull)
-                    .flatMap(table -> table.nonnullFlow().values().stream())
-                    .filter(Objects::nonNull)
-                    .filter(flow -> flow.getId() != null)
-                    .forEach(flowConsumer);
+                        .filter(Objects::nonNull)
+                        .flatMap(table -> table.nonnullFlow().values().stream())
+                        .filter(Objects::nonNull)
+                        .filter(flow -> flow.getId() != null)
+                        .forEach(flow -> {
+                            final var flowRegistryKey = createKey(flow);
+                            if (getExistingKey(flowRegistryKey) == null) {
+                                // Now, we will update the registry
+                                storeDescriptor(flowRegistryKey, FlowDescriptorFactory.create(flow.getTableId(),
+                                    flow.getId()));
+                            }
+                        });
                 });
             }
 
index c8eee0e3e9185950df5196d1e615d91bba99489b..ebf5eec0691e6425dbb12ac3e46e7d5744a61674 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ * Copyright (c) 2024 PANTHEON.tech, s.r.o.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
@@ -7,10 +8,11 @@
  */
 package org.opendaylight.openflowplugin.impl.registry.flow;
 
-import static java.util.Objects.requireNonNull;
 import static java.util.Objects.requireNonNullElse;
 
-import java.util.Objects;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
 import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.openflowplugin.api.OFConstants;
 import org.opendaylight.openflowplugin.api.openflow.registry.flow.FlowRegistryKey;
@@ -18,10 +20,6 @@ import org.opendaylight.openflowplugin.impl.util.MatchNormalizationUtil;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.Flow;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.general.rev140714.GeneralAugMatchNodesNodeTableFlow;
-import org.opendaylight.yangtools.yang.common.Uint16;
-import org.opendaylight.yangtools.yang.common.Uint64;
 import org.opendaylight.yangtools.yang.common.Uint8;
 
 public final class FlowRegistryKeyFactory {
@@ -30,137 +28,39 @@ public final class FlowRegistryKeyFactory {
     // ... so we set a dummy value and overwrite it afterwards.
     public static final FlowKey DUMMY_FLOW_KEY = new FlowKey(new FlowId("__DUMMY_ID_FOR_ALIEN__"));
 
-    private FlowRegistryKeyFactory() {
-        // Hide implicit constructor
-    }
-
-    public static @NonNull FlowRegistryKey create(final Uint8 version, final @NonNull Flow flow) {
-        //TODO: mandatory flow input values (or default values) should be specified via yang model
-        final Uint8 tableId = requireNonNull(flow.getTableId(), "flow tableId must not be null");
-        final Uint16 priority = requireNonNullElse(flow.getPriority(), OFConstants.DEFAULT_FLOW_PRIORITY);
-        final Uint64 cookie = requireNonNullElse(flow.getCookie(), OFConstants.DEFAULT_FLOW_COOKIE).getValue();
-        Match match = MatchNormalizationUtil.normalizeMatch(
-            requireNonNullElse(flow.getMatch(), OFConstants.EMPTY_MATCH), version);
-        return new FlowRegistryKeyDto(tableId.toJava(), priority.toJava(), cookie, match);
-    }
-
-    private static final class FlowRegistryKeyDto implements FlowRegistryKey {
-        private final short tableId;
-        private final int priority;
-        private final Uint64 cookie;
-        private final Match match;
-
-        private FlowRegistryKeyDto(final short tableId, final int priority, final @NonNull Uint64 cookie,
-                                   final @NonNull Match match) {
-            this.tableId = tableId;
-            this.priority = priority;
-            this.cookie = cookie;
-            this.match = match;
-        }
-
-        @Override
-        public boolean equals(final Object obj) {
-            return this == obj || obj instanceof FlowRegistryKey that
-                && priority == that.getPriority() && tableId == that.getTableId() && cookie.equals(that.getCookie())
-                && equalMatch(that.getMatch());
-        }
-
-        private boolean equalMatch(final Match input) {
-            GeneralAugMatchNodesNodeTableFlow thisAug = match.augmentation(GeneralAugMatchNodesNodeTableFlow.class);
-            GeneralAugMatchNodesNodeTableFlow inputAug = input.augmentation(GeneralAugMatchNodesNodeTableFlow.class);
-            if (thisAug != inputAug) {
-                if (thisAug != null) {
-                    if (inputAug == null) {
-                        return false;
-                    }
-                    if (!Objects.equals(match.getEthernetMatch(), input.getEthernetMatch())) {
-                        return false;
-                    }
-                    if (!Objects.equals(match.getIcmpv4Match(), input.getIcmpv4Match())) {
-                        return false;
-                    }
-                    if (!Objects.equals(match.getIcmpv6Match(), input.getIcmpv6Match())) {
-                        return false;
-                    }
-                    if (!Objects.equals(match.getInPhyPort(), input.getInPhyPort())) {
-                        return false;
-                    }
-                    if (!Objects.equals(match.getInPort(), input.getInPort())) {
-                        return false;
-                    }
-                    if (!Objects.equals(match.getIpMatch(), input.getIpMatch())) {
-                        return false;
-                    }
-                    if (!Objects.equals(match.getLayer3Match(), input.getLayer3Match())) {
-                        return false;
-                    }
-                    if (!Objects.equals(match.getLayer4Match(), input.getLayer4Match())) {
-                        return false;
-                    }
-                    if (!Objects.equals(match.getMetadata(), input.getMetadata())) {
-                        return false;
-                    }
-                    if (!Objects.equals(match.getProtocolMatchFields(), input.getProtocolMatchFields())) {
-                        return false;
-                    }
-                    if (!Objects.equals(match.getTcpFlagsMatch(), input.getTcpFlagsMatch())) {
-                        return false;
-                    }
-                    if (!Objects.equals(match.getTunnel(), input.getTunnel())) {
-                        return false;
-                    }
-                    if (!Objects.equals(match.getVlanMatch(), input.getVlanMatch())) {
-                        return false;
-                    }
-                    for (var inputExtensionList : inputAug.nonnullExtensionList().values()) {
-                        if (!thisAug.nonnullExtensionList().containsValue(inputExtensionList)) {
-                            return false;
-                        }
-                    }
-                }
-            } else {
-                return getMatch().equals(input);
+    public static final @NonNull FlowRegistryKeyFactory VERSION_1_0 =
+        new FlowRegistryKeyFactory(OFConstants.OFP_VERSION_1_0);
+    public static final @NonNull FlowRegistryKeyFactory VERSION_1_3 =
+        new FlowRegistryKeyFactory(OFConstants.OFP_VERSION_1_3);
+    private static final LoadingCache<Uint8, @NonNull FlowRegistryKeyFactory> CACHE = CacheBuilder.newBuilder()
+        .weakValues().build(new CacheLoader<>() {
+            @Override
+            public FlowRegistryKeyFactory load(final Uint8 key) {
+                return new FlowRegistryKeyFactory(key);
             }
-            return true;
-        }
+        });
 
-        @Override
-        public int hashCode() {
-            int result = tableId;
-            result = 31 * result + priority;
-            result = 31 * result + cookie.hashCode();
-            result = 31 * result + match.hashCode();
-            return result;
-        }
-
-        @Override
-        public String toString() {
-            return "FlowRegistryKeyDto{"
-                    + "tableId=" + tableId
-                    + ", priority=" + priority
-                    + ", cookie=" + cookie
-                    + ", match=" + match
-                    + '}';
-        }
-
-        @Override
-        public short getTableId() {
-            return tableId;
-        }
+    private final MatchNormalizationUtil matchNormalizer;
 
-        @Override
-        public int getPriority() {
-            return priority;
-        }
+    private FlowRegistryKeyFactory(final Uint8 version) {
+        matchNormalizer = MatchNormalizationUtil.ofVersion(version);
+    }
 
-        @Override
-        public Uint64 getCookie() {
-            return cookie;
+    public static @NonNull FlowRegistryKeyFactory ofVersion(final Uint8 version) {
+        if (OFConstants.OFP_VERSION_1_3.equals(version)) {
+            return VERSION_1_3;
+        } else if (OFConstants.OFP_VERSION_1_0.equals(version)) {
+            return VERSION_1_0;
+        } else {
+            return CACHE.getUnchecked(version);
         }
+    }
 
-        @Override
-        public Match getMatch() {
-            return match;
-        }
+    public @NonNull FlowRegistryKey create(final @NonNull Flow flow) {
+        // FIXME: mandatory flow input values (or default values) should be specified via YANG model
+        final var priority = requireNonNullElse(flow.getPriority(), OFConstants.DEFAULT_FLOW_PRIORITY);
+        final var cookie = requireNonNullElse(flow.getCookie(), OFConstants.DEFAULT_FLOW_COOKIE).getValue();
+        return new FlowRegistryKeyImpl(flow.requireTableId().toJava(), priority.toJava(), cookie,
+            matchNormalizer.normalizeMatch(requireNonNullElse(flow.getMatch(), OFConstants.EMPTY_MATCH)));
     }
 }
diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/registry/flow/FlowRegistryKeyImpl.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/registry/flow/FlowRegistryKeyImpl.java
new file mode 100644 (file)
index 0000000..b758cd4
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ * Copyright (c) 2024 PANTHEON.tech, s.r.o.
+ *
+ * This program and the accompanying materials are made available under the
+ * 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.openflowplugin.impl.registry.flow;
+
+import static java.util.Objects.requireNonNull;
+
+import java.util.Objects;
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.openflowplugin.api.openflow.registry.flow.FlowRegistryKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.general.rev140714.GeneralAugMatchNodesNodeTableFlow;
+import org.opendaylight.yangtools.yang.common.Uint64;
+
+record FlowRegistryKeyImpl(
+        short tableId,
+        int priority,
+        @NonNull Uint64 cookie,
+        @NonNull Match match) implements FlowRegistryKey {
+
+    FlowRegistryKeyImpl {
+        requireNonNull(cookie);
+        requireNonNull(match);
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+        return this == obj || obj instanceof FlowRegistryKey that
+            && priority == that.getPriority() && tableId == that.getTableId() && cookie.equals(that.getCookie())
+            && equalMatch(that.getMatch());
+    }
+
+    private boolean equalMatch(final Match input) {
+        GeneralAugMatchNodesNodeTableFlow thisAug = match.augmentation(GeneralAugMatchNodesNodeTableFlow.class);
+        GeneralAugMatchNodesNodeTableFlow inputAug = input.augmentation(GeneralAugMatchNodesNodeTableFlow.class);
+        if (thisAug != inputAug) {
+            if (thisAug != null) {
+                if (inputAug == null) {
+                    return false;
+                }
+                if (!Objects.equals(match.getEthernetMatch(), input.getEthernetMatch())) {
+                    return false;
+                }
+                if (!Objects.equals(match.getIcmpv4Match(), input.getIcmpv4Match())) {
+                    return false;
+                }
+                if (!Objects.equals(match.getIcmpv6Match(), input.getIcmpv6Match())) {
+                    return false;
+                }
+                if (!Objects.equals(match.getInPhyPort(), input.getInPhyPort())) {
+                    return false;
+                }
+                if (!Objects.equals(match.getInPort(), input.getInPort())) {
+                    return false;
+                }
+                if (!Objects.equals(match.getIpMatch(), input.getIpMatch())) {
+                    return false;
+                }
+                if (!Objects.equals(match.getLayer3Match(), input.getLayer3Match())) {
+                    return false;
+                }
+                if (!Objects.equals(match.getLayer4Match(), input.getLayer4Match())) {
+                    return false;
+                }
+                if (!Objects.equals(match.getMetadata(), input.getMetadata())) {
+                    return false;
+                }
+                if (!Objects.equals(match.getProtocolMatchFields(), input.getProtocolMatchFields())) {
+                    return false;
+                }
+                if (!Objects.equals(match.getTcpFlagsMatch(), input.getTcpFlagsMatch())) {
+                    return false;
+                }
+                if (!Objects.equals(match.getTunnel(), input.getTunnel())) {
+                    return false;
+                }
+                if (!Objects.equals(match.getVlanMatch(), input.getVlanMatch())) {
+                    return false;
+                }
+                for (var inputExtensionList : inputAug.nonnullExtensionList().values()) {
+                    if (!thisAug.nonnullExtensionList().containsValue(inputExtensionList)) {
+                        return false;
+                    }
+                }
+            }
+        } else {
+            return getMatch().equals(input);
+        }
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = tableId;
+        result = 31 * result + priority;
+        result = 31 * result + cookie.hashCode();
+        result = 31 * result + match.hashCode();
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "FlowRegistryKeyDto{"
+            + "tableId=" + tableId
+            + ", priority=" + priority
+            + ", cookie=" + cookie
+            + ", match=" + match
+            + '}';
+    }
+
+    @Override
+    public short getTableId() {
+        return tableId;
+    }
+
+    @Override
+    public int getPriority() {
+        return priority;
+    }
+
+    @Override
+    public Uint64 getCookie() {
+        return cookie;
+    }
+
+    @Override
+    public Match getMatch() {
+        return match;
+    }
+}
index 0f97b2262dce4a4dbfa9137b4bfb6861b45e96a3..83cc0602ca7fee47b85ef3ca485929832e61e1c7 100644 (file)
@@ -13,7 +13,6 @@ import com.google.common.util.concurrent.ListenableFuture;
 import com.google.common.util.concurrent.MoreExecutors;
 import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
-import org.opendaylight.openflowplugin.impl.registry.flow.FlowRegistryKeyFactory;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlow;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowOutput;
@@ -26,9 +25,10 @@ public abstract non-sealed class AbstractAddFlow extends AbstractFlowRpc impleme
 
     @Override
     public final ListenableFuture<RpcResult<AddFlowOutput>> invoke(final AddFlowInput input) {
-        final var flowRegistryKey = FlowRegistryKeyFactory.create(version(), input);
+        final var flowRegistry = flowRegistry();
+        final var flowRegistryKey = flowRegistry.createKey(input);
         final var future = invokeImpl(input);
-        Futures.addCallback(future, new AddFlowCallback(input, flowRegistry(), flowRegistryKey),
+        Futures.addCallback(future, new AddFlowCallback(input, flowRegistry, flowRegistryKey),
             MoreExecutors.directExecutor());
         return future;
     }
index 1e9671049b8742418797f98f47513f00c5abaf08..d4240f884badf513eff7ad3f3390952b0fa5744e 100644 (file)
@@ -26,8 +26,7 @@ public abstract non-sealed class AbstractRemoveFlow extends AbstractFlowRpc impl
     @Override
     public final ListenableFuture<RpcResult<RemoveFlowOutput>> invoke(final RemoveFlowInput input) {
         final var future = invokeImpl(input);
-        Futures.addCallback(future, new RemoveFlowCallback(input, flowRegistry(), version()),
-            MoreExecutors.directExecutor());
+        Futures.addCallback(future, new RemoveFlowCallback(input, flowRegistry()), MoreExecutors.directExecutor());
         return future;
     }
 
index 670779bd841bea599a7ee4d34707207fb3b3d511..19c83c68dcdf38fe4540ccf5452fb69b3c76cb93 100644 (file)
@@ -26,8 +26,7 @@ public abstract non-sealed class AbstractUpdateFlow extends AbstractFlowRpc impl
     @Override
     public final ListenableFuture<RpcResult<UpdateFlowOutput>> invoke(final UpdateFlowInput input) {
         final var future = invokeImpl(input);
-        Futures.addCallback(future, new UpdateFlowCallback(input, flowRegistry(), version()),
-            MoreExecutors.directExecutor());
+        Futures.addCallback(future, new UpdateFlowCallback(input, flowRegistry()), MoreExecutors.directExecutor());
         return future;
     }
 
index 95de8a2612f5a29edbb599c0709548d9f9fcd06e..4d3ffbe304bd8dae16af3d1e39490311beaa2b42 100644 (file)
@@ -13,7 +13,6 @@ import static java.util.Objects.requireNonNull;
 import com.google.common.util.concurrent.FutureCallback;
 import org.opendaylight.openflowplugin.api.openflow.FlowGroupStatus;
 import org.opendaylight.openflowplugin.api.openflow.registry.flow.DeviceFlowRegistry;
-import org.opendaylight.openflowplugin.impl.registry.flow.FlowRegistryKeyFactory;
 import org.opendaylight.openflowplugin.impl.util.ErrorUtil;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
@@ -31,12 +30,10 @@ final class RemoveFlowCallback implements FutureCallback<RpcResult<RemoveFlowOut
 
     private final RemoveFlowInput input;
     private final DeviceFlowRegistry flowRegistry;
-    private final Uint8 version;
 
-    RemoveFlowCallback(final RemoveFlowInput input, final DeviceFlowRegistry flowRegistry, final Uint8 version) {
+    RemoveFlowCallback(final RemoveFlowInput input, final DeviceFlowRegistry flowRegistry) {
         this.input = requireNonNull(input);
         this.flowRegistry = requireNonNull(flowRegistry);
-        this.version = requireNonNull(version);
     }
 
     @Override
@@ -46,7 +43,7 @@ final class RemoveFlowCallback implements FutureCallback<RpcResult<RemoveFlowOut
                 LOG.debug("Flow remove finished without error for flow={}", input);
             }
             if (input.getTableId() != null && !input.getTableId().equals(OFPTT_ALL)) {
-                var flowRegistryKey = FlowRegistryKeyFactory.create(version, input);
+                var flowRegistryKey = flowRegistry.createKey(input);
                 flowRegistry.addMark(flowRegistryKey);
 
                 final FlowRef flowRef = input.getFlowRef();
index 2f6fc7ab1af5773d7e772e03a82455cccac15e5b..00ecd759fbcfa8125798636bf617214dd79e1764 100644 (file)
@@ -16,7 +16,6 @@ import org.opendaylight.openflowplugin.api.openflow.registry.flow.DeviceFlowRegi
 import org.opendaylight.openflowplugin.api.openflow.registry.flow.FlowDescriptor;
 import org.opendaylight.openflowplugin.api.openflow.registry.flow.FlowRegistryKey;
 import org.opendaylight.openflowplugin.impl.registry.flow.FlowDescriptorFactory;
-import org.opendaylight.openflowplugin.impl.registry.flow.FlowRegistryKeyFactory;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowInput;
@@ -34,20 +33,18 @@ final class UpdateFlowCallback implements FutureCallback<RpcResult<UpdateFlowOut
 
     private final UpdateFlowInput input;
     private final DeviceFlowRegistry flowRegistry;
-    private final Uint8 version;
 
-    UpdateFlowCallback(final UpdateFlowInput input, final DeviceFlowRegistry flowRegistry, final Uint8 version) {
+    UpdateFlowCallback(final UpdateFlowInput input, final DeviceFlowRegistry flowRegistry) {
         this.input = requireNonNull(input);
         this.flowRegistry = requireNonNull(flowRegistry);
-        this.version = requireNonNull(version);
     }
 
     @Override
     public void onSuccess(final RpcResult<UpdateFlowOutput> updateFlowOutputRpcResult) {
         final UpdatedFlow updated = input.getUpdatedFlow();
         final OriginalFlow original = input.getOriginalFlow();
-        final FlowRegistryKey origFlowRegistryKey = FlowRegistryKeyFactory.create(version, original);
-        final FlowRegistryKey updatedFlowRegistryKey = FlowRegistryKeyFactory.create(version, updated);
+        final FlowRegistryKey origFlowRegistryKey = flowRegistry.createKey(original);
+        final FlowRegistryKey updatedFlowRegistryKey = flowRegistry.createKey(updated);
         final FlowDescriptor origFlowDescriptor = flowRegistry.retrieveDescriptor(origFlowRegistryKey);
 
         final boolean isUpdate = origFlowDescriptor != null;
index c7b02a5ec871b3d7a40ab44369b74e1471c06ef2..a3235d2ee3e9ae364aa6385b9e801196119b8e4c 100644 (file)
@@ -39,7 +39,7 @@ abstract class AbstractDirectStatisticsService<I extends StoreStatsGrouping,
         extends AbstractMultipartService<I, T> {
 
     private final MultipartType multipartType;
-    private final OpenflowVersion ofVersion = OpenflowVersion.get(getVersion());
+    private final OpenflowVersion ofVersion = OpenflowVersion.ofVersion(getVersion());
     private final ConvertorExecutor convertorExecutor;
     private final MultipartWriterProvider multipartWriterProvider;
 
index 574a5456006f5f7e581a09c0988ae89805351172..5ab325a7c8cfa4b8f7b9342207dd1d6ab9ef48f5 100644 (file)
@@ -10,7 +10,6 @@ package org.opendaylight.openflowplugin.impl.statistics.services.direct;
 import com.google.common.util.concurrent.ListenableFuture;
 import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
 import org.opendaylight.openflowplugin.api.openflow.device.RequestContextStack;
-import org.opendaylight.openflowplugin.api.openflow.registry.flow.FlowRegistryKey;
 import org.opendaylight.openflowplugin.impl.datastore.MultipartWriterProvider;
 import org.opendaylight.openflowplugin.impl.registry.flow.FlowRegistryKeyFactory;
 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.ConvertorExecutor;
@@ -50,17 +49,15 @@ public abstract class AbstractGetFlowStatistics<T extends OfHeader>
      * @return generated flow ID
      */
     protected FlowId generateFlowId(final FlowAndStatisticsMapList flowStatistics) {
-        final FlowStatisticsDataBuilder flowStatisticsDataBld = new FlowStatisticsDataBuilder()
-                .setFlowStatistics(new FlowStatisticsBuilder(flowStatistics).build());
-
-        final FlowBuilder flowBuilder = new FlowBuilder(flowStatistics)
+        final var flowRegistry = getDeviceRegistry().getDeviceFlowRegistry();
+        final var flowRegistryKey = flowRegistry.createKey(new FlowBuilder(flowStatistics)
             .withKey(FlowRegistryKeyFactory.DUMMY_FLOW_KEY)
-            .addAugmentation(flowStatisticsDataBld.build());
-
-        final FlowRegistryKey flowRegistryKey = FlowRegistryKeyFactory.create(getVersion(), flowBuilder.build());
-
-        getDeviceRegistry().getDeviceFlowRegistry().store(flowRegistryKey);
-        return getDeviceRegistry().getDeviceFlowRegistry().retrieveDescriptor(flowRegistryKey).getFlowId();
+            .addAugmentation(new FlowStatisticsDataBuilder()
+                .setFlowStatistics(new FlowStatisticsBuilder(flowStatistics).build())
+                .build())
+            .build());
+        flowRegistry.store(flowRegistryKey);
+        return flowRegistry.retrieveDescriptor(flowRegistryKey).getFlowId();
     }
 
 }
index 4dcb4b99618b2f293adb8f240bcf8111ae66a241..bb74361bf063b170dbcd4f49d8a7dfb85beb5b96 100644 (file)
@@ -7,9 +7,12 @@
  */
 package org.opendaylight.openflowplugin.impl.util;
 
+import static java.util.Objects.requireNonNull;
+
 import java.net.InetAddress;
 import java.net.UnknownHostException;
 import java.util.Locale;
+import org.eclipse.jdt.annotation.NonNull;
 import org.eclipse.jdt.annotation.Nullable;
 import org.opendaylight.openflowplugin.api.openflow.md.util.OpenflowVersion;
 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.common.IpConversionUtil;
@@ -24,39 +27,50 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.DottedQuad;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.opendaylight.ipv6.arbitrary.bitmask.fields.rev160224.Ipv6ArbitraryMask;
-import org.opendaylight.yangtools.yang.common.Uint32;
-import org.opendaylight.yangtools.yang.common.Uint8;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
  * Utility class used for converting OpenFlow port numbers, Ipv4 and Ipv6 addresses to normalized format.
  */
-public final class AddressNormalizationUtil {
+public enum AddressNormalizationUtil {
+    VERSION_1_0(OpenflowVersion.OF10),
+    VERSION_1_3(OpenflowVersion.OF13),
+    UNSUPPORTED(OpenflowVersion.UNSUPPORTED);
+
     private static final Logger LOG = LoggerFactory.getLogger(AddressNormalizationUtil.class);
 
     private static final String NO_ETH_MASK = "ff:ff:ff:ff:ff:ff";
     private static final String PREFIX_SEPARATOR = "/";
 
-    private AddressNormalizationUtil() {
+    private final OpenflowVersion version;
+
+    AddressNormalizationUtil(final OpenflowVersion version) {
+        this.version = requireNonNull(version);
+    }
+
+    public static @NonNull AddressNormalizationUtil ofVersion(final OpenflowVersion version) {
+        return switch (version) {
+            case OF10 -> VERSION_1_0;
+            case OF13 -> VERSION_1_3;
+            case UNSUPPORTED -> UNSUPPORTED;
+        };
     }
 
     /**
      * Extract port number from URI and convert it to OpenFlow specific textual representation.
      *
      * @param port            the OpenFlow port
-     * @param protocolVersion the OpenFLow protocol version
      * @return normalized uri
      */
-    public static @Nullable Uri normalizeProtocolAgnosticPort(@Nullable final Uri port, final Uint8 protocolVersion) {
-        if (port == null) {
-            return null;
+    public @Nullable Uri normalizeProtocolAgnosticPort(final @Nullable Uri port) {
+        if (port != null) {
+            final var portValue = InventoryDataServiceUtil.portNumberfromNodeConnectorId(version, port.getValue());
+            if (portValue != null) {
+                return OpenflowPortsUtil.getProtocolAgnosticPortUri(version.getVersion(), portValue);
+            }
         }
-
-        Uint32 portValue = InventoryDataServiceUtil
-                .portNumberfromNodeConnectorId(OpenflowVersion.get(protocolVersion), port.getValue());
-
-        return portValue == null ? null : OpenflowPortsUtil.getProtocolAgnosticPortUri(protocolVersion, portValue);
+        return null;
     }
 
     /**
index 6dfdfc323bd31b754e2a5d67ade5499e18a3803e..d7db396de03908442cdd3c862d3048e8c7611ff1 100644 (file)
@@ -38,7 +38,7 @@ public final class FlowCreatorUtil {
             FlowConvertor.DEFAULT_OFPFF_FLOW_REM);
 
     private FlowCreatorUtil() {
-        // Hidden on purpose
+        // FIXME: turn this into a full class with Uint8 version captured
     }
 
     public static void setWildcardedFlowMatch(final Uint8 version, final MultipartRequestFlowBuilder flowBuilder) {
index 9680c87da8ba30ca99853b3b8fea29160218e71a..0f0a8ee66c1a59ad519c0f635904ef0f15bc8f52 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2017 Pantheon Technologies s.r.o. and others.  All rights reserved.
+ * Copyright (c) 2024 PANTHEON.tech, s.r.o.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
@@ -14,18 +15,14 @@ import static org.opendaylight.openflowplugin.impl.util.AddressNormalizationUtil
 import static org.opendaylight.openflowplugin.impl.util.AddressNormalizationUtil.normalizeIpv6Prefix;
 import static org.opendaylight.openflowplugin.impl.util.AddressNormalizationUtil.normalizeMacAddress;
 import static org.opendaylight.openflowplugin.impl.util.AddressNormalizationUtil.normalizeMacAddressMask;
-import static org.opendaylight.openflowplugin.impl.util.AddressNormalizationUtil.normalizeProtocolAgnosticPort;
 
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.cache.CacheBuilder;
 import com.google.common.cache.CacheLoader;
 import com.google.common.cache.LoadingCache;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import java.util.function.Function;
-import java.util.stream.Stream;
 import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.openflowplugin.api.OFConstants;
+import org.opendaylight.openflowplugin.api.openflow.md.util.OpenflowVersion;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
@@ -49,69 +46,62 @@ import org.opendaylight.yangtools.yang.common.Uint8;
 /**
  * Utility class for match normalization.
  */
+// FIXME: rename to MatchNormalizer, move to FlowRegistryKeyFactory's package and hide
 public final class MatchNormalizationUtil {
-    // Cache normalizers for common OpenFlow versions
-    private static final ImmutableMap<Uint8, ImmutableSet<Function<MatchBuilder, MatchBuilder>>> COMMON_NORMALIZERS =
-        ImmutableMap.<Uint8, ImmutableSet<Function<MatchBuilder, MatchBuilder>>>builder()
-            .put(OFConstants.OFP_VERSION_1_0,
-                createNormalizers(OFConstants.OFP_VERSION_1_0).collect(ImmutableSet.toImmutableSet()))
-            .put(OFConstants.OFP_VERSION_1_3,
-                createNormalizers(OFConstants.OFP_VERSION_1_3).collect(ImmutableSet.toImmutableSet()))
-            .build();
-    private static final LoadingCache<Uint8, ImmutableSet<Function<MatchBuilder, MatchBuilder>>> UNCOMMON_NORMALIZERS =
-        CacheBuilder.newBuilder().weakValues().build(new CacheLoader<>() {
+    public static final @NonNull MatchNormalizationUtil VERSION_1_0 =
+        new MatchNormalizationUtil(OFConstants.OFP_VERSION_1_0);
+    public static final @NonNull MatchNormalizationUtil VERSION_1_3 =
+        new MatchNormalizationUtil(OFConstants.OFP_VERSION_1_3);
+    private static final LoadingCache<Uint8, @NonNull MatchNormalizationUtil> CACHE = CacheBuilder.newBuilder()
+        .weakValues().build(new CacheLoader<>() {
             @Override
-            public ImmutableSet<Function<MatchBuilder, MatchBuilder>> load(final Uint8 key) {
-                return createNormalizers(key).collect(ImmutableSet.toImmutableSet());
+            public MatchNormalizationUtil load(final Uint8 key) {
+                return new MatchNormalizationUtil(key);
             }
         });
 
-    private MatchNormalizationUtil() {
-        // Hidden on purpose
+    private final AddressNormalizationUtil addressNormalizer;
+
+    private MatchNormalizationUtil(final Uint8 version) {
+        addressNormalizer = AddressNormalizationUtil.ofVersion(OpenflowVersion.ofVersion(version));
+    }
+
+    public static @NonNull MatchNormalizationUtil ofVersion(final Uint8 version) {
+        if (OFConstants.OFP_VERSION_1_3.equals(version)) {
+            return VERSION_1_3;
+        } else if (OFConstants.OFP_VERSION_1_0.equals(version)) {
+            return VERSION_1_0;
+        } else {
+            return CACHE.getUnchecked(version);
+        }
     }
 
     /**
      * Normalize match.
      *
      * @param match   the OpenFlow match
-     * @param version the OpenFlow version
      * @return normalized OpenFlow match
      */
-    public static @NonNull Match normalizeMatch(@NonNull final Match match, final Uint8 version) {
-        final var matchBuilder = new MatchBuilder(match);
-
-        var normalizers = COMMON_NORMALIZERS.get(version);
-        if (normalizers == null) {
-            normalizers = UNCOMMON_NORMALIZERS.getUnchecked(version);
-        }
-        normalizers.forEach(normalizer -> normalizer.apply(matchBuilder));
-
-        return matchBuilder.build();
-    }
-
-    private static @NonNull Stream<Function<MatchBuilder, MatchBuilder>> createNormalizers(final Uint8 version) {
-        return Stream.of(
-            MatchNormalizationUtil::normalizeExtensionMatch,
-            MatchNormalizationUtil::normalizeEthernetMatch,
-            MatchNormalizationUtil::normalizeArpMatch,
-            MatchNormalizationUtil::normalizeTunnelIpv4Match,
-            MatchNormalizationUtil::normalizeIpv4Match,
-            MatchNormalizationUtil::normalizeIpv4MatchArbitraryBitMask,
-            MatchNormalizationUtil::normalizeIpv6Match,
-            MatchNormalizationUtil::normalizeIpv6MatchArbitraryBitMask,
-            match -> normalizeInPortMatch(match, version),
-            match -> normalizeInPhyPortMatch(match, version));
-    }
-
-    private static @NonNull MatchBuilder normalizeExtensionMatch(@NonNull final MatchBuilder match) {
-        return new MatchBuilder(MatchUtil.transformMatch(match.build(), Match.class));
+    public @NonNull Match normalizeMatch(@NonNull final Match match) {
+        var builder = new MatchBuilder(match);
+        builder = normalizeExtensionMatch(builder);
+        builder = normalizeEthernetMatch(builder);
+        builder = normalizeArpMatch(builder);
+        builder = normalizeTunnelIpv4Match(builder);
+        builder = normalizeIpv4Match(builder);
+        builder = normalizeIpv4MatchArbitraryBitMask(builder);
+        builder = normalizeIpv6Match(builder);
+        builder = normalizeIpv6MatchArbitraryBitMask(builder);
+        builder = normalizeInPortMatch(builder);
+        builder = normalizeInPhyPortMatch(builder);
+        return builder.build();
     }
 
     @VisibleForTesting
-    static @NonNull MatchBuilder normalizeInPortMatch(final @NonNull MatchBuilder match, final Uint8 version) {
+    @NonNull MatchBuilder normalizeInPortMatch(final @NonNull MatchBuilder match) {
         final var inPort = match.getInPort();
         if (inPort != null) {
-            final var inPortUri = normalizeProtocolAgnosticPort(inPort, version);
+            final var inPortUri = addressNormalizer.normalizeProtocolAgnosticPort(inPort);
             if (inPortUri != null) {
                 match.setInPort(new NodeConnectorId(inPortUri));
             }
@@ -120,10 +110,10 @@ public final class MatchNormalizationUtil {
     }
 
     @VisibleForTesting
-    static @NonNull MatchBuilder normalizeInPhyPortMatch(final @NonNull MatchBuilder match, final Uint8 version) {
+    @NonNull MatchBuilder normalizeInPhyPortMatch(final @NonNull MatchBuilder match) {
         final var inPhyPort = match.getInPhyPort();
         if (inPhyPort != null) {
-            final var inPhyPortUri = normalizeProtocolAgnosticPort(inPhyPort, version);
+            final var inPhyPortUri = addressNormalizer.normalizeProtocolAgnosticPort(inPhyPort);
             if (inPhyPortUri != null) {
                 match.setInPhyPort(new NodeConnectorId(inPhyPortUri));
             }
@@ -247,4 +237,8 @@ public final class MatchNormalizationUtil {
         }
         return match;
     }
+
+    private static @NonNull MatchBuilder normalizeExtensionMatch(@NonNull final MatchBuilder match) {
+        return new MatchBuilder(MatchUtil.transformMatch(match.build(), Match.class));
+    }
 }
index 3c64bc4c4dbe9a7bd980338ec33a18add28342f7..f1939f23255fa85821b7ac804a6bf7535af6c15c 100644 (file)
@@ -244,7 +244,7 @@ public class DeviceContextImplTest {
                 FlowRemoved.class.getName())))).thenReturn(messageTranslatorFlowRemoved);
 
         final java.util.Optional<AbstractDeviceInitializer> deviceInitializer = java.util.Optional
-                .of(this.abstractDeviceInitializer);
+                .of(abstractDeviceInitializer);
 
         Mockito.lenient().when(deviceInitializerProvider.lookup(OFConstants.OFP_VERSION_1_3))
                 .thenReturn(deviceInitializer);
@@ -274,7 +274,7 @@ public class DeviceContextImplTest {
     public void testGetReadTransaction() {
         readTx = deviceContext.getReadTransaction();
         assertNotNull(readTx);
-        assertEquals(this.readTx, readTx);
+        assertEquals(readTx, readTx);
     }
 
     @Test
@@ -443,8 +443,7 @@ public class DeviceContextImplTest {
                 .thenReturn(flowRemovedMdsalBld.build());
 
         // insert flow+flowId into local registry
-        final FlowRegistryKey flowRegKey =
-                FlowRegistryKeyFactory.create(deviceInfo.getVersion(), flowRemovedMdsalBld.build());
+        final FlowRegistryKey flowRegKey = FlowRegistryKeyFactory.VERSION_1_3.create(flowRemovedMdsalBld.build());
         final FlowDescriptor flowDescriptor = FlowDescriptorFactory.create(Uint8.ZERO, new FlowId("ut-ofp:f456"));
         deviceContext.getDeviceFlowRegistry().storeDescriptor(flowRegKey, flowDescriptor);
 
index 75e1b6e2d2a5ddee914260f0d3788086be6d2141..ffe2e0baf59ad95d78e3df359a0b8a947bd663f0 100644 (file)
@@ -85,7 +85,7 @@ public class DeviceFlowRegistryImplTest {
         deviceFlowRegistry = new DeviceFlowRegistryImpl(OFConstants.OFP_VERSION_1_3, dataBroker, nodeInstanceIdentifier,
             history);
         final FlowAndStatisticsMapList flowStats = TestFlowHelper.createFlowAndStatisticsMapListBuilder(1).build();
-        key = FlowRegistryKeyFactory.create(OFConstants.OFP_VERSION_1_3, flowStats);
+        key = FlowRegistryKeyFactory.VERSION_1_3.create(flowStats);
         descriptor = FlowDescriptorFactory.create(Uint8.valueOf(key.getTableId()), new FlowId("ut:1"));
 
         Assert.assertEquals(0, deviceFlowRegistry.getAllFlowDescriptors().size());
@@ -114,7 +114,7 @@ public class DeviceFlowRegistryImplTest {
                 .build();
 
         final Map<FlowRegistryKey, FlowDescriptor> allFlowDescriptors = fillRegistry(path, flowCapableNode);
-        key = FlowRegistryKeyFactory.create(OFConstants.OFP_VERSION_1_3, flow);
+        key = FlowRegistryKeyFactory.VERSION_1_3.create(flow);
 
         InOrder order = inOrder(dataBroker, readOnlyTransaction);
         order.verify(dataBroker).newReadOnlyTransaction();
@@ -189,7 +189,7 @@ public class DeviceFlowRegistryImplTest {
 
         // store new key with old value
         final FlowAndStatisticsMapList flowStats = TestFlowHelper.createFlowAndStatisticsMapListBuilder(2).build();
-        final FlowRegistryKey key2 = FlowRegistryKeyFactory.create(OFConstants.OFP_VERSION_1_3, flowStats);
+        final FlowRegistryKey key2 = FlowRegistryKeyFactory.VERSION_1_3.create(flowStats);
         deviceFlowRegistry.storeDescriptor(key2, descriptor);
         Assert.assertEquals(2, deviceFlowRegistry.getAllFlowDescriptors().size());
         Assert.assertEquals("ut:1", deviceFlowRegistry.retrieveDescriptor(key2).getFlowId().getValue());
@@ -209,7 +209,7 @@ public class DeviceFlowRegistryImplTest {
 
         //store new key
         final String alienPrefix = "#UF$TABLE*2-";
-        final FlowRegistryKey key2 = FlowRegistryKeyFactory.create(OFConstants.OFP_VERSION_1_3,
+        final FlowRegistryKey key2 = FlowRegistryKeyFactory.VERSION_1_3.create(
                 TestFlowHelper.createFlowAndStatisticsMapListBuilder(2).build());
         deviceFlowRegistry.store(key2);
         newFlowId = deviceFlowRegistry.retrieveDescriptor(key2).getFlowId();
index b2af3588691ccf3e83caafea13bc32edec22cb62..46739579c1dd7cfb8a99cb31f0470da707bdeafb 100644 (file)
@@ -9,17 +9,19 @@
 package org.opendaylight.openflowplugin.impl.registry.flow;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertThrows;
 
 import java.util.ArrayList;
 import java.util.HashSet;
-import java.util.List;
-import org.junit.Assert;
+import java.util.NoSuchElementException;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
-import org.mockito.Mockito;
 import org.mockito.junit.MockitoJUnitRunner;
 import org.opendaylight.openflowplugin.api.OFConstants;
 import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
@@ -44,10 +46,7 @@ import org.slf4j.LoggerFactory;
 
 @RunWith(MockitoJUnitRunner.class)
 public class FlowRegistryKeyFactoryTest {
-
     private static final Logger LOG = LoggerFactory.getLogger(FlowRegistryKeyFactoryTest.class);
-
-
     private static final FlowsStatisticsUpdateBuilder FLOWS_STATISTICS_UPDATE_BUILDER =
             new FlowsStatisticsUpdateBuilder();
     @Mock
@@ -57,15 +56,13 @@ public class FlowRegistryKeyFactoryTest {
     @Mock
     private DeviceInfo deviceInfo;
 
-
     @Before
     public void setup() {
-        List<FlowAndStatisticsMapList> flowAndStatisticsMapListList = new ArrayList<>();
+        var flowAndStatisticsMapListList = new ArrayList<FlowAndStatisticsMapList>();
         for (int i = 1; i < 4; i++) {
             flowAndStatisticsMapListList.add(TestFlowHelper.createFlowAndStatisticsMapListBuilder(i).build());
         }
         FLOWS_STATISTICS_UPDATE_BUILDER.setFlowAndStatisticsMapList(flowAndStatisticsMapListList);
-        Mockito.when(deviceInfo.getVersion()).thenReturn(OFConstants.OFP_VERSION_1_3);
     }
 
     @Test
@@ -74,8 +71,8 @@ public class FlowRegistryKeyFactoryTest {
 
         HashSet<FlowRegistryKey> flowRegistryKeys = new HashSet<>();
         for (FlowAndStatisticsMapList item : flowStats.nonnullFlowAndStatisticsMapList()) {
-            final FlowRegistryKey key1 = FlowRegistryKeyFactory.create(deviceInfo.getVersion(), item);
-            final FlowRegistryKey key2 = FlowRegistryKeyFactory.create(deviceInfo.getVersion(), item);
+            final FlowRegistryKey key1 = FlowRegistryKeyFactory.VERSION_1_3.create(item);
+            final FlowRegistryKey key2 = FlowRegistryKeyFactory.VERSION_1_3.create(item);
             flowRegistryKeys.add(key1);
             flowRegistryKeys.add(key1);
             flowRegistryKeys.add(key2);
@@ -85,9 +82,11 @@ public class FlowRegistryKeyFactoryTest {
 
     @Test
     public void testEqualsNegative() {
+        final var keyFactory = FlowRegistryKeyFactory.VERSION_1_3;
+
         final FlowAndStatisticsMapList flowStatisticsMapList1 =
                 TestFlowHelper.createFlowAndStatisticsMapListBuilder(1).build();
-        final FlowRegistryKey key1 = FlowRegistryKeyFactory.create(deviceInfo.getVersion(), flowStatisticsMapList1);
+        final FlowRegistryKey key1 = keyFactory.create(flowStatisticsMapList1);
 
         FlowRegistryKey key2;
         FlowAndStatisticsMapListBuilder flowStatisticsMapListBld2;
@@ -95,22 +94,22 @@ public class FlowRegistryKeyFactoryTest {
         // different priority
         flowStatisticsMapListBld2 = new FlowAndStatisticsMapListBuilder(flowStatisticsMapList1);
         flowStatisticsMapListBld2.setPriority(Uint16.valueOf(flowStatisticsMapListBld2.getPriority().toJava() + 1));
-        key2 = FlowRegistryKeyFactory.create(deviceInfo.getVersion(), flowStatisticsMapListBld2.build());
-        Assert.assertFalse(key1.equals(key2));
+        key2 = keyFactory.create(flowStatisticsMapListBld2.build());
+        assertFalse(key1.equals(key2));
 
         // different match
         flowStatisticsMapListBld2 = new FlowAndStatisticsMapListBuilder(flowStatisticsMapList1);
         flowStatisticsMapListBld2.setMatch(new MatchBuilder().build());
-        key2 = FlowRegistryKeyFactory.create(deviceInfo.getVersion(), flowStatisticsMapListBld2.build());
-        Assert.assertFalse(key1.equals(key2));
+        key2 = keyFactory.create(flowStatisticsMapListBld2.build());
+        assertFalse(key1.equals(key2));
 
         // different tableId
         flowStatisticsMapListBld2 = new FlowAndStatisticsMapListBuilder(flowStatisticsMapList1);
         flowStatisticsMapListBld2.setTableId(Uint8.valueOf(flowStatisticsMapListBld2.getTableId().toJava() + 1));
-        key2 = FlowRegistryKeyFactory.create(deviceInfo.getVersion(), flowStatisticsMapListBld2.build());
-        Assert.assertFalse(key1.equals(key2));
+        key2 = keyFactory.create(flowStatisticsMapListBld2.build());
+        assertFalse(key1.equals(key2));
 
-        Assert.assertFalse(key1.equals(null));
+        assertFalse(key1.equals(null));
     }
 
     @Test
@@ -124,7 +123,7 @@ public class FlowRegistryKeyFactoryTest {
                 .setPriority(Uint16.TWO)
                 .setTableId(Uint8.ZERO);
 
-        FlowRegistryKey flow1Hash = FlowRegistryKeyFactory.create(deviceInfo.getVersion(), flow1Builder.build());
+        FlowRegistryKey flow1Hash = FlowRegistryKeyFactory.VERSION_1_3.create(flow1Builder.build());
         LOG.info("flowHash1: {}", flow1Hash.hashCode());
 
 
@@ -134,10 +133,10 @@ public class FlowRegistryKeyFactoryTest {
                 .setCookie(new FlowCookie(Uint64.valueOf(148)))
                 .setMatch(match2Builder.build());
 
-        FlowRegistryKey flow2Hash = FlowRegistryKeyFactory.create(deviceInfo.getVersion(), flow2Builder.build());
+        FlowRegistryKey flow2Hash = FlowRegistryKeyFactory.VERSION_1_3.create(flow2Builder.build());
         LOG.info("flowHash2: {}", flow2Hash.hashCode());
 
-        Assert.assertNotSame(flow1Hash, flow2Hash);
+        assertNotSame(flow1Hash, flow2Hash);
     }
 
     @Test
@@ -153,28 +152,21 @@ public class FlowRegistryKeyFactoryTest {
 
         FlowBuilder fb1 = new FlowBuilder(flow1Builder.build());
         fb1.setTableId((Uint8) null);
-        try {
-            FlowRegistryKeyFactory.create(deviceInfo.getVersion(), fb1.build());
-            Assert.fail("hash creation should have failed because of NPE");
-        } catch (NullPointerException e) {
-            // expected
-            Assert.assertEquals("flow tableId must not be null", e.getMessage());
-        }
+
+        var ex = assertThrows(NoSuchElementException.class,
+            () -> FlowRegistryKeyFactory.VERSION_1_3.create(fb1.build()));
+        assertEquals("Value of tableid is not present", ex.getMessage());
 
         FlowBuilder fb2 = new FlowBuilder(flow1Builder.build());
         fb2.setPriority((Uint16) null);
-        try {
-            FlowRegistryKeyFactory.create(deviceInfo.getVersion(), fb2.build());
-        } catch (NullPointerException e) {
-            // not expected
-            Assert.fail("no exception was expected while hash was creating.");
-        }
+
+        assertNotNull(FlowRegistryKeyFactory.VERSION_1_3.create(fb2.build()));
 
         FlowBuilder fb3 = new FlowBuilder(flow1Builder.build());
         fb3.setCookie(null);
-        FlowRegistryKey flowRegistryKey = FlowRegistryKeyFactory.create(deviceInfo.getVersion(), fb3.build());
-        Assert.assertNotNull(flowRegistryKey.getCookie());
-        Assert.assertEquals(OFConstants.DEFAULT_COOKIE, flowRegistryKey.getCookie());
+        FlowRegistryKey flowRegistryKey = FlowRegistryKeyFactory.VERSION_1_3.create(fb3.build());
+        assertNotNull(flowRegistryKey.getCookie());
+        assertEquals(OFConstants.DEFAULT_COOKIE, flowRegistryKey.getCookie());
     }
 
     @Test
@@ -182,7 +174,7 @@ public class FlowRegistryKeyFactoryTest {
         FlowsStatisticsUpdate flowStats = FLOWS_STATISTICS_UPDATE_BUILDER.build();
 
         for (FlowAndStatisticsMapList item : flowStats.nonnullFlowAndStatisticsMapList()) {
-            FlowRegistryKey flowRegistryKey = FlowRegistryKeyFactory.create(deviceInfo.getVersion(), item);
+            FlowRegistryKey flowRegistryKey = FlowRegistryKeyFactory.VERSION_1_3.create(item);
             FlowRegistryKey lastHash = null;
             if (null != lastHash) {
                 assertNotEquals(lastHash, flowRegistryKey);
index 761935b2ff3be8615a863f6f262bb9ef3038c2ae..872dbc7a3a266a721f4e411398ea8f6ba43549a0 100644 (file)
@@ -13,19 +13,16 @@ import static org.junit.Assert.assertNotNull;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import java.util.Collections;
 import java.util.List;
-import java.util.Optional;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.ArgumentMatchers;
 import org.mockito.Mock;
-import org.mockito.Mockito;
 import org.mockito.junit.MockitoJUnitRunner;
 import org.opendaylight.mdsal.binding.api.ReadTransaction;
 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
@@ -42,7 +39,6 @@ import org.opendaylight.openflowplugin.impl.datastore.MultipartWriterProviderFac
 import org.opendaylight.openflowplugin.impl.rpc.AbstractRequestContext;
 import org.opendaylight.openflowplugin.impl.services.multilayer.MultiLayerFlowMultipartRequestOnTheFlyCallback;
 import org.opendaylight.openflowplugin.impl.statistics.ofpspecific.MessageIntelligenceAgencyImpl;
-import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.ConvertorManager;
 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.ConvertorManagerFactory;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeBuilder;
@@ -104,6 +100,8 @@ public class MultipartRequestOnTheFlyCallbackTest {
     @Mock
     private DeviceFlowRegistry mockedFlowRegistry;
     @Mock
+    private FlowRegistryKey mockedFlowKey;
+    @Mock
     private FlowDescriptor mockedFlowDescriptor;
     @Mock
     private ReadTransaction mockedReadOnlyTx;
@@ -129,39 +127,32 @@ public class MultipartRequestOnTheFlyCallbackTest {
 
         when(mockedDeviceContext.getDeviceInfo()).thenReturn(mockedDeviceInfo);
         when(mockedDeviceContext.getDeviceFlowRegistry()).thenReturn(mockedFlowRegistry);
+        when(mockedFlowRegistry.createKey(any())).thenReturn(mockedFlowKey);
         when(mockedFlowRegistry.retrieveDescriptor(any(FlowRegistryKey.class)))
                 .thenReturn(mockedFlowDescriptor);
 
-        final InstanceIdentifier<FlowCapableNode> nodePath =
-                mockedDeviceInfo.getNodeInstanceIdentifier().augmentation(FlowCapableNode.class);
-        final FlowCapableNodeBuilder flowNodeBuilder = new FlowCapableNodeBuilder();
-        flowNodeBuilder.setTable(Collections.emptyMap());
-        final Optional<FlowCapableNode> flowNodeOpt = Optional.of(flowNodeBuilder.build());
         dummyRequestContext = new AbstractRequestContext<>(DUMMY_XID) {
-
             @Override
             public void close() {
                 //NOOP
             }
         };
 
-        final ConvertorManager convertorManager = ConvertorManagerFactory.createDefaultManager();
         multipartRequestOnTheFlyCallback = new MultiLayerFlowMultipartRequestOnTheFlyCallback<>(
             dummyRequestContext,
             String.class,
             mockedDeviceContext,
             dummyEventIdentifier,
             MultipartWriterProviderFactory.createDefaultProvider(mockedDeviceContext),
-            convertorManager);
+            ConvertorManagerFactory.createDefaultManager());
     }
 
 
     @Test
     public void testOnSuccessWithNull() throws Exception {
         multipartRequestOnTheFlyCallback.onSuccess(null);
-        final RpcResult<List<MultipartReply>> expectedRpcResult =
-                RpcResultBuilder.success(Collections.<MultipartReply>emptyList()).build();
-        final RpcResult<List<MultipartReply>> actualResult = dummyRequestContext.getFuture().get();
+        final var expectedRpcResult = RpcResultBuilder.<List<MultipartReply>>success(List.of()).build();
+        final var actualResult = dummyRequestContext.getFuture().get();
         assertEquals(expectedRpcResult.getErrors(), actualResult.getErrors());
         assertEquals(expectedRpcResult.getResult(), actualResult.getResult());
         assertEquals(expectedRpcResult.isSuccessful(), actualResult.isSuccessful());
@@ -187,10 +178,9 @@ public class MultipartRequestOnTheFlyCallbackTest {
         assertEquals(expectedRpcResult.getResult(), actualResult.getResult());
         assertEquals(expectedRpcResult.isSuccessful(), actualResult.isSuccessful());
 
-        Mockito.verify(mockedDeviceContext, Mockito.never())
-                .writeToTransaction(eq(LogicalDatastoreType.OPERATIONAL),
-                        ArgumentMatchers.<InstanceIdentifier>any(), ArgumentMatchers.any());
-        Mockito.verify(mockedDeviceContext).submitTransaction();
+        verify(mockedDeviceContext, never())
+                .writeToTransaction(eq(LogicalDatastoreType.OPERATIONAL), any(), any());
+        verify(mockedDeviceContext).submitTransaction();
     }
 
     /**
@@ -199,7 +189,7 @@ public class MultipartRequestOnTheFlyCallbackTest {
     @Test
     public void testOnSuccessWithValidMultipart1() {
         final MatchBuilder matchBuilder = new MatchBuilder()
-                .setMatchEntry(Collections.emptyList());
+                .setMatchEntry(List.of());
         final FlowStatsBuilder flowStatsBuilder = new FlowStatsBuilder()
                 .setTableId(tableId)
                 .setPriority(Uint16.TWO)
@@ -211,7 +201,7 @@ public class MultipartRequestOnTheFlyCallbackTest {
                 .setMatch(matchBuilder.build())
                 .setFlags(new FlowModFlags(true, false, false, false, false));
         final MultipartReplyFlowBuilder multipartReplyFlowBuilder = new MultipartReplyFlowBuilder()
-                .setFlowStats(Collections.singletonList(flowStatsBuilder.build()));
+                .setFlowStats(List.of(flowStatsBuilder.build()));
         final MultipartReplyFlowCaseBuilder multipartReplyFlowCaseBuilder = new MultipartReplyFlowCaseBuilder()
                 .setMultipartReplyFlow(multipartReplyFlowBuilder.build());
         final MultipartReplyMessageBuilder mpReplyMessage = new MultipartReplyMessageBuilder()
@@ -226,14 +216,12 @@ public class MultipartRequestOnTheFlyCallbackTest {
         final TableBuilder tableDataBld = new TableBuilder();
         tableDataBld.setId(tableId);
         flowNodeBuilder.setTable(BindingMap.of(tableDataBld.build()));
-        final Optional<FlowCapableNode> flowNodeOpt = Optional.of(flowNodeBuilder.build());
 
         multipartRequestOnTheFlyCallback.onSuccess(mpReplyMessage.build());
 
-        verify(mockedReadOnlyTx, times(0)).read(LogicalDatastoreType.OPERATIONAL, nodePath);
-        verify(mockedReadOnlyTx, times(0)).close();
-        verify(mockedDeviceContext, times(1)).writeToTransaction(eq(LogicalDatastoreType.OPERATIONAL),
-                any(), any());
+        verify(mockedReadOnlyTx, never()).read(LogicalDatastoreType.OPERATIONAL, nodePath);
+        verify(mockedReadOnlyTx, never()).close();
+        verify(mockedDeviceContext, times(1)).writeToTransaction(eq(LogicalDatastoreType.OPERATIONAL), any(), any());
     }
 
     /**
@@ -252,9 +240,8 @@ public class MultipartRequestOnTheFlyCallbackTest {
         // Nothing else than flow is supported by on the fly callback
         assertNotNull(actualResult.getErrors());
         assertFalse(actualResult.getErrors().isEmpty());
-        Mockito.verify(mockedFlowRegistry, Mockito.never()).store(any());
-        Mockito.verify(mockedDeviceContext, Mockito.never())
-                .writeToTransaction(eq(LogicalDatastoreType.OPERATIONAL),
-                        ArgumentMatchers.<InstanceIdentifier>any(), ArgumentMatchers.any());
+        verify(mockedFlowRegistry, never()).store(any());
+        verify(mockedDeviceContext, never())
+                .writeToTransaction(eq(LogicalDatastoreType.OPERATIONAL), any(), any());
     }
 }
index acdd46c67b7660a952d6fd98ea3f980b8fff4966..73fe382d884c023e52f1319fd5e419cf11b3bed0 100644 (file)
@@ -10,13 +10,13 @@ package org.opendaylight.openflowplugin.impl.services.sal;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
-import java.util.concurrent.ExecutionException;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -33,6 +33,7 @@ import org.opendaylight.openflowplugin.api.openflow.device.RequestContext;
 import org.opendaylight.openflowplugin.api.openflow.device.RequestContextStack;
 import org.opendaylight.openflowplugin.api.openflow.device.Xid;
 import org.opendaylight.openflowplugin.api.openflow.registry.flow.DeviceFlowRegistry;
+import org.opendaylight.openflowplugin.api.openflow.registry.flow.FlowRegistryKey;
 import org.opendaylight.openflowplugin.api.openflow.statistics.ofpspecific.MessageSpy;
 import org.opendaylight.openflowplugin.impl.services.multilayer.MultiAddFlow;
 import org.opendaylight.openflowplugin.impl.services.multilayer.MultiRemoveFlow;
@@ -116,6 +117,8 @@ public class SalFlowServiceImplTest {
     @Mock
     private DeviceFlowRegistry deviceFlowRegistry;
     @Mock
+    private FlowRegistryKey flowKey;
+    @Mock
     private GetFeaturesOutput mockedFeaturesOutput;
 
     @Before
@@ -165,6 +168,7 @@ public class SalFlowServiceImplTest {
 
     @Test
     public void testAddFlow() throws Exception {
+        when(deviceFlowRegistry.createKey(any())).thenReturn(flowKey);
         addFlow(OFConstants.OFP_VERSION_1_0);
         addFlow(OFConstants.OFP_VERSION_1_3);
     }
@@ -179,7 +183,7 @@ public class SalFlowServiceImplTest {
         addFlowFailCallback(OFConstants.OFP_VERSION_1_3);
     }
 
-    private void addFlowFailCallback(final Uint8 version) throws InterruptedException, ExecutionException {
+    private void addFlowFailCallback(final Uint8 version) throws Exception {
         AddFlowInput mockedAddFlowInput = new AddFlowInputBuilder()
                 .setMatch(match)
                 .setTableId(Uint8.ONE)
@@ -188,6 +192,7 @@ public class SalFlowServiceImplTest {
 
         doReturn(Futures.<RequestContext<Object>>immediateFailedFuture(new Exception("ut-failed-response")))
                 .when(requestContext).getFuture();
+        when(deviceFlowRegistry.createKey(any())).thenReturn(flowKey);
 
         final var rpcResultFuture = mockAddFlow(version).invoke(mockedAddFlowInput);
 
@@ -207,7 +212,7 @@ public class SalFlowServiceImplTest {
         removeFlowFailCallback(OFConstants.OFP_VERSION_1_3);
     }
 
-    private void removeFlowFailCallback(final Uint8 version) throws InterruptedException, ExecutionException {
+    private void removeFlowFailCallback(final Uint8 version) throws Exception {
         RemoveFlowInput mockedRemoveFlowInput = new RemoveFlowInputBuilder()
                 .setTableId(Uint8.ONE)
                 .setMatch(match)
@@ -227,11 +232,13 @@ public class SalFlowServiceImplTest {
 
     @Test
     public void testAddFlowWithItemLifecycle() throws Exception {
+        when(deviceFlowRegistry.createKey(any())).thenReturn(flowKey);
         addFlow(OFConstants.OFP_VERSION_1_0);
         addFlow(OFConstants.OFP_VERSION_1_3);
     }
 
-    private void addFlow(final Uint8 version) throws ExecutionException, InterruptedException {
+    private void addFlow(final Uint8 version) throws Exception {
+
         AddFlowInput mockedAddFlowInput = new AddFlowInputBuilder()
                 .setMatch(match)
                 .setTableId(Uint8.ONE)
@@ -321,7 +328,7 @@ public class SalFlowServiceImplTest {
     }
 
     private static <T extends DataObject> void verifyOutput(final ListenableFuture<RpcResult<T>> rpcResultFuture)
-            throws ExecutionException, InterruptedException {
+            throws Exception {
         assertNotNull(rpcResultFuture);
         final var addFlowOutputRpcResult = rpcResultFuture.get();
         assertNotNull(addFlowOutputRpcResult);
index 5e7fe6fb8cbc9f5ced805f95029085fc0acd02de..d1ccf1d24b137f6ce924c9bd28024a816d1b77cf 100755 (executable)
@@ -155,6 +155,8 @@ public class StatisticsGatheringUtilsTest {
     @Mock
     private FlowDescriptor flowDescriptor;
     @Mock
+    private FlowRegistryKey flowRegistryKey;
+    @Mock
     private FlowId flowId;
     @Mock
     private GetFeaturesOutput features;
@@ -175,7 +177,8 @@ public class StatisticsGatheringUtilsTest {
         when(deviceContext.getDeviceFlowRegistry()).thenReturn(deviceFlowRegistry);
         when(deviceContext.getDeviceGroupRegistry()).thenReturn(deviceGroupRegistry);
         when(deviceContext.getDeviceMeterRegistry()).thenReturn(deviceMeterRegistry);
-        when(deviceFlowRegistry.retrieveDescriptor(any(FlowRegistryKey.class))).thenReturn(flowDescriptor);
+        when(deviceFlowRegistry.createKey(any())).thenReturn(flowRegistryKey);
+        when(deviceFlowRegistry.retrieveDescriptor(any())).thenReturn(flowDescriptor);
         when(flowDescriptor.getFlowId()).thenReturn(new FlowId("MOCK_FLOW"));
         when(deviceContext.getReadTransaction()).thenReturn(readTx);
         when(deviceContext.getReadTransaction()).thenReturn(readTx);
@@ -208,7 +211,7 @@ public class StatisticsGatheringUtilsTest {
         Assert.assertEquals(42, flow.getValue().getTableId().intValue());
     }
 
-    private static Iterable<FlowsStatisticsUpdate> prepareFlowStatisticsData() {
+    private static List<FlowsStatisticsUpdate> prepareFlowStatisticsData() {
         final FlowAndStatisticsMapListBuilder flowAndStatsMapListBld = new FlowAndStatisticsMapListBuilder();
         flowAndStatsMapListBld.setTableId(Uint8.valueOf(42));
         flowAndStatsMapListBld.setMatch(new MatchBuilder().build());
index dde1522fec2dd98c8573a8a39e5616c9c2c8a90e..8ffb5763ce53671eabca9cccdc3647aa0bea550a 100644 (file)
@@ -5,13 +5,11 @@
  * 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.openflowplugin.impl.util;
 
 import static org.junit.Assert.assertEquals;
 
 import org.junit.Test;
-import org.opendaylight.openflowplugin.api.OFConstants;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address;
@@ -22,16 +20,12 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.
 import org.opendaylight.yang.gen.v1.urn.opendaylight.opendaylight.ipv6.arbitrary.bitmask.fields.rev160224.Ipv6ArbitraryMask;
 
 public class AddressNormalizationUtilTest {
-
     @Test
     public void normalizeProtocolAgnosticPortOF10() {
         final Uri left = new Uri("openflow:1:INPORT");
         final Uri right = new Uri("IN_PORT");
 
-        assertEquals(
-                right,
-                AddressNormalizationUtil.normalizeProtocolAgnosticPort(left, OFConstants.OFP_VERSION_1_0)
-        );
+        assertEquals(right, AddressNormalizationUtil.VERSION_1_0.normalizeProtocolAgnosticPort(left));
     }
 
     @Test
@@ -39,10 +33,7 @@ public class AddressNormalizationUtilTest {
         final Uri left = new Uri("openflow:1:ANY");
         final Uri right = new Uri("ANY");
 
-        assertEquals(
-                right,
-                AddressNormalizationUtil.normalizeProtocolAgnosticPort(left, OFConstants.OFP_VERSION_1_3)
-        );
+        assertEquals(right, AddressNormalizationUtil.VERSION_1_3.normalizeProtocolAgnosticPort(left));
     }
 
     @Test
index f945d83ba81d4b141a0dd284a6b1a824a4d0a23b..6bbf932d4a57aed662a2324da048b8a7dce19899 100644 (file)
@@ -11,7 +11,6 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
 
 import org.junit.Test;
-import org.opendaylight.openflowjava.protocol.api.util.EncodeConstants;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address;
@@ -43,8 +42,8 @@ public class MatchNormalizationUtilTest {
     public void normalizeInPortMatch() {
         final long port = 10;
 
-        final MatchBuilder matchBuilder = MatchNormalizationUtil.normalizeInPortMatch(new MatchBuilder()
-                .setInPort(new NodeConnectorId("openflow:1:" + port)), EncodeConstants.OF_VERSION_1_3);
+        final MatchBuilder matchBuilder = MatchNormalizationUtil.VERSION_1_3.normalizeInPortMatch(new MatchBuilder()
+                .setInPort(new NodeConnectorId("openflow:1:" + port)));
 
         assertEquals(String.valueOf(port), matchBuilder.getInPort().getValue());
     }
@@ -53,8 +52,8 @@ public class MatchNormalizationUtilTest {
     public void normalizeInPhyPortMatch() {
         final long port = 10;
 
-        final MatchBuilder matchBuilder = MatchNormalizationUtil.normalizeInPhyPortMatch(new MatchBuilder()
-                .setInPhyPort(new NodeConnectorId("openflow:1:" + port)), EncodeConstants.OF_VERSION_1_3);
+        final MatchBuilder matchBuilder = MatchNormalizationUtil.VERSION_1_3.normalizeInPhyPortMatch(new MatchBuilder()
+                .setInPhyPort(new NodeConnectorId("openflow:1:" + port)));
 
         assertEquals(String.valueOf(port), matchBuilder.getInPhyPort().getValue());
     }