Handle nullable lists in sfc 59/77259/2
authorStephen Kitt <skitt@redhat.com>
Wed, 24 Oct 2018 15:18:23 +0000 (17:18 +0200)
committerSam Hague <shague@redhat.com>
Thu, 25 Oct 2018 22:47:52 +0000 (22:47 +0000)
Following YANGTOOLS-585, lists can be null (which is correctly
indicated with an @Nullable annotation). This patch deals with the
fallout.

This adds a couple of utility classes which will be deleted as soon as
we upgrade to the MRI release of mdsal.

Change-Id: I1af1362d6b812cf07ae90564037d6afe81cd610e
Signed-off-by: Stephen Kitt <skitt@redhat.com>
14 files changed:
sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/providers/GeniusProvider.java
sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/providers/OpenFlow13Provider.java
sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/providers/SfcProvider.java
sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/service/domain/ClassifierEntry.java
sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/service/domain/impl/ConfigurationClassifierImpl.java
sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/utils/AclMatches.java
sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/utils/SfcUtils.java [new file with mode: 0644]
sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/DelegatingDataTreeListener.java
sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/NeutronMdsalHelper.java
sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/SfcMdsalHelper.java
sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/SfcTranslatorUtils.java [new file with mode: 0644]
sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/flowclassifier/FlowClassifierTranslator.java
sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/portchain/NeutronPortChainListener.java
sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/portchain/PortChainTranslator.java

index 8c3dcbb779df766c19f3761e2258160703e1cddb..6bc689b629187ea4c3b0a5a39d9f9d2aece850b4 100644 (file)
@@ -8,6 +8,8 @@
 
 package org.opendaylight.netvirt.sfc.classifier.providers;
 
+import static org.opendaylight.netvirt.sfc.classifier.utils.SfcUtils.nullToEmpty;
+
 import com.google.common.net.InetAddresses;
 import java.math.BigInteger;
 import java.util.Collections;
@@ -271,12 +273,11 @@ public class GeniusProvider {
             }
 
             Class<? extends InterfaceTypeBase> ifType = tp.getInterfaceType();
