Bug 7521: Convert byte[] to ShardManagerSnapshot in DatastoreSnapshot
[controller.git] / opendaylight / md-sal / sal-distributed-datastore / src / main / java / org / opendaylight / controller / cluster / datastore / persisted / DatastoreSnapshot.java
index 3c5e86b21d6abfb49bcbd7d331de73aeba9ded8d..fec44082ecdfee199f532dbf9bdee0be1d2c285c 100644 (file)
@@ -9,11 +9,16 @@ package org.opendaylight.controller.cluster.datastore.persisted;
 
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
 import java.io.Serializable;
+import java.util.ArrayList;
 import java.util.List;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
+import org.opendaylight.controller.cluster.raft.persisted.Snapshot;
 
 /**
  * Stores a snapshot of the internal state of a data store.
@@ -23,14 +28,57 @@ import javax.annotation.Nullable;
 public class DatastoreSnapshot implements Serializable {
     private static final long serialVersionUID = 1L;
 
+    private static final class Proxy implements Externalizable {
+        private static final long serialVersionUID = 1L;
+
+        private DatastoreSnapshot datastoreSnapshot;
+
+        // checkstyle flags the public modifier as redundant which really doesn't make sense since it clearly isn't
+        // redundant. It is explicitly needed for Java serialization to be able to create instances via reflection.
+        @SuppressWarnings("checkstyle:RedundantModifier")
+        public Proxy() {
+            // For Externalizable
+        }
+
+        Proxy(final DatastoreSnapshot datastoreSnapshot) {
+            this.datastoreSnapshot = datastoreSnapshot;
+        }
+
+        @Override
+        public void writeExternal(ObjectOutput out) throws IOException {
+            out.writeObject(datastoreSnapshot.type);
+            out.writeObject(datastoreSnapshot.shardManagerSnapshot);
+
+            out.writeInt(datastoreSnapshot.shardSnapshots.size());
+            for (ShardSnapshot shardSnapshot: datastoreSnapshot.shardSnapshots) {
+                out.writeObject(shardSnapshot);
+            }
+        }
+
+        @Override
+        public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
+            String type = (String)in.readObject();
+            ShardManagerSnapshot shardManagerSnapshot = (ShardManagerSnapshot) in.readObject();
+
+            int size = in.readInt();
+            List<ShardSnapshot> shardSnapshots = new ArrayList<>(size);
+            for (int i = 0; i < size; i++) {
+                shardSnapshots.add((ShardSnapshot) in.readObject());
+            }
+
+            datastoreSnapshot = new DatastoreSnapshot(type, shardManagerSnapshot, shardSnapshots);
+        }
+
+        private Object readResolve() {
+            return datastoreSnapshot;
+        }
+    }
+
     private final String type;
-    private final byte[] shardManagerSnapshot;
+    private final ShardManagerSnapshot shardManagerSnapshot;
     private final List<ShardSnapshot> shardSnapshots;
 
-    @SuppressFBWarnings(value = "EI_EXPOSE_REP2", justification = "Stores a reference to an externally mutable byte[] "
-            + "object but this is OK since this class is merely a DTO and does not process byte[] internally. "
-            + "Also it would be inefficient to create a return copy as the byte[] could be large.")
-    public DatastoreSnapshot(@Nonnull String type, @Nullable byte[] shardManagerSnapshot,
+    public DatastoreSnapshot(@Nonnull String type, @Nullable ShardManagerSnapshot shardManagerSnapshot,
             @Nonnull List<ShardSnapshot> shardSnapshots) {
         this.type = Preconditions.checkNotNull(type);
         this.shardManagerSnapshot = shardManagerSnapshot;
@@ -42,11 +90,8 @@ public class DatastoreSnapshot implements Serializable {
         return type;
     }
 
-    @SuppressFBWarnings(value = "EI_EXPOSE_REP", justification = "Exposes a mutable object stored in a field but "
-            + "this is OK since this class is merely a DTO and does not process byte[] internally. "
-            + "Also it would be inefficient to create a return copy as the byte[] could be large.")
     @Nullable
-    public byte[] getShardManagerSnapshot() {
+    public ShardManagerSnapshot getShardManagerSnapshot() {
         return shardManagerSnapshot;
     }
 
@@ -55,13 +100,50 @@ public class DatastoreSnapshot implements Serializable {
         return shardSnapshots;
     }
 
+    @SuppressWarnings("static-method")
+    private Object writeReplace() {
+        return new Proxy(this);
+    }
+
     public static class ShardSnapshot implements Serializable {
         private static final long serialVersionUID = 1L;
 
+        private static final class Proxy implements Externalizable {
+            private static final long serialVersionUID = 1L;
+
+            private ShardSnapshot shardSnapshot;
+
+            // checkstyle flags the public modifier as redundant which really doesn't make sense since it clearly isn't
+            // redundant. It is explicitly needed for Java serialization to be able to create instances via reflection.
+            @SuppressWarnings("checkstyle:RedundantModifier")
+            public Proxy() {
+                // For Externalizable
+            }
+
+            Proxy(final ShardSnapshot shardSnapshot) {
+                this.shardSnapshot = shardSnapshot;
+            }
+
+            @Override
+            public void writeExternal(ObjectOutput out) throws IOException {
+                out.writeObject(shardSnapshot.name);
+                out.writeObject(shardSnapshot.snapshot);
+            }
+
+            @Override
+            public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
+                shardSnapshot = new ShardSnapshot((String)in.readObject(), (Snapshot) in.readObject());
+            }
+
+            private Object readResolve() {
+                return shardSnapshot;
+            }
+        }
+
         private final String name;
-        private final byte[] snapshot;
+        private final Snapshot snapshot;
 
-        public ShardSnapshot(@Nonnull String name, @Nonnull byte[] snapshot) {
+        public ShardSnapshot(@Nonnull String name, @Nonnull Snapshot snapshot) {
             this.name = Preconditions.checkNotNull(name);
             this.snapshot = Preconditions.checkNotNull(snapshot);
         }
@@ -71,12 +153,14 @@ public class DatastoreSnapshot implements Serializable {
             return name;
         }
 
-        @SuppressFBWarnings(value = "EI_EXPOSE_REP", justification = "Exposes a mutable object stored in a field but "
-                + "this is OK since this class is merely a DTO and does not process byte[] internally. "
-                + "Also it would be inefficient to create a return copy as the byte[] could be large.")
         @Nonnull
-        public byte[] getSnapshot() {
+        public Snapshot getSnapshot() {
             return snapshot;
         }
+
+        @SuppressWarnings("static-method")
+        private Object writeReplace() {
+            return new Proxy(this);
+        }
     }
 }