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.
@VisibleForTesting
TEST_FUTURE_VERSION(65535);
+ private static final Logger LOG = LoggerFactory.getLogger(ABIVersion.class);
+
private final short value;
ABIVersion(final int intVersion) {
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;
+ }
+ }
}
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
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