[AETHER-1104] Calculate PiPipeconf fingerprint in a deterministic way

New master after taking over a switch was pushing again the pipeline
and all the flows and groups. This was happening because DefaultPiPipeconf
fingerprint was not calculated in a deterministic way across the cluster.

This patch introduces the following changes:
- Implements toString method in each abstraction representing a pipeline
- Hashes the p4Info file to generate a consistent hash of the pipeline model
- Uses a sorted collection to generate a consistent hash of the extensions

Change-Id: I792283b0a9b821284add36b3aba52843f33527c3
diff --git a/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4InfoParser.java b/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4InfoParser.java
index d5bf2e6..7c1fd1a 100644
--- a/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4InfoParser.java
+++ b/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4InfoParser.java
@@ -20,6 +20,8 @@
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Maps;
+import com.google.common.hash.Hashing;
+import com.google.common.hash.HashingInputStream;
 import com.google.protobuf.ExtensionRegistry;
 import com.google.protobuf.TextFormat;
 import org.onosproject.net.pi.model.PiActionId;
@@ -135,6 +137,19 @@
             throw new P4InfoParserException("Unable to parse protobuf " + p4InfoUrl.toString(), e);
         }
 
+        // Generate fingerprint of the pipeline by hashing p4info file
+        final int fingerprint;
+        try {
+            HashingInputStream hin = new HashingInputStream(Hashing.crc32(), p4InfoUrl.openStream());
+            //noinspection StatementWithEmptyBody
+            while (hin.read() != -1) {
+                // Do nothing. Reading all input stream to update hash.
+            }
+            fingerprint = hin.hash().asInt();
+        } catch (IOException e) {
+            throw new P4InfoParserException("Unable to generate fingerprint " + p4InfoUrl.toString(), e);
+        }
+
         // Start by parsing and mapping instances to to their integer P4Info IDs.
         // Convenient to build the table model at the end.
 
@@ -243,7 +258,8 @@
                 meterImmMap,
                 registerImmMap,
                 actProfileImmMap,
-                ImmutableMap.copyOf(pktOpMap));
+                ImmutableMap.copyOf(pktOpMap),
+                fingerprint);
     }