-            if (ifType.equals(InterfaceTypeVxlan.class)) {
-                List<Options> tpOptions = tp.getOptions();
-                for (Options tpOption : tpOptions) {
+            if (InterfaceTypeVxlan.class.equals(ifType)) {
+                for (Options tpOption : nullToEmpty(tp.getOptions())) {
                     // From the VXLAN Tunnels, we want the one with the GPE option set
-                    if (tpOption.key().getOption().equals(OPTION_KEY_REMOTE_IP)) {
-                        if (tpOption.getValue().equals(OPTION_VALUE_FLOW) && tp.getOfport() != null) {
+                    if (OPTION_KEY_REMOTE_IP.equals(tpOption.key().getOption())) {
+                        if (OPTION_VALUE_FLOW.equals(tpOption.getValue()) && tp.getOfport() != null) {
                             return Optional.ofNullable(tp.getOfport());
                         }
                     }
index 850df6204aecba65836dbd8a70478defbfde693d..5ef5f2228a89d596340096ee60f9b8964d6e239e 100644 (file)
@@ -12,6 +12,7 @@ import com.google.common.net.InetAddresses;
 import java.math.BigInteger;
 import java.util.ArrayList;
 import java.util.List;
+import javax.annotation.Nullable;
 import javax.inject.Singleton;
 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
 import org.opendaylight.genius.infra.Datastore.Configuration;
@@ -79,6 +80,7 @@ public class OpenFlow13Provider {
     public static final String OF_URI_SEPARATOR = ":";
     public static final Ipv4Address NULL_IP = new Ipv4Address("0.0.0.0");
 
+    @Nullable
     public List<MatchBuilder> getMatchBuilderFromAceMatches(Matches matches) {
         if (matches == null) {
             return null;
index 1ec6dcf4101cd102c97cb9b548ff76d88041bce9..c91892c09800790760a661278d63d39a09a82292 100644 (file)
@@ -10,6 +10,7 @@ package org.opendaylight.netvirt.sfc.classifier.providers;
 
 import java.util.Collections;
 import java.util.List;
+import java.util.Objects;
 import java.util.Optional;
 import java.util.stream.Collectors;
 import javax.inject.Inject;
@@ -124,7 +125,7 @@ public class SfcProvider {
         SffSfDataPlaneLocator sffSfDataPlaneLocator = sff.map(ServiceFunctionForwarder::getServiceFunctionDictionary)
                 .orElse(Collections.emptyList())
                 .stream()
-                .filter(serviceFunctionDictionary -> serviceFunctionDictionary.getName().equals(sfName))
+                .filter(serviceFunctionDictionary -> Objects.equals(serviceFunctionDictionary.getName(), sfName))
                 .findAny()
                 .map(ServiceFunctionDictionary::getSffSfDataPlaneLocator)
                 .orElse(null);
@@ -153,7 +154,7 @@ public class SfcProvider {
         Optional<String> interfaceName = sff.map(ServiceFunctionForwarderBase::getSffDataPlaneLocator)
                 .orElse(Collections.emptyList())
                 .stream()
-                .filter(sffDataPlaneLocator -> sffDataPlaneLocator.getName().equals(locatorName))
+                .filter(sffDataPlaneLocator -> Objects.equals(sffDataPlaneLocator.getName(), locatorName))
                 .findAny()
                 .map(SffDataPlaneLocator::getDataPlaneLocator)
                 .filter(dataPlaneLocator -> dataPlaneLocator.getLocatorType() instanceof LogicalInterface)
index 9760a40038f300538822e4089930c61c884abb83..0cc4294c5d4fa5c2a719abf94bf1adcb3ab93f4f 100644 (file)
@@ -10,6 +10,7 @@ package org.opendaylight.netvirt.sfc.classifier.service.domain;
 
 import com.google.common.base.MoreObjects;
 import java.util.Objects;
+import javax.annotation.Nullable;
 import org.opendaylight.netvirt.sfc.classifier.service.domain.api.ClassifierEntryRenderer;
 import org.opendaylight.netvirt.sfc.classifier.service.domain.api.ClassifierRenderableEntry;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.Matches;
@@ -31,19 +32,21 @@ public final class ClassifierEntry implements ClassifierRenderableEntry {
     }
 
     private final EntryType entryType;
-    private final NodeId node;
-    private final InterfaceKey interfaceKey;
-    private final String connector;
-    private final Matches matches;
-    private final Long nsp;
-    private final Short nsi;
-    private final Short nsl;
-    private final String destinationIp;
-    private final String firstHopIp;
+    // TODO skitt Rework using a class hierarchy so we can enforce null constraints
+    private final @Nullable NodeId node;
+    private final @Nullable InterfaceKey interfaceKey;
+    private final @Nullable String connector;
+    private final @Nullable Matches matches;
+    private final @Nullable Long nsp;
+    private final @Nullable Short nsi;
+    private final @Nullable Short nsl;
+    private final @Nullable String destinationIp;
+    private final @Nullable String firstHopIp;
 
-    private ClassifierEntry(EntryType entryType, NodeId node, InterfaceKey interfaceKey, String connector,
-                            Matches matches, Long nsp, Short nsi, Short nsl, String destinationIp,
-                            String firstHopIp) {
+    private ClassifierEntry(EntryType entryType, @Nullable NodeId node, @Nullable InterfaceKey interfaceKey,
+                            @Nullable String connector, @Nullable Matches matches, @Nullable Long nsp,
+                            @Nullable Short nsi, @Nullable Short nsl, @Nullable String destinationIp,
+                            @Nullable String firstHopIp) {
         this.entryType = entryType;
         this.node = node;
         this.interfaceKey = interfaceKey;
@@ -206,7 +209,7 @@ public final class ClassifierEntry implements ClassifierRenderableEntry {
      * @return the {@code ClassifierEntry}.
      */
     public static ClassifierEntry buildPathEntry(NodeId node, Long nsp, short nsi, short nsl,
-                                                 String firstHopIp) {
+                                                 @Nullable String firstHopIp) {
         return new ClassifierEntry(
                 EntryType.PATH_ENTRY_TYPE,
                 node,
index 68a461d6abe42c2584f2c7dc39ba5279d657e0bc..cff22de7cdc633cc6d44f11be2781b01bbfeaf49 100644 (file)
@@ -215,7 +215,7 @@ public class ConfigurationClassifierImpl implements ClassifierState {
                 .orElse(null);
         RenderedServicePath reverseRsp = rsps.stream()
                 .filter(RenderedServicePath::isReversePath)
-                .filter(rsp -> forwardRsp != null && rsp.getSymmetricPathId().equals(forwardRsp.getPathId()))
+                .filter(rsp -> forwardRsp != null && Objects.equals(rsp.getSymmetricPathId(), forwardRsp.getPathId()))
                 .findAny()
                 .orElse(null);
 
index 0a7b27798c4407673e28759b19ed677337819dca..f931677f09d5a582b4c4808a27a4bf211feca2de 100644 (file)
@@ -98,7 +98,7 @@ public class AclMatches {
         }
         if (portMatches.isEmpty()) {
             newMatches.add(this.matchBuilder);
-        } else if (!portMatches.isEmpty()) {
+        } else {
             for (GeneralAugMatchNodesNodeTableFlow portMatch : portMatches) {
                 newMatches.add(new MatchBuilder(matchBuilder.build())
                     .addAugmentation(GeneralAugMatchNodesNodeTableFlow.class, portMatch));
diff --git a/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/utils/SfcUtils.java b/sfc/classifier/impl/src/main/java/org/opendaylight/netvirt/sfc/classifier/utils/SfcUtils.java
new file mode 100644 (file)
index 0000000..61f8ea6
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright © 2018 Red Hat, Inc. and others.
+ *
+ * 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.netvirt.sfc.classifier.utils;
+
+import static java.util.Collections.emptyList;
+
+import java.util.List;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+public final class SfcUtils {
+    private SfcUtils() {
+        // Utility class
+    }
+
+    // TODO Replace this with mdsal's DataObjectUtils.nullToEmpty when upgrading to mdsal 3
+    @Nonnull
+    public static <T> List<T> nullToEmpty(final @Nullable List<T> input) {
+        return input != null ? input : emptyList();
+    }
+}
index 1354af1ec4db7555cd046674c8618bf67b33f8e0..003605e1d00666d5b672a196979b5930a542e9f5 100644 (file)
@@ -15,6 +15,7 @@ import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ThreadFactory;
 import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
 import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener;
@@ -37,6 +38,7 @@ public abstract class DelegatingDataTreeListener<T extends DataObject> implement
         .setNameFormat("NeutronSfcListener-%d").build();
     private final ExecutorService executorService = Executors.newFixedThreadPool(1, THREAD_FACTORY);
     private final INeutronSfcDataProcessor<T> dataProcessor;
+    @Nullable
     private ListenerRegistration<DelegatingDataTreeListener<T>> listenerRegistration;
 
     public DelegatingDataTreeListener(DataBroker db, DataTreeIdentifier<T> treeId) {
@@ -96,8 +98,6 @@ public abstract class DelegatingDataTreeListener<T extends DataObject> implement
             listenerRegistration.close();
             listenerRegistration = null;
         }
-        if (executorService != null) {
-            executorService.shutdownNow();
-        }
+        executorService.shutdownNow();
     }
 }
index f9307545f095d024436f7a8b5ca02f05d17f482a..f1c21cb5c0686f81a9fb2351c92fef36fb4465cc 100644 (file)
@@ -8,6 +8,7 @@
 
 package org.opendaylight.netvirt.sfc.translator;
 
+import javax.annotation.Nullable;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
@@ -50,21 +51,25 @@ public class NeutronMdsalHelper {
         this.dataBroker = dataBroker;
     }
 
+    @Nullable
     public Port getNeutronPort(Uuid portId) {
         return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
                 LogicalDatastoreType.CONFIGURATION, getNeutronPortPath(portId)).orNull();
     }
 
+    @Nullable
     public PortPair getNeutronPortPair(Uuid portPairId) {
         return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
                 LogicalDatastoreType.CONFIGURATION, getNeutronPortPairPath(portPairId)).orNull();
     }
 
+    @Nullable
     public PortPairGroup getNeutronPortPairGroup(Uuid portPairGroupId) {
         return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
                 LogicalDatastoreType.CONFIGURATION, getNeutronPortPairGroupPath(portPairGroupId)).orNull();
     }
 
+    @Nullable
     public SfcFlowClassifier getNeutronFlowClassifier(Uuid flowClassifierId) {
         return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
                 LogicalDatastoreType.CONFIGURATION, getNeutronSfcFlowClassifierPath(flowClassifierId)).orNull();
index d83690187a076a0a8f5b3838fe8843817cc592d6..e68a2de06f91ee5e1661558e9b0314ab1099bb04 100644 (file)
@@ -8,6 +8,7 @@
 
 package org.opendaylight.netvirt.sfc.translator;
 
+import javax.annotation.Nullable;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
@@ -87,6 +88,7 @@ public class SfcMdsalHelper {
     }
 
     //Service Function
+    @Nullable
     public ServiceFunction readServiceFunction(ServiceFunctionKey sfKey) {
         InstanceIdentifier<ServiceFunction> sfIid = getSFPath(sfKey);
         LOG.info("Read Service Function {} from config data store at {}",sfKey, sfIid);
@@ -125,6 +127,7 @@ public class SfcMdsalHelper {
     }
 
     //Service Function Forwarder
+    @Nullable
     public ServiceFunctionForwarder readServiceFunctionForwarder(ServiceFunctionForwarderKey sffKey) {
         InstanceIdentifier<ServiceFunctionForwarder> sffIid = getSFFPath(sffKey);
         LOG.info("Read Service Function Forwarder from config data store at {}", sffIid);
diff --git a/sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/SfcTranslatorUtils.java b/sfc/translator/src/main/java/org/opendaylight/netvirt/sfc/translator/SfcTranslatorUtils.java
new file mode 100644 (file)
index 0000000..1be3afe
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright © 2018 Red Hat, Inc. and others.
+ *
+ * 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.netvirt.sfc.translator;
+
+import static java.util.Collections.emptyList;
+
+import java.util.List;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+public final class SfcTranslatorUtils {
+    private SfcTranslatorUtils() {
+        // Utility class
+    }
+
+    // TODO Replace this with mdsal's DataObjectUtils.nullToEmpty when upgrading to mdsal 3
+    @Nonnull
+    public static <T> List<T> nullToEmpty(final @Nullable List<T> input) {
+        return input != null ? input : emptyList();
+    }
+}
index 810110ef0842ebe98c17062e9eef18142e67ff5a..4816304fd09e2eb0be6ed2187dd0d62002cd4c01 100644 (file)
@@ -9,6 +9,7 @@
 package org.opendaylight.netvirt.sfc.translator.flowclassifier;
 
 import java.util.ArrayList;
+import javax.annotation.Nullable;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.Ipv4Acl;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.Ipv6Acl;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.Acl;
@@ -55,7 +56,7 @@ public final class FlowClassifierTranslator {
         return buildAcl(flowClassifier, null);
     }
 
-    public static Acl buildAcl(SfcFlowClassifier flowClassifier, String sfpName) {
+    public static Acl buildAcl(SfcFlowClassifier flowClassifier, @Nullable String sfpName) {
         LOG.info("OpenStack Networking SFC pushed Flow classifier : {}", flowClassifier);
         AclBuilder aclBuilder = new AclBuilder();
         AceBuilder aceBuilder = new AceBuilder();
@@ -101,7 +102,7 @@ public final class FlowClassifierTranslator {
                 if (sourceIp != null && sourceIp.getIpv6Prefix() != null) {
                     aceIpv6Builder.setSourceIpv6Network(sourceIp.getIpv6Prefix());
                 }
-                if (sourceIp != null && destinationIp.getIpv6Prefix() != null) {
+                if (destinationIp != null && destinationIp.getIpv6Prefix() != null) {
                     aceIpv6Builder.setDestinationIpv6Network(destinationIp.getIpv6Prefix());
                 }
                 aceIpBuilder.setAceIpVersion(aceIpv6Builder.build());
index fdd5eb4b98606dc72487ad547f0a4324d5e359a0..a7eeb799a31c378c409481a8d9b4e3627a1747a5 100644 (file)
@@ -8,10 +8,14 @@
 
 package org.opendaylight.netvirt.sfc.translator.portchain;
 
+import static org.opendaylight.netvirt.sfc.translator.SfcTranslatorUtils.nullToEmpty;
+
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
@@ -75,8 +79,8 @@ public class NeutronPortChainListener extends DelegatingDataTreeListener<PortCha
      */
     @Override
     public void update(PortChain origPortChain, PortChain updatePortChain) {
-        List<Uuid> oldFcList = origPortChain.getFlowClassifiers();
-        oldFcList.removeAll(updatePortChain.getFlowClassifiers());
+        List<Uuid> oldFcList = new ArrayList<>(nullToEmpty(origPortChain.getFlowClassifiers()));
+        oldFcList.removeAll(nullToEmpty(updatePortChain.getFlowClassifiers()));
         if (!oldFcList.isEmpty()) {
             LOG.debug("Removing old list {}", oldFcList);
             processFlowClassifiers(origPortChain, oldFcList, null, false);
@@ -105,12 +109,12 @@ public class NeutronPortChainListener extends DelegatingDataTreeListener<PortCha
         List<ServiceFunction> portChainServiceFunctionList = new ArrayList<>();
 
         //Read chain related port pair group from neutron data store
-        for (Uuid ppgUuid : newPortChain.getPortPairGroups()) {
+        for (Uuid ppgUuid : nullToEmpty(newPortChain.getPortPairGroups())) {
             PortPairGroup ppg = neutronMdsalHelper.getNeutronPortPairGroup(ppgUuid);
             if (ppg != null) {
                 List<PortPair> portPairList = new ArrayList<>();
                 portPairGroupList.add(ppg);
-                for (Uuid ppUuid : ppg.getPortPairs()) {
+                for (Uuid ppUuid : nullToEmpty(ppg.getPortPairs())) {
                     PortPair pp = neutronMdsalHelper.getNeutronPortPair(ppUuid);
                     if (pp == null) {
                         LOG.error("Port pair {} does not exist in the neutron data store", ppUuid);
@@ -169,10 +173,12 @@ public class NeutronPortChainListener extends DelegatingDataTreeListener<PortCha
         // The RSP will automatically be created from the SFP added above.
 
         // Add ACLs from flow classifiers
-        processFlowClassifiers(newPortChain, newPortChain.getFlowClassifiers(), sfp.getName().getValue(), true);
+        processFlowClassifiers(newPortChain, nullToEmpty(newPortChain.getFlowClassifiers()), sfp.getName().getValue(),
+            true);
     }
 
-    private void processFlowClassifiers(PortChain pc, List<Uuid> flowClassifiers, String sfpName, boolean added) {
+    private void processFlowClassifiers(PortChain pc, @Nonnull List<Uuid> flowClassifiers, @Nullable String sfpName,
+            boolean added) {
         for (Uuid uuid : flowClassifiers) {
             SfcFlowClassifier fc = neutronMdsalHelper.getNeutronFlowClassifier(uuid);
             if (fc != null) {
index 01407843b4ea1b88f47fb21b4a4e31ecc9e55ead..1b9e19e03f1c86aa6a04743fba2513f045dc72b8 100644 (file)
@@ -61,7 +61,7 @@ public final class PortChainTranslator {
         List<ChainParameters> cpList = portChain.getChainParameters();
         if (cpList != null && !cpList.isEmpty()) {
             for (ChainParameters cp : cpList) {
-                if (cp.getChainParameter().equals(SYMMETRIC_PARAM)) {
+                if (SYMMETRIC_PARAM.equals(cp.getChainParameter())) {
                     //Override the symmetric default value.
                     sfcBuilder.setSymmetric(Boolean.valueOf(cp.getChainParameterValue()));
                     break;