Fix FindBugs warnings in sal-remoterpc-connector and enable enforcement 96/47696/5
authorTom Pantelis <tpanteli@brocade.com>
Thu, 27 Oct 2016 17:06:33 +0000 (13:06 -0400)
committerTom Pantelis <tpanteli@brocade.com>
Wed, 30 Nov 2016 15:07:29 +0000 (15:07 +0000)
Warnings fixed:
  - RemoteRpcImplementation: use of 'error' known to be null
  - RpcBroker, RpcRegistry: The Creator class has non-Serializable field.
    Removed the Creator class and used Props that creates by reflection.
  - RpcBroker: use of 'result' that is marked as @Nullable
  - RpcBroker: redundant check of 'result.getErrors()' that is known to be
    non-null (marked as @Nonnull).
  - Gossiper, RemoteRpcRegistryMXBeanImpl: use entrySet iterator instead of
    keySet and get.
  - Messages: redundant specification of implements Serializable
  - LatestEntryRoutingLogic: Comparator should also implement Serializable in
    case TreeSet is serialized. This isn't the case here but it doesn't hurt
    to implement Serializable in lieu of supressing the warning.
  - LatestEntryRoutingLogic: Fixed potential null pointer de-reference in
    'compare'.

Change-Id: I8930c8975e1dd9179d78e74087b3994a365b90f8
Signed-off-by: Tom Pantelis <tpanteli@brocade.com>
opendaylight/md-sal/sal-remoterpc-connector/pom.xml
opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RemoteRpcImplementation.java
opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RemoteRpcProviderConfig.java
opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RpcBroker.java
opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/messages/ExecuteRpc.java
opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/messages/RpcResponse.java
opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/RpcRegistry.java
opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/gossip/Gossiper.java
opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/gossip/Messages.java
opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/mbeans/RemoteRpcRegistryMXBeanImpl.java
opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/utils/LatestEntryRoutingLogic.java

index 772d4461f0bc294a5f270dc1eb41c606b6b46615..c8251efdf562cf5f733a88ef61503dd621293a0e 100644 (file)
                 <propertyExpansion>checkstyle.violationSeverity=error</propertyExpansion>
               </configuration>
             </plugin>
+            <plugin>
+              <groupId>org.codehaus.mojo</groupId>
+              <artifactId>findbugs-maven-plugin</artifactId>
+              <configuration>
+                <failOnError>true</failOnError>
+              </configuration>
+            </plugin>
         </plugins>
     </build>
 
