[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/core/api/src/main/java/org/onosproject/net/pi/model/DefaultPiPipeconf.java b/core/api/src/main/java/org/onosproject/net/pi/model/DefaultPiPipeconf.java
index 464bdd7..2041cdb 100644
--- a/core/api/src/main/java/org/onosproject/net/pi/model/DefaultPiPipeconf.java
+++ b/core/api/src/main/java/org/onosproject/net/pi/model/DefaultPiPipeconf.java
@@ -192,21 +192,25 @@
             Map<Class<? extends Behaviour>, Class<? extends Behaviour>> behaviours =
                     behaviourMapBuilder.build();
             return new DefaultPiPipeconf(
-                    id, pipelineModel, generateFingerprint(extensions.values()),
+                    id, pipelineModel, generateFingerprint(extensions),
                     behaviours, extensions);
         }
 
-        private long generateFingerprint(Collection<URL> extensions) {
+        private long generateFingerprint(Map<ExtensionType, URL> extensions) {
             Collection<Integer> hashes = new ArrayList<>();
-            for (URL extUrl : extensions) {
+            for (ExtensionType extensionType : ExtensionType.values()) {
                 try {
-                    HashingInputStream hin = new HashingInputStream(
-                            Hashing.crc32(), extUrl.openStream());
-                    //noinspection StatementWithEmptyBody
-                    while (hin.read() != -1) {
-                        // Do nothing. Reading all input stream to update hash.
+                    // Get the extension if present and then hash the content
+                    URL extUrl = extensions.get(extensionType);
+                    if (extUrl != null) {
+                        HashingInputStream hin = new HashingInputStream(
+                                Hashing.crc32(), extUrl.openStream());
+                        //noinspection StatementWithEmptyBody
+                        while (hin.read() != -1) {
+                            // Do nothing. Reading all input stream to update hash.
+                        }
+                        hashes.add(hin.hash().asInt());
                     }
-                    hashes.add(hin.hash().asInt());
                 } catch (IOException e) {
                     throw new IllegalArgumentException(e);
                 }