Separate lazy-versioned NormalizedNodeDataInput 78/82278/6
authorRobert Varga <robert.varga@pantheon.tech>
Tue, 28 May 2019 13:28:55 +0000 (15:28 +0200)
committerRobert Varga <robert.varga@pantheon.tech>
Wed, 29 May 2019 17:51:17 +0000 (19:51 +0200)
NormalizedNodeInputStreamReader is really only one implementation
of the streaming format, which happens to be bound to LITHIUM_VERSION.

This effectively means NormalizedNodeInputOutput can give out either
a version-bound reader or an unbound reader -- which we facilitate by
creating VersionedNormalizedNodeDataInput which is a simple forwarder
with lazily-initialized delegate.

Since this increases the number of (NormalizedNode)DataInput
implementations, we share as much code as possible through the use
of forwarding implementations.

JIRA: CONTROLLER-1898
Change-Id: I28713346730ed5bf7f912bf8afa5d8722b202035
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/ForwardingDataInput.java [new file with mode: 0644]
opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/ForwardingNormalizedNodeDataInput.java [new file with mode: 0644]
opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/InvalidNormalizedNodeStreamException.java
opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/NormalizedNodeInputOutput.java
opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/NormalizedNodeInputStreamReader.java
opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/VersionedNormalizedNodeDataInput.java [new file with mode: 0644]