index e02c202551010d12505f61f21af07f42e74ccac7..11f145ce1ee02e4f2268186961658ae53a2a926e 100644 (file)
@@ -63,7 +63,7 @@ public class RemoteRpcImplementation implements DOMRpcImplementation {
                     final List<Pair<ActorRef, Long>> routePairs = routes.getRouterWithUpdateTime();
                     if (routePairs == null || routePairs.isEmpty()) {
                         frontEndFuture.failNow(new DOMRpcImplementationNotAvailableException(
-                                "No local or remote implementation available for rpc %s", rpc.getType(), error));
+                                "No local or remote implementation available for rpc %s", rpc.getType()));
                     } else {
                         final ActorRef remoteImplRef = new LatestEntryRoutingLogic(routePairs).select();
                         final Object executeRpcMessage = ExecuteRpc.from(rpc, input);
index 8cdf9c5ef165f1bb256499d6e2de41eba369547f..b08df445595cf65011488eb8c4d1e306a6a1fc60 100644 (file)
@@ -9,6 +9,7 @@ package org.opendaylight.controller.remote.rpc;
 
 import akka.util.Timeout;
 import com.typesafe.config.Config;
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import java.util.concurrent.TimeUnit;
 import org.opendaylight.controller.cluster.common.actor.CommonConfig;
 import scala.concurrent.duration.FiniteDuration;
@@ -82,6 +83,10 @@ public class RemoteRpcProviderConfig extends CommonConfig {
     /**
      * This is called via blueprint xml as the builder pattern can't be used.
      */
+    @SuppressFBWarnings(value = "BC_UNCONFIRMED_CAST_OF_RETURN_VALUE",
+            justification = "Findbugs flags this as an unconfirmed cast of return value but the build method clearly "
+                + "returns RemoteRpcProviderConfig. Perhaps it's confused b/c the build method is overloaded and "
+                + "and differs in return type from the base class.")
     public static RemoteRpcProviderConfig newInstance(String actorSystemName, boolean metricCaptureEnabled,
             int mailboxCapacity) {
         return new Builder(actorSystemName).metricCaptureEnabled(metricCaptureEnabled)
index 964a12bcf84d10a243c57145a14c347239bff887..3d870c99411917e136b2f1cad496dc0c4e9ce01f 100644 (file)
@@ -10,23 +10,17 @@ package org.opendaylight.controller.remote.rpc;
 
 import akka.actor.ActorRef;
 import akka.actor.Props;
-import akka.japi.Creator;
 import com.google.common.base.Preconditions;
 import com.google.common.base.Throwables;
 import com.google.common.util.concurrent.CheckedFuture;
 import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
-import java.util.Arrays;
-import java.util.Collection;
 import org.opendaylight.controller.cluster.common.actor.AbstractUntypedActor;
 import org.opendaylight.controller.md.sal.dom.api.DOMRpcException;
 import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
 import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
 import org.opendaylight.controller.remote.rpc.messages.ExecuteRpc;
 import org.opendaylight.controller.remote.rpc.messages.RpcResponse;
-import org.opendaylight.yangtools.yang.common.RpcError;
-import org.opendaylight.yangtools.yang.common.RpcError.ErrorType;
-import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
 
@@ -43,7 +37,7 @@ public class RpcBroker extends AbstractUntypedActor {
 
     public static Props props(final DOMRpcService rpcService) {
         Preconditions.checkNotNull(rpcService, "DOMRpcService can not be null");
-        return Props.create(new RpcBrokerCreator(rpcService));
+        return Props.create(RpcBroker.class, rpcService);
     }
 
     @Override
@@ -67,14 +61,18 @@ public class RpcBroker extends AbstractUntypedActor {
             Futures.addCallback(future, new FutureCallback<DOMRpcResult>() {
                 @Override
                 public void onSuccess(final DOMRpcResult result) {
-                    if (result.getErrors() != null && !result.getErrors().isEmpty()) {
-                        final String message = String.format("Execution of RPC %s failed", msg.getRpc());
-                        Collection<RpcError> errors = result.getErrors();
-                        if (errors == null || errors.size() == 0) {
-                            errors = Arrays.asList(RpcResultBuilder.newError(ErrorType.RPC, null, message));
-                        }
+                    if (result == null) {
+                        // This shouldn't happen but the FutureCallback annotates the result param with Nullable so
+                        // handle null here to avoid FindBugs warning.
+                        LOG.debug("Got null DOMRpcResult - sending null response for execute rpc : {}", msg.getRpc());
+                        sender.tell(new RpcResponse(null), self);
+                        return;
+                    }
 
-                        sender.tell(new akka.actor.Status.Failure(new RpcErrorsException(message, errors)), self);
+                    if (!result.getErrors().isEmpty()) {
+                        final String message = String.format("Execution of RPC %s failed", msg.getRpc());
+                        sender.tell(new akka.actor.Status.Failure(new RpcErrorsException(message,
+                                result.getErrors())), self);
                     } else {
                         LOG.debug("Sending response for execute rpc : {}", msg.getRpc());
 
@@ -97,19 +95,4 @@ public class RpcBroker extends AbstractUntypedActor {
             sender.tell(new akka.actor.Status.Failure(e), sender);
         }
     }
-
-    private static class RpcBrokerCreator implements Creator<RpcBroker> {
-        private static final long serialVersionUID = 1L;
-
-        final DOMRpcService rpcService;
-
-        RpcBrokerCreator(final DOMRpcService rpcService) {
-            this.rpcService = rpcService;
-        }
-
-        @Override
-        public RpcBroker create() throws Exception {
-            return new RpcBroker(rpcService);
-        }
-    }
 }
index a5300a2722d27cfec820de6557b2bf94455a4edc..4824cd71cc3fe4a2b6324a2b0ae0ce2cd7b238ec 100644 (file)
@@ -10,6 +10,7 @@ package org.opendaylight.controller.remote.rpc.messages;
 
 import com.google.common.base.MoreObjects;
 import com.google.common.base.Preconditions;
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import java.io.Externalizable;
 import java.io.IOException;
 import java.io.ObjectInput;
@@ -25,6 +26,9 @@ import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 public class ExecuteRpc implements Serializable {
     private static final long serialVersionUID = 1128904894827335676L;
 
+    @SuppressFBWarnings(value = "SE_BAD_FIELD", justification = "This field is not Serializable but this class "
+            + "implements writeReplace to delegate serialization to a Proxy class and thus instances of this class "
+            + "aren't serialized. FindBugs does not recognize this.")
     private final NormalizedNode<?, ?> inputNormalizedNode;
     private final QName rpc;
 
index d46bf6ab32ce5e96889482526d37c802d2099002..2d86ac0f2014a29b12d3b9ddfbd05e8ee1c77b2a 100644 (file)
@@ -7,6 +7,7 @@
  */
 package org.opendaylight.controller.remote.rpc.messages;
 
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import java.io.Externalizable;
 import java.io.IOException;
 import java.io.ObjectInput;
@@ -19,6 +20,9 @@ import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 public class RpcResponse implements Serializable {
     private static final long serialVersionUID = -4211279498688989245L;
 
+    @SuppressFBWarnings(value = "SE_BAD_FIELD", justification = "This field is not Serializable but this class "
+            + "implements writeReplace to delegate serialization to a Proxy class and thus instances of this class "
+            + "aren't serialized. FindBugs does not recognize this.")
     private final NormalizedNode<?, ?> resultNormalizedNode;
 
     public RpcResponse(@Nullable final NormalizedNode<?, ?> inputNormalizedNode) {
index 43f5dbcdc0ea8d71d77afec172f4f5328cd66e5d..fc5b618663988d304d6b51468d2da9f99250d7b2 100644 (file)
@@ -10,7 +10,6 @@ package org.opendaylight.controller.remote.rpc.registry;
 import akka.actor.ActorRef;
 import akka.actor.Cancellable;
 import akka.actor.Props;
-import akka.japi.Creator;
 import akka.japi.Option;
 import akka.japi.Pair;
 import com.google.common.base.Preconditions;
@@ -27,7 +26,6 @@ import org.opendaylight.controller.remote.rpc.registry.RpcRegistry.Messages.Remo
 import org.opendaylight.controller.remote.rpc.registry.RpcRegistry.Messages.SetLocalRouter;
 import org.opendaylight.controller.remote.rpc.registry.gossip.Bucket;
 import org.opendaylight.controller.remote.rpc.registry.gossip.BucketStore;
-import org.opendaylight.controller.remote.rpc.registry.mbeans.RemoteRpcRegistryMXBeanImpl;
 import org.opendaylight.controller.sal.connector.api.RpcRouter;
 import org.opendaylight.controller.sal.connector.api.RpcRouter.RouteIdentifier;
 import scala.concurrent.duration.FiniteDuration;
@@ -50,7 +48,7 @@ public class RpcRegistry extends BucketStore<RoutingTable> {
     }
 
     public static Props props(RemoteRpcProviderConfig config) {
-        return Props.create(new RpcRegistryCreator(config));
+        return Props.create(RpcRegistry.class, config);
     }
 
     @Override
@@ -285,20 +283,4 @@ public class RpcRegistry extends BucketStore<RoutingTable> {
             }
         }
     }
-
-    private static class RpcRegistryCreator implements Creator<RpcRegistry> {
-        private static final long serialVersionUID = 1L;
-        private final RemoteRpcProviderConfig config;
-
-        private RpcRegistryCreator(RemoteRpcProviderConfig config) {
-            this.config = config;
-        }
-
-        @Override
-        public RpcRegistry create() throws Exception {
-            RpcRegistry registry =  new RpcRegistry(config);
-            new RemoteRpcRegistryMXBeanImpl(registry);
-            return registry;
-        }
-    }
 }
index 439c131e3f6999fb438d8622e343c85036c55368..d26bda1c25fa481f2cb13a37efc819ada1d550ac 100644 (file)
@@ -390,14 +390,17 @@ public class Gossiper extends AbstractUntypedActorWithMetering {
                     localIsNewer.removeAll(remoteVersions.keySet());
 
 
-                    for (Address address : remoteVersions.keySet()) {
-
-                        if (localVersions.get(address) == null || remoteVersions.get(address) == null) {
+                    for (Map.Entry<Address, Long> entry : remoteVersions.entrySet()) {
+                        Address address = entry.getKey();
+                        Long remoteVersion = entry.getValue();
+                        Long localVersion = localVersions.get(address);
+                        if (localVersion == null || remoteVersion == null) {
                             continue; //this condition is taken care of by above diffs
                         }
-                        if (localVersions.get(address) <  remoteVersions.get(address)) {
+
+                        if (localVersion < remoteVersion) {
                             localIsOlder.add(address);
-                        } else if (localVersions.get(address) > remoteVersions.get(address)) {
+                        } else if (localVersion > remoteVersion) {
                             localIsNewer.add(address);
                         }
                     }
index 99a94e70e9114bc2f6e320240bf75d150034c84a..4f18584399efc8c656ef09499949ee0ce9433bce 100644 (file)
@@ -69,7 +69,7 @@ public class Messages {
             }
         }
 
-        public static class GetAllBucketsReply<T extends Copier<T>> extends ContainsBuckets<T> implements Serializable {
+        public static class GetAllBucketsReply<T extends Copier<T>> extends ContainsBuckets<T> {
             private static final long serialVersionUID = 1L;
 
             public GetAllBucketsReply(Map<Address, Bucket<T>> buckets) {
@@ -77,8 +77,7 @@ public class Messages {
             }
         }
 
-        public static class GetBucketsByMembersReply<T extends Copier<T>> extends ContainsBuckets<T>
-                implements Serializable {
+        public static class GetBucketsByMembersReply<T extends Copier<T>> extends ContainsBuckets<T>  {
             private static final long serialVersionUID = 1L;
 
             public GetBucketsByMembersReply(Map<Address, Bucket<T>> buckets) {
@@ -107,7 +106,7 @@ public class Messages {
 
         }
 
-        public static class GetBucketVersionsReply extends ContainsBucketVersions implements Serializable {
+        public static class GetBucketVersionsReply extends ContainsBucketVersions {
             private static final long serialVersionUID = 1L;
 
             public GetBucketVersionsReply(Map<Address, Long> versions) {
@@ -115,8 +114,7 @@ public class Messages {
             }
         }
 
-        public static class UpdateRemoteBuckets<T extends Copier<T>> extends ContainsBuckets<T>
-                implements Serializable {
+        public static class UpdateRemoteBuckets<T extends Copier<T>> extends ContainsBuckets<T> {
             private static final long serialVersionUID = 1L;
 
             public UpdateRemoteBuckets(Map<Address, Bucket<T>> buckets) {
@@ -134,7 +132,7 @@ public class Messages {
             private static final long serialVersionUID = 5803354404380026143L;
         }
 
-        public static final class GossipStatus extends ContainsBucketVersions implements Serializable {
+        public static final class GossipStatus extends ContainsBucketVersions {
             private static final long serialVersionUID = -593037395143883265L;
 
             private final Address from;
@@ -149,8 +147,7 @@ public class Messages {
             }
         }
 
-        public static final class GossipEnvelope<T extends Copier<T>> extends ContainsBuckets<T>
-                implements Serializable {
+        public static final class GossipEnvelope<T extends Copier<T>> extends ContainsBuckets<T> {
             private static final long serialVersionUID = 8346634072582438818L;
 
             private final Address from;
index c0bdbb8d21d262178459d56522ae719701fbf803..5fbd91cc81c349ad0244ac4b0d96c39f6ab4ebf7 100644 (file)
@@ -12,6 +12,7 @@ import akka.actor.Address;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.Set;
 import org.opendaylight.controller.md.sal.common.util.jmx.AbstractMXBean;
 import org.opendaylight.controller.remote.rpc.registry.RoutingTable;
@@ -81,9 +82,9 @@ public class RemoteRpcRegistryMXBeanImpl extends AbstractMXBean implements Remot
 
         // Get all RPCs from remote bucket
         Map<Address, Bucket<RoutingTable>> buckets = rpcRegistry.getRemoteBuckets();
-        for (Address address : buckets.keySet()) {
-            RoutingTable table = buckets.get(address).getData();
-            rpcMap.putAll(getRpcMemberMapByName(table, name, address.toString()));
+        for (Entry<Address, Bucket<RoutingTable>> entry : buckets.entrySet()) {
+            RoutingTable table = entry.getValue().getData();
+            rpcMap.putAll(getRpcMemberMapByName(table, name, entry.getKey().toString()));
         }
 
         log.debug("list of RPCs {} searched by name {}", rpcMap, name);
@@ -96,10 +97,9 @@ public class RemoteRpcRegistryMXBeanImpl extends AbstractMXBean implements Remot
         Map<String, String> rpcMap = new HashMap<>(getRpcMemberMapByRoute(localTable, routeId, LOCAL_CONSTANT));
 
         Map<Address, Bucket<RoutingTable>> buckets = rpcRegistry.getRemoteBuckets();
-        for (Address address : buckets.keySet()) {
-            RoutingTable table = buckets.get(address).getData();
-            rpcMap.putAll(getRpcMemberMapByRoute(table, routeId, address.toString()));
-
+        for (Entry<Address, Bucket<RoutingTable>> entry : buckets.entrySet()) {
+            RoutingTable table = entry.getValue().getData();
+            rpcMap.putAll(getRpcMemberMapByRoute(table, routeId, entry.getKey().toString()));
         }
 
         log.debug("list of RPCs {} searched by route {}", rpcMap, routeId);
index c0e2973aab53c48e92329d2d96487d277d25531e..f7b36a776e74af78b80b86837be5951b318b20a0 100644 (file)
@@ -11,6 +11,7 @@ package org.opendaylight.controller.remote.rpc.utils;
 import akka.actor.ActorRef;
 import akka.japi.Pair;
 import com.google.common.base.Preconditions;
+import java.io.Serializable;
 import java.util.Collection;
 import java.util.Comparator;
 import java.util.SortedSet;
@@ -36,22 +37,28 @@ public class LatestEntryRoutingLogic implements RoutingLogic {
         return actorRefSet.last().first();
     }
 
-    private class LatestEntryComparator implements Comparator<Pair<ActorRef, Long>> {
+    private static class LatestEntryComparator implements Comparator<Pair<ActorRef, Long>>, Serializable {
+        private static final long serialVersionUID = 1L;
 
         @Override
         public int compare(Pair<ActorRef, Long> o1, Pair<ActorRef, Long> o2) {
             if (o1 == null && o2 == null) {
                 return 0;
             }
-            if (o1 == null && o2 != null) {
+
+            if (o1 != null && o2 != null && o1.second() == null && o2.second() == null) {
+                return 0;
+            }
+
+            if ((o1 == null || o1.second() == null) && o2 != null) {
                 return -1;
             }
-            if (o1 != null && o2 == null) {
+
+            if (o2 == null || o2.second() == null) {
                 return 1;
             }
 
             return o1.second().compareTo(o2.second());
-
         }
     }
 }