BUG-5280: add client connect messages 66/42866/7
authorRobert Varga <rovarga@cisco.com>
Sun, 31 Jul 2016 21:55:28 +0000 (23:55 +0200)
committerTom Pantelis <tpanteli@brocade.com>
Wed, 3 Aug 2016 11:47:18 +0000 (11:47 +0000)
When a frontend is attempting to re-establish communication
with the backend it sends its coordinates and various other
information to a backend.

Sending ConnectClientRequest initiates a handshake, to which
the backend will respond either with a failure, or with an
adjusted ConnectClientSuccess.

Change-Id: I58ba9a2103f80e528654222f82f07416f7d7815e
Signed-off-by: Robert Varga <rovarga@cisco.com>
opendaylight/md-sal/cds-access-api/src/main/java/org/opendaylight/controller/cluster/access/ABIVersion.java
opendaylight/md-sal/cds-access-api/src/main/java/org/opendaylight/controller/cluster/access/commands/ConnectClientFailure.java [new file with mode: 0644]
opendaylight/md-sal/cds-access-api/src/main/java/org/opendaylight/controller/cluster/access/commands/ConnectClientFailureProxyV1.java [new file with mode: 0644]
opendaylight/md-sal/cds-access-api/src/main/java/org/opendaylight/controller/cluster/access/commands/ConnectClientRequest.java [new file with mode: 0644]
opendaylight/md-sal/cds-access-api/src/main/java/org/opendaylight/controller/cluster/access/commands/ConnectClientRequestProxyV1.java [new file with mode: 0644]
opendaylight/md-sal/cds-access-api/src/main/java/org/opendaylight/controller/cluster/access/commands/ConnectClientSuccess.java [new file with mode: 0644]
opendaylight/md-sal/cds-access-api/src/main/java/org/opendaylight/controller/cluster/access/commands/ConnectClientSuccessProxyV1.java [new file with mode: 0644]
opendaylight/md-sal/cds-access-api/src/main/java/org/opendaylight/controller/cluster/access/commands/ExistsTransactionSuccess.java

index c25c156..0e40e6e 100644 (file)
@@ -15,6 +15,8 @@ import java.io.DataOutput;
 import java.io.IOException;
 import javax.annotation.Nonnull;
 import org.opendaylight.yangtools.concepts.WritableObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * Enumeration of all ABI versions supported by this implementation of the client access API.
@@ -43,6 +45,8 @@ public enum ABIVersion implements WritableObject {
     @VisibleForTesting
     TEST_FUTURE_VERSION(65535);
 
+    private static final Logger LOG = LoggerFactory.getLogger(ABIVersion.class);
+
     private final short value;
 
     ABIVersion(final int intVersion) {
@@ -114,4 +118,17 @@ public enum ABIVersion implements WritableObject {
             throw new IOException("Unsupported version", e);
         }
     }
+
+    public static ABIVersion inexactReadFrom(final @Nonnull DataInput in) throws IOException {
+        final short onWire = in.readShort();
+        try {
+            return ABIVersion.valueOf(onWire);
+        } catch (FutureVersionException e) {
+            LOG.debug("Received future version", e);
+            return ABIVersion.TEST_FUTURE_VERSION;
+        } catch (PastVersionException e) {
+            LOG.debug("Received past version", e);
+            return ABIVersion.TEST_PAST_VERSION;
+        }
+    }
 }
