From b19f8de136ff795078b3515af22fe5634d61d82c Mon Sep 17 00:00:00 2001 From: Robert Varga Date: Sun, 22 May 2016 13:35:40 +0200 Subject: [PATCH] BUG-5930: introduce ABIVersion This patch introduces the concept of ABI version in the client API. The concept will serve to guide frontend/backend interactions so that version negotiation cal ne implemented and messages are sent using a compatible serialization format. Change-Id: I90f9fa70c745c62350960ce151cd116e14b5208a Signed-off-by: Robert Varga --- .../controller/cluster/access/ABIVersion.java | 117 ++++++++++++++++++ .../access/AbstractVersionException.java | 49 ++++++++ .../access/FutureVersionException.java | 25 ++++ .../cluster/access/PastVersionException.java | 25 ++++ .../cluster/access/package-info.java | 13 ++ .../cluster/access/ABIVersionTest.java | 55 ++++++++ 6 files changed, 284 insertions(+) create mode 100644 opendaylight/md-sal/cds-access-api/src/main/java/org/opendaylight/controller/cluster/access/ABIVersion.java create mode 100644 opendaylight/md-sal/cds-access-api/src/main/java/org/opendaylight/controller/cluster/access/AbstractVersionException.java create mode 100644 opendaylight/md-sal/cds-access-api/src/main/java/org/opendaylight/controller/cluster/access/FutureVersionException.java create mode 100644 opendaylight/md-sal/cds-access-api/src/main/java/org/opendaylight/controller/cluster/access/PastVersionException.java create mode 100644 opendaylight/md-sal/cds-access-api/src/main/java/org/opendaylight/controller/cluster/access/package-info.java create mode 100644 opendaylight/md-sal/cds-access-api/src/test/java/org/opendaylight/controller/cluster/access/ABIVersionTest.java diff --git a/opendaylight/md-sal/cds-access-api/src/main/java/org/opendaylight/controller/cluster/access/ABIVersion.java b/opendaylight/md-sal/cds-access-api/src/main/java/org/opendaylight/controller/cluster/access/ABIVersion.java new file mode 100644 index 0000000000..c25c156a27 --- /dev/null +++ b/opendaylight/md-sal/cds-access-api/src/main/java/org/opendaylight/controller/cluster/access/ABIVersion.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2016 Cisco Systems, Inc. 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.access; + +import com.google.common.annotations.Beta; +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Preconditions; +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.concepts.WritableObject; + +/** + * Enumeration of all ABI versions supported by this implementation of the client access API. + * + * @author Robert Varga + */ +@Beta +public enum ABIVersion implements WritableObject { + // NOTE: enumeration values need to be sorted in asceding order of their version to keep Comparable working + + /** + * Version which is older than any other version. This version exists purely for testing purposes. + */ + @VisibleForTesting + TEST_PAST_VERSION(0), + + /** + * Initial ABI version, as shipped with Boron Simultaneous release. + */ + // We seed the initial version to be the same as DataStoreVersions.BORON-VERSION for compatibility reasons. + BORON(5), + + /** + * Version which is newer than any other version. This version exists purely for testing purposes. + */ + @VisibleForTesting + TEST_FUTURE_VERSION(65535); + + private final short value; + + ABIVersion(final int intVersion) { + Preconditions.checkArgument(intVersion >= 0 && intVersion <= 65535); + value = (short) intVersion; + } + + /** + * Return the unsigned short integer identifying this version. + * + * @return Unsigned short integer identifying this version + */ + public short shortValue() { + return value; + } + + /** + * Return the codebase-native ABI version. This version is the default version allocated to messages at runtime. + * Conversion to previous versions may incur additional overhead (such as object allocation). + * + * @return Current {@link ABIVersion} + */ + public static @Nonnull ABIVersion current() { + return BORON; + } + + /** + * Return the {@link ABIVersion} corresponding to an unsigned short integer. This method is provided for callers + * which provide their own recovery strategy in case of version incompatibility. + * + * @param s Short integer as returned from {@link #shortValue()} + * @return {@link ABIVersion} + * @throws FutureVersionException if the specified integer identifies a future version + * @throws PastVersionException if the specified integer identifies a past version which is no longer supported + */ + public static @Nonnull ABIVersion valueOf(final short s) throws FutureVersionException, PastVersionException { + switch (Short.toUnsignedInt(s)) { + case 0: + case 1: + case 2: + case 3: + case 4: + throw new PastVersionException(s, BORON); + case 5: + return BORON; + default: + throw new FutureVersionException(s, BORON); + } + } + + @Override + public void writeTo(final DataOutput out) throws IOException { + out.writeShort(value); + } + + /** + * Read an {@link ABIVersion} from a {@link DataInput}. This method is provided for callers which do not have + * a recovery strategy for dealing with unsupported versions. + * + * @param in Input from which to read + * @return An {@link ABIVersion} + * @throws IOException If read fails or an unsupported version is encountered + */ + public static @Nonnull ABIVersion readFrom(final @Nonnull DataInput in) throws IOException { + final short s = in.readShort(); + try { + return valueOf(s); + } catch (FutureVersionException | PastVersionException e) { + throw new IOException("Unsupported version", e); + } + } +} diff --git a/opendaylight/md-sal/cds-access-api/src/main/java/org/opendaylight/controller/cluster/access/AbstractVersionException.java b/opendaylight/md-sal/cds-access-api/src/main/java/org/opendaylight/controller/cluster/access/AbstractVersionException.java new file mode 100644 index 0000000000..11a27950f7 --- /dev/null +++ b/opendaylight/md-sal/cds-access-api/src/main/java/org/opendaylight/controller/cluster/access/AbstractVersionException.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2016 Cisco Systems, Inc. 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.access; + +import com.google.common.annotations.Beta; +import com.google.common.base.Preconditions; +import javax.annotation.Nonnull; + +/** + * Abstract base exception used for reporting version mismatches from {@link ABIVersion}. + * + * @author Robert Varga + */ +@Beta +public abstract class AbstractVersionException extends Exception { + private static final long serialVersionUID = 1L; + private final ABIVersion closestVersion; + private final int version; + + AbstractVersionException(final String message, final short version, final ABIVersion closestVersion) { + super(message); + this.closestVersion = Preconditions.checkNotNull(closestVersion); + this.version = Short.toUnsignedInt(version); + } + + /** + * Return the numeric version which has caused this exception. + * + * @return Numeric version + */ + public final int getVersion() { + return version; + } + + /** + * Return the closest version supported by this codebase. + * + * @return Closest supported {@link ABIVersion} + */ + public final @Nonnull ABIVersion getClosestVersion() { + return closestVersion; + } + +} diff --git a/opendaylight/md-sal/cds-access-api/src/main/java/org/opendaylight/controller/cluster/access/FutureVersionException.java b/opendaylight/md-sal/cds-access-api/src/main/java/org/opendaylight/controller/cluster/access/FutureVersionException.java new file mode 100644 index 0000000000..d5f132a7b8 --- /dev/null +++ b/opendaylight/md-sal/cds-access-api/src/main/java/org/opendaylight/controller/cluster/access/FutureVersionException.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2016 Cisco Systems, Inc. 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.access; + +import com.google.common.annotations.Beta; + +/** + * Exception thrown from {@link ABIVersion#valueOf(short)} when the specified version is too new to be supported + * by the codebase. + * + * @author Robert Varga + */ +@Beta +public final class FutureVersionException extends AbstractVersionException { + private static final long serialVersionUID = 1L; + + FutureVersionException(final short version, ABIVersion closest) { + super("Version " + Short.toUnsignedInt(version) + " is too new", version, closest); + } +} diff --git a/opendaylight/md-sal/cds-access-api/src/main/java/org/opendaylight/controller/cluster/access/PastVersionException.java b/opendaylight/md-sal/cds-access-api/src/main/java/org/opendaylight/controller/cluster/access/PastVersionException.java new file mode 100644 index 0000000000..c8cbe54b3d --- /dev/null +++ b/opendaylight/md-sal/cds-access-api/src/main/java/org/opendaylight/controller/cluster/access/PastVersionException.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2016 Cisco Systems, Inc. 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.access; + +import com.google.common.annotations.Beta; + +/** + * Exception thrown from {@link ABIVersion#valueOf(short)} when the specified version is too old and no longer + * supported by the codebase. + * + * @author Robert Varga + */ +@Beta +public final class PastVersionException extends AbstractVersionException { + private static final long serialVersionUID = 1L; + + PastVersionException(final short version, final ABIVersion closest) { + super("Version " + Short.toUnsignedInt(version) + " is too old", version, closest); + } +} diff --git a/opendaylight/md-sal/cds-access-api/src/main/java/org/opendaylight/controller/cluster/access/package-info.java b/opendaylight/md-sal/cds-access-api/src/main/java/org/opendaylight/controller/cluster/access/package-info.java new file mode 100644 index 0000000000..e3b0fbcc77 --- /dev/null +++ b/opendaylight/md-sal/cds-access-api/src/main/java/org/opendaylight/controller/cluster/access/package-info.java @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2016 Cisco Systems, Inc. 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 + */ +/** + * This package contains the base definitions of the APIs exposed by the clustered data store backend. + * + * @author Robert Varga + */ +package org.opendaylight.controller.cluster.access; \ No newline at end of file diff --git a/opendaylight/md-sal/cds-access-api/src/test/java/org/opendaylight/controller/cluster/access/ABIVersionTest.java b/opendaylight/md-sal/cds-access-api/src/test/java/org/opendaylight/controller/cluster/access/ABIVersionTest.java new file mode 100644 index 0000000000..6866136496 --- /dev/null +++ b/opendaylight/md-sal/cds-access-api/src/test/java/org/opendaylight/controller/cluster/access/ABIVersionTest.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2016 Cisco Systems, Inc. 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.access; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.opendaylight.controller.cluster.access.ABIVersion.BORON; +import static org.opendaylight.controller.cluster.access.ABIVersion.TEST_FUTURE_VERSION; +import static org.opendaylight.controller.cluster.access.ABIVersion.TEST_PAST_VERSION; +import com.google.common.io.ByteArrayDataOutput; +import com.google.common.io.ByteStreams; +import java.io.IOException; +import org.junit.Test; + +public class ABIVersionTest { + @Test + public void testInvalidVersions() { + assertTrue(TEST_PAST_VERSION.compareTo(TEST_FUTURE_VERSION) < 0); + assertTrue(TEST_PAST_VERSION.compareTo(BORON) < 0); + assertTrue(TEST_FUTURE_VERSION.compareTo(BORON) > 0); + } + + @Test + public void testBoronVersion() throws Exception { + assertEquals((short)5, BORON.shortValue()); + assertEquals(BORON, ABIVersion.valueOf(BORON.shortValue())); + assertEquals(BORON, ABIVersion.readFrom(ByteStreams.newDataInput(writeVersion(BORON)))); + } + + @Test(expected=PastVersionException.class) + public void testInvalidPastVersion() throws Exception { + ABIVersion.valueOf(TEST_PAST_VERSION.shortValue()); + } + + @Test(expected=FutureVersionException.class) + public void testInvalidFutureVersion() throws Exception { + ABIVersion.valueOf(TEST_FUTURE_VERSION.shortValue()); + } + + private static byte[] writeVersion(final ABIVersion version) { + final ByteArrayDataOutput bado = ByteStreams.newDataOutput(); + bado.writeShort(version.shortValue()); + return bado.toByteArray(); + } + + @Test(expected=IOException.class) + public void testBadRead() throws IOException { + ABIVersion.readFrom(ByteStreams.newDataInput(writeVersion(TEST_PAST_VERSION))); + } +} -- 2.36.6