diff --git a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/ForwardingDataInput.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/ForwardingDataInput.java
new file mode 100644 (file)
index 0000000..0ec7fbe
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2019 PANTHEON.tech, s.r.o. and others.  All rights reserved.
+ *
+ * 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.controller.cluster.datastore.node.utils.stream;
+
+import java.io.DataInput;
+import java.io.IOException;
+import org.eclipse.jdt.annotation.NonNull;
+
+// Not a ForwardingObject because delegate() can legally throw and we do not want redirect toString()
+abstract class ForwardingDataInput implements DataInput {
+
+    abstract @NonNull DataInput delegate() throws IOException;
+
+    @Override
+    @SuppressWarnings("checkstyle:parameterName")
+    public final void readFully(final byte[] b) throws IOException {
+        delegate().readFully(b);
+    }
+
+    @Override
+    @SuppressWarnings("checkstyle:parameterName")
+    public final void readFully(final byte[] b, final int off, final int len) throws IOException {
+        delegate().readFully(b, off, len);
+    }
+
+    @Override
+    @SuppressWarnings("checkstyle:parameterName")
+    public final int skipBytes(final int n) throws IOException {
+        return delegate().skipBytes(n);
+    }
+
+    @Override
+    public final boolean readBoolean() throws IOException {
+        return delegate().readBoolean();
+    }
+
+    @Override
+    public final byte readByte() throws IOException {
+        return delegate().readByte();
+    }
+
+    @Override
+    public final int readUnsignedByte() throws IOException {
+        return delegate().readUnsignedByte();
+    }
+
+    @Override
+    public final short readShort() throws IOException {
+        return delegate().readShort();
+    }
+
+    @Override
+    public final int readUnsignedShort() throws IOException {
+        return delegate().readUnsignedShort();
+    }
+
+    @Override
+    public final char readChar() throws IOException {
+        return delegate().readChar();
+    }
+
+    @Override
+    public final int readInt() throws IOException {
+        return delegate().readInt();
+    }
+
+    @Override
+    public final long readLong() throws IOException {
+        return delegate().readLong();
+    }
+
+    @Override
+    public final float readFloat() throws IOException {
+        return delegate().readFloat();
+    }
+
+    @Override
+    public final double readDouble() throws IOException {
+        return delegate().readDouble();
+    }
+
+    @Override
+    public final String readLine() throws IOException {
+        return delegate().readLine();
+    }
+
+    @Override
+    public final String readUTF() throws IOException {
+        return delegate().readUTF();
+    }
+}
diff --git a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/ForwardingNormalizedNodeDataInput.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/ForwardingNormalizedNodeDataInput.java
new file mode 100644 (file)
index 0000000..590a8b0
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2019 PANTHEON.tech, s.r.o. and others.  All rights reserved.
+ *
+ * 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.controller.cluster.datastore.node.utils.stream;
+
+import java.io.IOException;
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+
+abstract class ForwardingNormalizedNodeDataInput extends ForwardingDataInput implements NormalizedNodeDataInput {
+
+    @Override
+    abstract @NonNull NormalizedNodeDataInput delegate() throws IOException;
+
+    @Override
+    public final NormalizedNode<?, ?> readNormalizedNode() throws IOException {
+        return delegate().readNormalizedNode();
+    }
+
+    @Override
+    public final YangInstanceIdentifier readYangInstanceIdentifier() throws IOException {
+        return delegate().readYangInstanceIdentifier();
+    }
+
+    @Override
+    public final PathArgument readPathArgument() throws IOException {
+        return delegate().readPathArgument();
+    }
+
+    @Override
+    public final SchemaPath readSchemaPath() throws IOException {
+        return delegate().readSchemaPath();
+    }
+}
index da60496a22796113932a9e8c8231322c0c3cde48..2099e3d5a6909a9ba761a25dabf5f1e78edaa05f 100644 (file)
@@ -18,7 +18,11 @@ import java.io.IOException;
 public class InvalidNormalizedNodeStreamException extends IOException {
     private static final long serialVersionUID = 1L;
 
-    public InvalidNormalizedNodeStreamException(String message) {
+    public InvalidNormalizedNodeStreamException(final String message) {
         super(message);
     }
+
+    public InvalidNormalizedNodeStreamException(final String message, final Throwable cause) {
+        super(message, cause);
+    }
 }
index 5ad195a9b7cd207842a859ef6b78d139dc6f76f1..f46a9e2a5b13e6a312a6663f53157121b74bd730 100644 (file)
@@ -28,18 +28,7 @@ public final class NormalizedNodeInputOutput {
      * @throws IOException if an error occurs reading from the input
      */
     public static NormalizedNodeDataInput newDataInput(final @NonNull DataInput input) throws IOException {
-        final byte marker = input.readByte();
-        if (marker != TokenTypes.SIGNATURE_MARKER) {
-            throw new InvalidNormalizedNodeStreamException(String.format("Invalid signature marker: %d", marker));
-        }
-
-        final short version = input.readShort();
-        switch (version) {
-            case TokenTypes.LITHIUM_VERSION:
-                return new NormalizedNodeInputStreamReader(input, true);
-            default:
-                throw new InvalidNormalizedNodeStreamException(String.format("Unhandled stream version %s", version));
-        }
+        return new VersionedNormalizedNodeDataInput(input).delegate();
     }
 
     /**
@@ -50,7 +39,7 @@ public final class NormalizedNodeInputOutput {
      * @return a new {@link NormalizedNodeDataInput} instance
      */
     public static NormalizedNodeDataInput newDataInputWithoutValidation(final @NonNull DataInput input) {
-        return new NormalizedNodeInputStreamReader(input, false);
+        return new VersionedNormalizedNodeDataInput(input);
     }
 
     /**
index 9b2ce2b64d4fab9d71e5ac844983008ad8b85979..239cd7cb57f703d9c6ef7795fc74fc72a889497b 100755 (executable)
@@ -25,6 +25,7 @@ import java.util.Set;
 import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.parsers.ParserConfigurationException;
 import javax.xml.transform.dom.DOMSource;
+import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.controller.cluster.datastore.node.utils.QNameFactory;
 import org.opendaylight.yangtools.util.ImmutableOffsetMapTemplate;
 import org.opendaylight.yangtools.yang.common.Empty;
@@ -54,11 +55,11 @@ import org.xml.sax.SAXException;
  * nodes. This process goes in recursive manner, where each NodeTypes object signifies the start of the object, except
  * END_NODE. If a node can have children, then that node's end is calculated based on appearance of END_NODE.
  */
-public class NormalizedNodeInputStreamReader implements NormalizedNodeDataInput {
+public class NormalizedNodeInputStreamReader extends ForwardingDataInput implements NormalizedNodeDataInput {
 
     private static final Logger LOG = LoggerFactory.getLogger(NormalizedNodeInputStreamReader.class);
 
-    private final DataInput input;
+    private final @NonNull DataInput input;
 
     private final List<String> codedStringMap = new ArrayList<>();
 
@@ -69,34 +70,18 @@ public class NormalizedNodeInputStreamReader implements NormalizedNodeDataInput
     @SuppressWarnings("rawtypes")
     private NormalizedNodeBuilder<NodeWithValue, Object, LeafSetEntryNode<Object>> leafSetEntryBuilder;
 
-    private boolean readSignatureMarker = true;
-
-    NormalizedNodeInputStreamReader(final DataInput input, final boolean versionChecked) {
+    NormalizedNodeInputStreamReader(final DataInput input) {
         this.input = requireNonNull(input);
-        readSignatureMarker = !versionChecked;
     }
 
     @Override
-    public NormalizedNode<?, ?> readNormalizedNode() throws IOException {
-        readSignatureMarkerAndVersionIfNeeded();
-        return readNormalizedNodeInternal();
+    final DataInput delegate() {
+        return input;
     }
 
-    private void readSignatureMarkerAndVersionIfNeeded() throws IOException {
-        if (readSignatureMarker) {
-            readSignatureMarker = false;
-
-            final byte marker = input.readByte();
-            if (marker != TokenTypes.SIGNATURE_MARKER) {
-                throw new InvalidNormalizedNodeStreamException(String.format(
-                        "Invalid signature marker: %d", marker));
-            }
-
-            final short version = input.readShort();
-            if (version != TokenTypes.LITHIUM_VERSION) {
-                throw new InvalidNormalizedNodeStreamException(String.format("Unhandled stream version %s", version));
-            }
-        }
+    @Override
+    public NormalizedNode<?, ?> readNormalizedNode() throws IOException {
+        return readNormalizedNodeInternal();
     }
 
     private NormalizedNode<?, ?> readNormalizedNodeInternal() throws IOException {
@@ -356,8 +341,6 @@ public class NormalizedNodeInputStreamReader implements NormalizedNodeDataInput
 
     @Override
     public SchemaPath readSchemaPath() throws IOException {
-        readSignatureMarkerAndVersionIfNeeded();
-
         final boolean absolute = input.readBoolean();
         final int size = input.readInt();
 
@@ -370,7 +353,6 @@ public class NormalizedNodeInputStreamReader implements NormalizedNodeDataInput
 
     @Override
     public YangInstanceIdentifier readYangInstanceIdentifier() throws IOException {
-        readSignatureMarkerAndVersionIfNeeded();
         return readYangInstanceIdentifierInternal();
     }
 
@@ -442,94 +424,4 @@ public class NormalizedNodeInputStreamReader implements NormalizedNodeDataInput
         }
         return builder;
     }
-
-    @Override
-    public void readFully(final byte[] value) throws IOException {
-        readSignatureMarkerAndVersionIfNeeded();
-        input.readFully(value);
-    }
-
-    @Override
-    public void readFully(final byte[] str, final int off, final int len) throws IOException {
-        readSignatureMarkerAndVersionIfNeeded();
-        input.readFully(str, off, len);
-    }
-
-    @Override
-    public int skipBytes(final int num) throws IOException {
-        readSignatureMarkerAndVersionIfNeeded();
-        return input.skipBytes(num);
-    }
-
-    @Override
-    public boolean readBoolean() throws IOException {
-        readSignatureMarkerAndVersionIfNeeded();
-        return input.readBoolean();
-    }
-
-    @Override
-    public byte readByte() throws IOException {
-        readSignatureMarkerAndVersionIfNeeded();
-        return input.readByte();
-    }
-
-    @Override
-    public int readUnsignedByte() throws IOException {
-        readSignatureMarkerAndVersionIfNeeded();
-        return input.readUnsignedByte();
-    }
-
-    @Override
-    public short readShort() throws IOException {
-        readSignatureMarkerAndVersionIfNeeded();
-        return input.readShort();
-    }
-
-    @Override
-    public int readUnsignedShort() throws IOException {
-        readSignatureMarkerAndVersionIfNeeded();
-        return input.readUnsignedShort();
-    }
-
-    @Override
-    public char readChar() throws IOException {
-        readSignatureMarkerAndVersionIfNeeded();
-        return input.readChar();
-    }
-
-    @Override
-    public int readInt() throws IOException {
-        readSignatureMarkerAndVersionIfNeeded();
-        return input.readInt();
-    }
-
-    @Override
-    public long readLong() throws IOException {
-        readSignatureMarkerAndVersionIfNeeded();
-        return input.readLong();
-    }
-
-    @Override
-    public float readFloat() throws IOException {
-        readSignatureMarkerAndVersionIfNeeded();
-        return input.readFloat();
-    }
-
-    @Override
-    public double readDouble() throws IOException {
-        readSignatureMarkerAndVersionIfNeeded();
-        return input.readDouble();
-    }
-
-    @Override
-    public String readLine() throws IOException {
-        readSignatureMarkerAndVersionIfNeeded();
-        return input.readLine();
-    }
-
-    @Override
-    public String readUTF() throws IOException {
-        readSignatureMarkerAndVersionIfNeeded();
-        return input.readUTF();
-    }
 }
diff --git a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/VersionedNormalizedNodeDataInput.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/stream/VersionedNormalizedNodeDataInput.java
new file mode 100644 (file)
index 0000000..860fe39
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2019 PANTHEON.tech, s.r.o. and others.  All rights reserved.
+ *
+ * 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.controller.cluster.datastore.node.utils.stream;
+
+import static java.util.Objects.requireNonNull;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+final class VersionedNormalizedNodeDataInput extends ForwardingNormalizedNodeDataInput {
+    private DataInput input;
+    private NormalizedNodeDataInput delegate;
+
+    VersionedNormalizedNodeDataInput(final DataInput input) {
+        this.input = requireNonNull(input);
+    }
+
+    @Override
+    NormalizedNodeDataInput delegate() throws IOException {
+        if (delegate != null) {
+            return delegate;
+        }
+
+        final byte marker = input.readByte();
+        if (marker != TokenTypes.SIGNATURE_MARKER) {
+            throw defunct("Invalid signature marker: %d", marker);
+        }
+
+        final short version = input.readShort();
+        final NormalizedNodeDataInput ret;
+        switch (version) {
+            case TokenTypes.LITHIUM_VERSION:
+                ret = new NormalizedNodeInputStreamReader(input);
+                break;
+            default:
+                throw defunct("Unhandled stream version %s", version);
+        }
+
+        setDelegate(ret);
+        return ret;
+    }
+
+    private InvalidNormalizedNodeStreamException defunct(final String format, final Object... args) {
+        final InvalidNormalizedNodeStreamException ret = new InvalidNormalizedNodeStreamException(
+            String.format(format, args));
+        // Make sure the stream is not touched
+        setDelegate(new ForwardingNormalizedNodeDataInput() {
+            @Override
+            NormalizedNodeDataInput delegate() throws IOException {
+                throw new InvalidNormalizedNodeStreamException("Stream is not usable", ret);
+            }
+        });
+        return ret;
+    }
+
+    private void setDelegate(final NormalizedNodeDataInput delegate) {
+        this.delegate = requireNonNull(delegate);
+        input = null;
+    }
+}