diff --git a/opendaylight/md-sal/cds-access-api/src/main/java/org/opendaylight/controller/cluster/access/commands/ConnectClientFailure.java b/opendaylight/md-sal/cds-access-api/src/main/java/org/opendaylight/controller/cluster/access/commands/ConnectClientFailure.java
new file mode 100644 (file)
index 0000000..c1380cc
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * 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.commands;
+
+import com.google.common.annotations.Beta;
+import org.opendaylight.controller.cluster.access.ABIVersion;
+import org.opendaylight.controller.cluster.access.concepts.AbstractRequestFailureProxy;
+import org.opendaylight.controller.cluster.access.concepts.ClientIdentifier;
+import org.opendaylight.controller.cluster.access.concepts.RequestException;
+import org.opendaylight.controller.cluster.access.concepts.RequestFailure;
+
+/**
+ * A {@link RequestFailure} reported when {@link ConnectClientRequest} fails.
+ *
+ * @author Robert Varga
+ */
+@Beta
+public final class ConnectClientFailure extends RequestFailure<ClientIdentifier, ConnectClientFailure> {
+    private static final long serialVersionUID = 1L;
+
+    ConnectClientFailure(final ClientIdentifier target, final RequestException cause) {
+        super(target, cause);
+    }
+
+    private ConnectClientFailure(final ConnectClientFailure failure, final ABIVersion version) {
+        super(failure, version);
+    }
+
+    @Override
+    protected AbstractRequestFailureProxy<ClientIdentifier, ConnectClientFailure> externalizableProxy(
+            final ABIVersion version) {
+        return new ConnectClientFailureProxyV1(this);
+    }
+
+    @Override
+    protected ConnectClientFailure cloneAsVersion(final ABIVersion version) {
+        return new ConnectClientFailure(this, version);
+    }
+}
diff --git a/opendaylight/md-sal/cds-access-api/src/main/java/org/opendaylight/controller/cluster/access/commands/ConnectClientFailureProxyV1.java b/opendaylight/md-sal/cds-access-api/src/main/java/org/opendaylight/controller/cluster/access/commands/ConnectClientFailureProxyV1.java
new file mode 100644 (file)
index 0000000..5635754
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * 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.commands;
+
+import java.io.DataInput;
+import java.io.IOException;
+import org.opendaylight.controller.cluster.access.concepts.AbstractRequestFailureProxy;
+import org.opendaylight.controller.cluster.access.concepts.ClientIdentifier;
+import org.opendaylight.controller.cluster.access.concepts.RequestException;
+
+/**
+ * Serialization proxy for use with {@link ConnectClientFailure}. This class implements initial (Boron) serialization
+ * format.
+ *
+ * @author Robert Varga
+ */
+final class ConnectClientFailureProxyV1 extends AbstractRequestFailureProxy<ClientIdentifier, ConnectClientFailure> {
+    public ConnectClientFailureProxyV1() {
+        // For Externalizable
+    }
+
+    ConnectClientFailureProxyV1(final ConnectClientFailure failure) {
+        super(failure);
+    }
+
+    @Override
+    protected ConnectClientFailure createFailure(final ClientIdentifier target, final RequestException cause) {
+        return new ConnectClientFailure(target, cause);
+    }
+
+    @Override
+    protected ClientIdentifier readTarget(final DataInput in) throws IOException {
+        return ClientIdentifier.readFrom(in);
+    }
+}
diff --git a/opendaylight/md-sal/cds-access-api/src/main/java/org/opendaylight/controller/cluster/access/commands/ConnectClientRequest.java b/opendaylight/md-sal/cds-access-api/src/main/java/org/opendaylight/controller/cluster/access/commands/ConnectClientRequest.java
new file mode 100644 (file)
index 0000000..4800cea
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * 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.commands;
+
+import akka.actor.ActorRef;
+import com.google.common.annotations.Beta;
+import com.google.common.base.MoreObjects.ToStringHelper;
+import com.google.common.base.Preconditions;
+import javax.annotation.Nonnull;
+import org.opendaylight.controller.cluster.access.ABIVersion;
+import org.opendaylight.controller.cluster.access.concepts.AbstractRequestProxy;
+import org.opendaylight.controller.cluster.access.concepts.ClientIdentifier;
+import org.opendaylight.controller.cluster.access.concepts.Request;
+import org.opendaylight.controller.cluster.access.concepts.RequestException;
+
+/**
+ * Request to connect a frontend instance to the backend. It carries basic information about the frontend:
+ * - its coordinates in {@link #getReplyTo()}.
+ * - its minimum supported ABI version
+ * - its maximum supported ABI version
+ *
+ * It also includes request stream sequencing information.
+ *
+ * @author Robert Varga
+ */
+@Beta
+public final class ConnectClientRequest extends Request<ClientIdentifier, ConnectClientRequest> {
+    private static final long serialVersionUID = 1L;
+
+    private final ABIVersion minVersion;
+    private final ABIVersion maxVersion;
+    private final long resumeSequence;
+
+    public ConnectClientRequest(final ClientIdentifier identifier, final ActorRef replyTo, final ABIVersion minVersion,
+            final ABIVersion maxVersion) {
+        this(identifier, replyTo, minVersion, maxVersion, 0);
+    }
+
+    public ConnectClientRequest(final ClientIdentifier identifier, final ActorRef replyTo, final ABIVersion minVersion,
+            final ABIVersion maxVersion, final long resumeSequence) {
+        super(identifier, replyTo);
+        this.minVersion = Preconditions.checkNotNull(minVersion);
+        this.maxVersion = Preconditions.checkNotNull(maxVersion);
+        this.resumeSequence = resumeSequence;
+    }
+
+    private ConnectClientRequest(final ConnectClientRequest request, final ABIVersion version) {
+        super(request, version);
+        this.minVersion = request.minVersion;
+        this.maxVersion = request.maxVersion;
+        this.resumeSequence = request.resumeSequence;
+    }
+
+    public ABIVersion getMinVersion() {
+        return minVersion;
+    }
+
+    public ABIVersion getMaxVersion() {
+        return maxVersion;
+    }
+
+    public long getResumeSequence() {
+        return resumeSequence;
+    }
+
+    @Override
+    public final ConnectClientFailure toRequestFailure(final RequestException cause) {
+        return new ConnectClientFailure(getTarget(), cause);
+    }
+
+    @Override
+    protected AbstractRequestProxy<ClientIdentifier, ConnectClientRequest> externalizableProxy(final ABIVersion version) {
+        return new ConnectClientRequestProxyV1(this);
+    }
+
+    @Override
+    protected ConnectClientRequest cloneAsVersion(final ABIVersion version) {
+        return new ConnectClientRequest(this, version);
+    }
+
+    @Override
+    protected @Nonnull ToStringHelper addToStringAttributes(final @Nonnull ToStringHelper toStringHelper) {
+        return super.addToStringAttributes(toStringHelper).add("minVersion", minVersion).add("maxVersion", maxVersion)
+                .add("resumeSequence", resumeSequence);
+    }
+}
diff --git a/opendaylight/md-sal/cds-access-api/src/main/java/org/opendaylight/controller/cluster/access/commands/ConnectClientRequestProxyV1.java b/opendaylight/md-sal/cds-access-api/src/main/java/org/opendaylight/controller/cluster/access/commands/ConnectClientRequestProxyV1.java
new file mode 100644 (file)
index 0000000..5fb26d0
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * 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.commands;
+
+import akka.actor.ActorRef;
+import java.io.DataInput;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import org.opendaylight.controller.cluster.access.ABIVersion;
+import org.opendaylight.controller.cluster.access.concepts.AbstractRequestProxy;
+import org.opendaylight.controller.cluster.access.concepts.ClientIdentifier;
+import org.opendaylight.yangtools.concepts.WritableObjects;
+
+/**
+ * Externalizable proxy for use with {@link ConnectClientRequest}. It implements the initial (Boron) serialization
+ * format.
+ *
+ * @author Robert Varga
+ */
+final class ConnectClientRequestProxyV1 extends AbstractRequestProxy<ClientIdentifier, ConnectClientRequest> {
+    private ABIVersion minVersion;
+    private ABIVersion maxVersion;
+    private long resumeSequence;
+
+    public ConnectClientRequestProxyV1() {
+        // for Externalizable
+    }
+
+    ConnectClientRequestProxyV1(final ConnectClientRequest request) {
+        super(request);
+        this.minVersion = request.getMinVersion();
+        this.maxVersion = request.getMaxVersion();
+        this.resumeSequence = request.getResumeSequence();
+    }
+
+    @Override
+    public void writeExternal(final ObjectOutput out) throws IOException {
+        super.writeExternal(out);
+        minVersion.writeTo(out);
+        maxVersion.writeTo(out);
+        WritableObjects.writeLong(out, resumeSequence);
+    }
+
+    @Override
+    public void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException {
+        super.readExternal(in);
+        minVersion = ABIVersion.inexactReadFrom(in);
+        maxVersion = ABIVersion.inexactReadFrom(in);
+        resumeSequence = WritableObjects.readLong(in);
+    }
+
+    @Override
+    protected ConnectClientRequest createRequest(final ClientIdentifier target, final ActorRef replyTo) {
+        return new ConnectClientRequest(target, replyTo, minVersion, maxVersion, resumeSequence);
+    }
+
+    @Override
+    protected ClientIdentifier readTarget(final DataInput in) throws IOException {
+        return ClientIdentifier.readFrom(in);
+    }
+}
diff --git a/opendaylight/md-sal/cds-access-api/src/main/java/org/opendaylight/controller/cluster/access/commands/ConnectClientSuccess.java b/opendaylight/md-sal/cds-access-api/src/main/java/org/opendaylight/controller/cluster/access/commands/ConnectClientSuccess.java
new file mode 100644 (file)
index 0000000..c230259
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * 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.commands;
+
+import akka.actor.ActorRef;
+import akka.actor.ActorSelection;
+import com.google.common.annotations.Beta;
+import com.google.common.base.MoreObjects.ToStringHelper;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+import java.util.List;
+import java.util.Optional;
+import javax.annotation.Nonnull;
+import org.opendaylight.controller.cluster.access.ABIVersion;
+import org.opendaylight.controller.cluster.access.concepts.ClientIdentifier;
+import org.opendaylight.controller.cluster.access.concepts.RequestSuccess;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree;
+
+/**
+ * Successful reply to an {@link ConnectClientRequest}. Client actor which initiated this connection should use
+ * the version reported via {@link #getVersion()} of this message to communicate with this backend. Should this backend
+ * fail, the client can try accessing the provided alternates.
+ *
+ * @author Robert Varga
+ */
+@Beta
+public final class ConnectClientSuccess extends RequestSuccess<ClientIdentifier, ConnectClientSuccess> {
+    private static final long serialVersionUID = 1L;
+
+    private final List<ActorSelection> alternates;
+    private final DataTree dataTree;
+    private final ActorRef backend;
+
+    ConnectClientSuccess(final ClientIdentifier target, final ActorRef backend, final List<ActorSelection> alternates,
+        final Optional<DataTree> dataTree) {
+        super(target);
+        this.backend = Preconditions.checkNotNull(backend);
+        this.alternates = ImmutableList.copyOf(alternates);
+        this.dataTree = dataTree.orElse(null);
+    }
+
+    public ConnectClientSuccess(final @Nonnull ClientIdentifier target, final @Nonnull ActorRef backend,
+            final @Nonnull List<ActorSelection> alternates,
+            final @Nonnull DataTree dataTree) {
+        this(target, backend, alternates, Optional.of(dataTree));
+    }
+
+    /**
+     * Return the list of known alternate backends. The client can use this list to perform recovery procedures.
+     *
+     * @return a list of known backend alternates
+     */
+    public @Nonnull List<ActorSelection> getAlternates() {
+        return alternates;
+    }
+
+    public @Nonnull ActorRef getBackend() {
+        return backend;
+    }
+
+    public Optional<DataTree> getDataTree() {
+        return Optional.ofNullable(dataTree);
+    }
+
+    @Override
+    protected ConnectClientSuccessProxyV1 externalizableProxy(final ABIVersion version) {
+        return new ConnectClientSuccessProxyV1(this);
+    }
+
+    @Override
+    protected ConnectClientSuccess cloneAsVersion(final ABIVersion version) {
+        return this;
+    }
+
+    @Override
+    protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
+        return super.addToStringAttributes(toStringHelper).add("alternates", alternates).add("dataTree", dataTree);
+    }
+}
diff --git a/opendaylight/md-sal/cds-access-api/src/main/java/org/opendaylight/controller/cluster/access/commands/ConnectClientSuccessProxyV1.java b/opendaylight/md-sal/cds-access-api/src/main/java/org/opendaylight/controller/cluster/access/commands/ConnectClientSuccessProxyV1.java
new file mode 100644 (file)
index 0000000..d05ca37
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * 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.commands;
+
+import akka.actor.ActorRef;
+import akka.actor.ActorSelection;
+import akka.serialization.JavaSerializer;
+import akka.serialization.Serialization;
+import java.io.DataInput;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import org.opendaylight.controller.cluster.access.concepts.AbstractSuccessProxy;
+import org.opendaylight.controller.cluster.access.concepts.ClientIdentifier;
+
+/**
+ * Externalizable proxy for use with {@link ConnectClientSuccess}. It implements the initial (Boron) serialization
+ * format.
+ *
+ * @author Robert Varga
+ */
+final class ConnectClientSuccessProxyV1 extends AbstractSuccessProxy<ClientIdentifier, ConnectClientSuccess> {
+    private static final long serialVersionUID = 1L;
+
+    private List<ActorSelection> alternates;
+    private ActorRef backend;
+
+    public ConnectClientSuccessProxyV1() {
+        // For Externalizable
+    }
+
+    ConnectClientSuccessProxyV1(final ConnectClientSuccess success) {
+        super(success);
+        this.alternates = success.getAlternates();
+        this.backend = success.getBackend();
+        // We are ignoring the DataTree, it is not serializable anyway
+    }
+
+    @Override
+    public void writeExternal(final ObjectOutput out) throws IOException {
+        super.writeExternal(out);
+
+        out.writeUTF(Serialization.serializedActorPath(backend));
+
+        out.writeInt(alternates.size());
+        for (ActorSelection b : alternates) {
+            out.writeObject(b.toSerializationFormat());
+        }
+    }
+
+    @Override
+    public void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException {
+        super.readExternal(in);
+
+        backend = JavaSerializer.currentSystem().value().provider().resolveActorRef(in.readUTF());
+
+        final int backendsSize = in.readInt();
+        if (backendsSize < 1) {
+            throw new IOException("Illegal number of backends " + backendsSize);
+        }
+
+        alternates = new ArrayList<>(backendsSize);
+        for (int i = 0; i < backendsSize; ++i) {
+            alternates.add(ActorSelection.apply(ActorRef.noSender(), (String)in.readObject()));
+        }
+    }
+
+    @Override
+    protected ConnectClientSuccess createSuccess(final ClientIdentifier target) {
+        return new ConnectClientSuccess(target, backend, alternates, Optional.empty());
+    }
+
+    @Override
+    protected ClientIdentifier readTarget(final DataInput in) throws IOException {
+        return ClientIdentifier.readFrom(in);
+    }
+}
index 3316792..5481d0d 100644 (file)
@@ -13,7 +13,7 @@ import org.opendaylight.controller.cluster.access.ABIVersion;
 import org.opendaylight.controller.cluster.access.concepts.TransactionIdentifier;
 
 /**
- * Successuful reply to an {@link ExistsTransactionRequest}. It indicates presence of requested data via
+ * Successful reply to an {@link ExistsTransactionRequest}. It indicates presence of requested data via
  * {@link #getExists()}.
  *
  * @author Robert Varga