/* * 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 static com.google.common.base.Preconditions.checkArgument; import static java.util.Objects.requireNonNull; import akka.actor.ActorRef; import akka.actor.ActorSelection; import akka.serialization.JavaSerializer; import akka.serialization.Serialization; import com.google.common.base.MoreObjects.ToStringHelper; import com.google.common.collect.ImmutableList; import java.io.DataInput; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectInputStream; import java.io.ObjectOutput; import java.io.ObjectOutputStream; import java.io.ObjectStreamException; import java.util.ArrayList; import java.util.List; import java.util.Optional; import org.eclipse.jdt.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.tree.api.ReadOnlyDataTree; /** * 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. */ public final class ConnectClientSuccess extends RequestSuccess { interface SerialForm extends RequestSuccess.SerialForm { @Override default ClientIdentifier readTarget(final DataInput in) throws IOException { return ClientIdentifier.readFrom(in); } @Override default ConnectClientSuccess readExternal(final ObjectInput in, final ClientIdentifier target, final long sequence) throws IOException, ClassNotFoundException { final var backend = JavaSerializer.currentSystem().value().provider() .resolveActorRef((String) in.readObject()); final var maxMessages = in.readInt(); final int alternatesSize = in.readInt(); final var alternates = new ArrayList(alternatesSize); for (int i = 0; i < alternatesSize; ++i) { alternates.add(ActorSelection.apply(ActorRef.noSender(), (String)in.readObject())); } return new ConnectClientSuccess(target, sequence, backend, alternates, maxMessages, null); } @Override default void writeExternal(final ObjectOutput out, final ConnectClientSuccess msg) throws IOException { out.writeObject(Serialization.serializedActorPath(msg.backend)); out.writeInt(msg.maxMessages); out.writeInt(msg.alternates.size()); for (ActorSelection b : msg.alternates) { out.writeObject(b.toSerializationFormat()); } // We are ignoring the DataTree, it is not serializable anyway } } @java.io.Serial private static final long serialVersionUID = 1L; private final @NonNull ImmutableList alternates; private final ReadOnlyDataTree dataTree; private final @NonNull ActorRef backend; private final int maxMessages; private ConnectClientSuccess(final ConnectClientSuccess success, final ABIVersion version) { super(success, version); alternates = success.alternates; dataTree = success.dataTree; backend = success.backend; maxMessages = success.maxMessages; } ConnectClientSuccess(final ClientIdentifier target, final long sequence, final ActorRef backend, final List alternates, final int maxMessages, final ReadOnlyDataTree dataTree) { super(target, sequence); this.backend = requireNonNull(backend); this.alternates = ImmutableList.copyOf(alternates); this.dataTree = dataTree; checkArgument(maxMessages > 0, "Maximum messages has to be positive, not %s", maxMessages); this.maxMessages = maxMessages; } public ConnectClientSuccess(final @NonNull ClientIdentifier target, final long sequence, final @NonNull ActorRef backend, final @NonNull List alternates, final @NonNull ReadOnlyDataTree dataTree, final int maxMessages) { this(target, sequence, backend, alternates, maxMessages, requireNonNull(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 getAlternates() { return alternates; } public @NonNull ActorRef getBackend() { return backend; } public Optional getDataTree() { return Optional.ofNullable(dataTree); } public int getMaxMessages() { return maxMessages; } @Override protected SerialForm externalizableProxy(final ABIVersion version) { return new CCS(this); } @Override protected ConnectClientSuccess cloneAsVersion(final ABIVersion version) { return new ConnectClientSuccess(this, version); } @Override protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) { return super.addToStringAttributes(toStringHelper).add("alternates", alternates) .add("dataTree present", getDataTree().isPresent()).add("maxMessages", maxMessages); } @java.io.Serial private void readObject(final ObjectInputStream stream) throws IOException, ClassNotFoundException { throwNSE(); } @java.io.Serial private void readObjectNoData() throws ObjectStreamException { throwNSE(); } @java.io.Serial private void writeObject(final ObjectOutputStream stream) throws IOException { throwNSE(); } }