<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.opendaylight.controller</groupId>
- <artifactId>bundle-parent</artifactId>
+ <artifactId>mdsal-parent</artifactId>
<version>4.0.2-SNAPSHOT</version>
- <relativePath>../../../bundle-parent</relativePath>
+ <relativePath>../bundle-parent</relativePath>
</parent>
<artifactId>eos-dom-akka</artifactId>
<groupId>org.opendaylight.mdsal</groupId>
<artifactId>mdsal-eos-dom-api</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>mdsal-binding-api</artifactId>
+ </dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>concepts</artifactId>
import java.util.concurrent.CompletionStage;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
+import java.util.function.Function;
import javax.annotation.PreDestroy;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.opendaylight.controller.eos.akka.owner.checker.command.StateCheckerCommand;
import org.opendaylight.controller.eos.akka.owner.supervisor.command.ActivateDataCenter;
import org.opendaylight.controller.eos.akka.owner.supervisor.command.DeactivateDataCenter;
+import org.opendaylight.controller.eos.akka.owner.supervisor.command.GetEntitiesReply;
+import org.opendaylight.controller.eos.akka.owner.supervisor.command.GetEntitiesRequest;
+import org.opendaylight.controller.eos.akka.owner.supervisor.command.GetEntityOwnerReply;
+import org.opendaylight.controller.eos.akka.owner.supervisor.command.GetEntityOwnerRequest;
+import org.opendaylight.controller.eos.akka.owner.supervisor.command.GetEntityReply;
+import org.opendaylight.controller.eos.akka.owner.supervisor.command.GetEntityRequest;
import org.opendaylight.controller.eos.akka.owner.supervisor.command.OwnerSupervisorCommand;
+import org.opendaylight.controller.eos.akka.owner.supervisor.command.OwnerSupervisorReply;
import org.opendaylight.controller.eos.akka.registry.candidate.command.CandidateRegistryCommand;
import org.opendaylight.controller.eos.akka.registry.candidate.command.RegisterCandidate;
import org.opendaylight.controller.eos.akka.registry.candidate.command.UnregisterCandidate;
import org.opendaylight.controller.eos.akka.registry.listener.type.command.RegisterListener;
import org.opendaylight.controller.eos.akka.registry.listener.type.command.TypeListenerRegistryCommand;
import org.opendaylight.controller.eos.akka.registry.listener.type.command.UnregisterListener;
+import org.opendaylight.mdsal.binding.api.RpcProviderService;
import org.opendaylight.mdsal.eos.common.api.CandidateAlreadyRegisteredException;
import org.opendaylight.mdsal.eos.common.api.EntityOwnershipState;
import org.opendaylight.mdsal.eos.dom.api.DOMEntity;
import org.opendaylight.mdsal.eos.dom.api.DOMEntityOwnershipListener;
import org.opendaylight.mdsal.eos.dom.api.DOMEntityOwnershipListenerRegistration;
import org.opendaylight.mdsal.eos.dom.api.DOMEntityOwnershipService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.entity.owners.norev.GetEntitiesInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.entity.owners.norev.GetEntitiesOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.entity.owners.norev.GetEntityInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.entity.owners.norev.GetEntityOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.entity.owners.norev.GetEntityOwnerInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.entity.owners.norev.GetEntityOwnerOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.entity.owners.norev.OdlEntityOwnersService;
+import org.opendaylight.yangtools.concepts.Registration;
+import org.opendaylight.yangtools.yang.binding.RpcOutput;
import org.opendaylight.yangtools.yang.common.Empty;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate;
*/
@Singleton
@Component(immediate = true, service = { DOMEntityOwnershipService.class, DataCenterControl.class })
-public class AkkaEntityOwnershipService implements DOMEntityOwnershipService, DataCenterControl, AutoCloseable {
+public class AkkaEntityOwnershipService implements DOMEntityOwnershipService, DataCenterControl, AutoCloseable,
+ OdlEntityOwnersService {
private static final Logger LOG = LoggerFactory.getLogger(AkkaEntityOwnershipService.class);
private static final String DATACENTER_PREFIX = "dc";
private static final Duration DATACENTER_OP_TIMEOUT = Duration.ofSeconds(20);
+ private static final Duration QUERY_TIMEOUT = Duration.ofSeconds(10);
private final Set<DOMEntity> registeredEntities = ConcurrentHashMap.newKeySet();
private final String localCandidate;
private final ActorRef<StateCheckerCommand> ownerStateChecker;
protected final ActorRef<OwnerSupervisorCommand> ownerSupervisor;
+ private Registration reg;
+
@VisibleForTesting
protected AkkaEntityOwnershipService(final ActorSystem actorSystem)
throws ExecutionException, InterruptedException {
@Inject
@Activate
- public AkkaEntityOwnershipService(@Reference final ActorSystemProvider provider)
- throws ExecutionException, InterruptedException {
- this(provider.getActorSystem());
+ public AkkaEntityOwnershipService(@Reference final ActorSystemProvider actorProvider,
+ @Reference final RpcProviderService rpcProvider) throws ExecutionException, InterruptedException {
+ this(actorProvider.getActorSystem());
+
+ reg = rpcProvider.registerRpcImplementation(OdlEntityOwnersService.class, this);
}
@PreDestroy
@Deactivate
@Override
public void close() throws InterruptedException, ExecutionException {
+ if (reg != null) {
+ reg.close();
+ reg = null;
+ }
AskPattern.ask(bootstrap, Terminate::new, Duration.ofSeconds(5), scheduler).toCompletableFuture().get();
}
AskPattern.ask(ownerSupervisor, DeactivateDataCenter::new, DATACENTER_OP_TIMEOUT, scheduler));
}
+
+ @Override
+ public ListenableFuture<RpcResult<GetEntitiesOutput>> getEntities(final GetEntitiesInput input) {
+ return toRpcFuture(AskPattern.ask(ownerSupervisor, GetEntitiesRequest::new, QUERY_TIMEOUT, scheduler),
+ GetEntitiesReply::toOutput);
+ }
+
+ @Override
+ public ListenableFuture<RpcResult<GetEntityOutput>> getEntity(final GetEntityInput input) {
+ return toRpcFuture(AskPattern.ask(ownerSupervisor,
+ (final ActorRef<GetEntityReply> replyTo) -> new GetEntityRequest(replyTo, input), QUERY_TIMEOUT, scheduler),
+ GetEntityReply::toOutput);
+ }
+
+ @Override
+ public ListenableFuture<RpcResult<GetEntityOwnerOutput>> getEntityOwner(final GetEntityOwnerInput input) {
+ return toRpcFuture(AskPattern.ask(ownerSupervisor,
+ (final ActorRef<GetEntityOwnerReply> replyTo) -> new GetEntityOwnerRequest(replyTo, input), QUERY_TIMEOUT,
+ scheduler), GetEntityOwnerReply::toOutput);
+ }
+
void unregisterCandidate(final DOMEntity entity) {
LOG.debug("Unregistering candidate for {}", entity);
return runningContext;
}
+ private static <R extends OwnerSupervisorReply, O extends RpcOutput> ListenableFuture<RpcResult<O>> toRpcFuture(
+ final CompletionStage<R> stage, final Function<R, O> outputFunction) {
+
+ final SettableFuture<RpcResult<O>> future = SettableFuture.create();
+ stage.whenComplete((reply, failure) -> {
+ if (failure != null) {
+ future.setException(failure);
+ } else {
+ future.set(RpcResultBuilder.success(outputFunction.apply(reply)).build());
+ }
+ });
+ return future;
+ }
+
private static ListenableFuture<Empty> toListenableFuture(final String op, final CompletionStage<?> stage) {
final SettableFuture<Empty> future = SettableFuture.create();
stage.whenComplete((reply, failure) -> {
if (failure != null) {
- LOG.warn("{} DataCenter has failed", op, failure);
+ LOG.warn("{} DataCenter failed", op, failure);
future.setException(failure);
} else {
LOG.debug("{} DataCenter successful", op);
import java.util.Set;
import java.util.function.BiPredicate;
import java.util.stream.Collectors;
+import org.opendaylight.controller.eos.akka.owner.supervisor.command.AbstractEntityRequest;
import org.opendaylight.controller.eos.akka.owner.supervisor.command.CandidatesChanged;
import org.opendaylight.controller.eos.akka.owner.supervisor.command.DataCenterDeactivated;
import org.opendaylight.controller.eos.akka.owner.supervisor.command.DeactivateDataCenter;
+import org.opendaylight.controller.eos.akka.owner.supervisor.command.GetEntitiesReply;
+import org.opendaylight.controller.eos.akka.owner.supervisor.command.GetEntitiesRequest;
+import org.opendaylight.controller.eos.akka.owner.supervisor.command.GetEntityOwnerReply;
+import org.opendaylight.controller.eos.akka.owner.supervisor.command.GetEntityOwnerRequest;
+import org.opendaylight.controller.eos.akka.owner.supervisor.command.GetEntityReply;
+import org.opendaylight.controller.eos.akka.owner.supervisor.command.GetEntityRequest;
import org.opendaylight.controller.eos.akka.owner.supervisor.command.MemberDownEvent;
import org.opendaylight.controller.eos.akka.owner.supervisor.command.MemberReachableEvent;
import org.opendaylight.controller.eos.akka.owner.supervisor.command.MemberUnreachableEvent;
.onMessage(MemberDownEvent.class, this::onPeerDown)
.onMessage(MemberReachableEvent.class, this::onPeerReachable)
.onMessage(MemberUnreachableEvent.class, this::onPeerUnreachable)
+ .onMessage(GetEntitiesRequest.class, this::onGetEntities)
+ .onMessage(GetEntityRequest.class, this::onGetEntity)
+ .onMessage(GetEntityOwnerRequest.class, this::onGetEntityOwner)
.build();
}
final BiPredicate<DOMEntity, String> predicate) {
LOG.debug("Reassigning owners for {}", entities);
for (final DOMEntity entity : entities) {
-
-
if (predicate.test(entity, oldOwner)) {
ownerToEntity.remove(oldOwner, entity);
assignOwnerFor(entity);
return this;
}
+ private Behavior<OwnerSupervisorCommand> onGetEntities(final GetEntitiesRequest request) {
+ request.getReplyTo().tell(new GetEntitiesReply(currentOwners, currentCandidates));
+ return this;
+ }
+
+ private Behavior<OwnerSupervisorCommand> onGetEntity(final GetEntityRequest request) {
+ final DOMEntity entity = extractEntity(request);
+ request.getReplyTo().tell(new GetEntityReply(currentOwners.get(entity), currentCandidates.get(entity)));
+ return this;
+ }
+
+ private Behavior<OwnerSupervisorCommand> onGetEntityOwner(final GetEntityOwnerRequest request) {
+ request.getReplyTo().tell(new GetEntityOwnerReply(currentOwners.get(extractEntity(request))));
+ return this;
+ }
+
private void handleReachableEvent(final Set<String> roles) {
if (roles.contains(dataCenter)) {
activeMembers.add(extractRole(roles));
return members;
}
+ private static DOMEntity extractEntity(final AbstractEntityRequest<?> request) {
+ return new DOMEntity(request.getType().getValue(), request.getName().getValue());
+ }
+
private static String extractRole(final Member member) {
return extractRole(member.getRoles());
}
--- /dev/null
+/*
+ * Copyright (c) 2021 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.eos.akka.owner.supervisor.command;
+
+import akka.actor.typed.ActorRef;
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.entity.owners.norev.EntityId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.entity.owners.norev.EntityName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.entity.owners.norev.EntityType;
+
+public abstract class AbstractEntityRequest<T extends OwnerSupervisorReply> extends OwnerSupervisorRequest<T> {
+ private static final long serialVersionUID = 1L;
+
+ private final @NonNull EntityType type;
+ private final @NonNull EntityName name;
+
+ AbstractEntityRequest(final ActorRef<T> replyTo, final EntityId entity) {
+ super(replyTo);
+ this.type = entity.requireType();
+ this.name = entity.requireName();
+ }
+
+ public final @NonNull EntityType getType() {
+ return type;
+ }
+
+ public final @NonNull EntityName getName() {
+ return name;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2021 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.eos.akka.owner.supervisor.command;
+
+import static com.google.common.base.Verify.verify;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSetMultimap;
+import com.google.common.collect.ImmutableSetMultimap.Builder;
+import com.google.common.collect.Iterables;
+import java.io.Serializable;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.mdsal.eos.dom.api.DOMEntity;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.entity.owners.norev.EntityName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.entity.owners.norev.EntityType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.entity.owners.norev.GetEntitiesOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.entity.owners.norev.GetEntitiesOutputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.entity.owners.norev.NodeName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.entity.owners.norev.get.entities.output.EntitiesBuilder;
+import org.opendaylight.yangtools.yang.binding.util.BindingMap;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+
+public final class GetEntitiesReply extends OwnerSupervisorReply implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ private final ImmutableSetMultimap<DOMEntity, String> candidates;
+ private final ImmutableMap<DOMEntity, String> owners;
+
+ public GetEntitiesReply(final Map<DOMEntity, String> owners, final Map<DOMEntity, Set<String>> candidates) {
+ final Builder<DOMEntity, String> builder = ImmutableSetMultimap.builder();
+ for (Entry<DOMEntity, Set<String>> entry : candidates.entrySet()) {
+ builder.putAll(entry.getKey(), entry.getValue());
+ }
+ this.candidates = builder.build();
+ this.owners = ImmutableMap.copyOf(owners);
+ }
+
+ public @NonNull GetEntitiesOutput toOutput() {
+ final Set<DOMEntity> entities = new HashSet<>();
+ entities.addAll(owners.keySet());
+ entities.addAll(candidates.keySet());
+
+ return new GetEntitiesOutputBuilder()
+ .setEntities(entities.stream()
+ .map(entity -> {
+ final EntitiesBuilder eb = new EntitiesBuilder()
+ .setType(new EntityType(entity.getType()))
+ .setName(extractName(entity))
+ .setCandidateNodes(candidates.get(entity).stream()
+ .map(NodeName::new).collect(Collectors.toUnmodifiableList()));
+
+ final String owner = owners.get(entity);
+ if (owner != null) {
+ eb.setOwnerNode(new NodeName(owner));
+ }
+ return eb.build();
+ })
+ .collect(BindingMap.toMap()))
+ .build();
+ }
+
+ private static EntityName extractName(final DOMEntity entity) {
+ final PathArgument last = entity.getIdentifier().getLastPathArgument();
+ verify(last instanceof NodeIdentifierWithPredicates, "Unexpected last argument %s", last);
+ final Object value = Iterables.getOnlyElement(((NodeIdentifierWithPredicates) last).values());
+ verify(value instanceof String, "Unexpected predicate value %s", value);
+ return new EntityName((String) value);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2021 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.eos.akka.owner.supervisor.command;
+
+import akka.actor.typed.ActorRef;
+
+public final class GetEntitiesRequest extends OwnerSupervisorRequest<GetEntitiesReply> {
+ private static final long serialVersionUID = 1L;
+
+ public GetEntitiesRequest(final ActorRef<GetEntitiesReply> replyTo) {
+ super(replyTo);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2021 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.eos.akka.owner.supervisor.command;
+
+import java.io.Serializable;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.entity.owners.norev.GetEntityOwnerOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.entity.owners.norev.GetEntityOwnerOutputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.entity.owners.norev.NodeName;
+
+public final class GetEntityOwnerReply extends OwnerSupervisorReply implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ private final String owner;
+
+ public GetEntityOwnerReply(final @Nullable String owner) {
+ this.owner = owner;
+ }
+
+ public @NonNull GetEntityOwnerOutput toOutput() {
+ final GetEntityOwnerOutputBuilder builder = new GetEntityOwnerOutputBuilder();
+ if (owner != null) {
+ builder.setOwnerNode(new NodeName(owner));
+ }
+ return builder.build();
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2021 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.eos.akka.owner.supervisor.command;
+
+import akka.actor.typed.ActorRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.entity.owners.norev.EntityId;
+
+public final class GetEntityOwnerRequest extends AbstractEntityRequest<GetEntityOwnerReply> {
+ private static final long serialVersionUID = 1L;
+
+ public GetEntityOwnerRequest(final ActorRef<GetEntityOwnerReply> replyTo, final EntityId entity) {
+ super(replyTo, entity);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2021 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.eos.akka.owner.supervisor.command;
+
+import com.google.common.collect.ImmutableSet;
+import java.io.Serializable;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.entity.owners.norev.GetEntityOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.entity.owners.norev.GetEntityOutputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.entity.owners.norev.NodeName;
+
+public final class GetEntityReply extends OwnerSupervisorReply implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ private final ImmutableSet<String> candidates;
+ private final String owner;
+
+ public GetEntityReply(final @Nullable String owner, final @Nullable Set<String> candidates) {
+ this.owner = owner;
+ this.candidates = candidates == null ? ImmutableSet.of() : ImmutableSet.copyOf(candidates);
+ }
+
+ public @NonNull GetEntityOutput toOutput() {
+ final GetEntityOutputBuilder builder = new GetEntityOutputBuilder();
+ if (owner != null) {
+ builder.setOwnerNode(new NodeName(owner));
+ }
+ return builder
+ .setCandidateNodes(candidates.stream().map(NodeName::new).collect(Collectors.toUnmodifiableList()))
+ .build();
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2021 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.eos.akka.owner.supervisor.command;
+
+import akka.actor.typed.ActorRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.entity.owners.norev.EntityId;
+
+public final class GetEntityRequest extends AbstractEntityRequest<GetEntityReply> {
+ private static final long serialVersionUID = 1L;
+
+ public GetEntityRequest(final ActorRef<GetEntityReply> replyTo, final EntityId entity) {
+ super(replyTo, entity);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2021 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.eos.akka.owner.supervisor.command;
+
+import static java.util.Objects.requireNonNull;
+
+import akka.actor.typed.ActorRef;
+import java.io.Serializable;
+import org.eclipse.jdt.annotation.NonNull;
+
+abstract class OwnerSupervisorRequest<T extends OwnerSupervisorReply> extends OwnerSupervisorCommand
+ implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ private final @NonNull ActorRef<T> replyTo;
+
+ OwnerSupervisorRequest(final ActorRef<T> replyTo) {
+ this.replyTo = requireNonNull(replyTo);
+ }
+
+ public final @NonNull ActorRef<T> getReplyTo() {
+ return replyTo;
+ }
+}
--- /dev/null
+module odl-entity-owners {
+ namespace urn:opendaylight:params:xml:ns:yang:controller:entity-owners;
+ prefix entity-owners;
+
+ organization 'OpenDaylight Project';
+ description "An initial cut at modeling entity ownership status information
+ in a way which is not dependent on the datastore.
+
+ This model is considered experimental and
+ implementation-specific. It can change incompatibly between
+ OpenDaylight releases.";
+
+ typedef entity-type {
+ type string {
+ length 1..max;
+ // FIXME: it would be nice to have a pattern here, or even better
+ // if we turn this into an extensible enum (i.e. identityref)
+ }
+ }
+
+ typedef entity-name {
+ type string {
+ length 1..max;
+ }
+ }
+
+ typedef node-name {
+ type string {
+ length 1..max;
+ }
+ }
+
+ grouping entity-id {
+ leaf type {
+ type entity-type;
+ mandatory true;
+ }
+ leaf name {
+ type entity-name;
+ mandatory true;
+ }
+ }
+
+ grouping owner {
+ leaf owner-node {
+ type node-name;
+ }
+ }
+
+ grouping candidates {
+ leaf-list candidate-nodes {
+ type node-name;
+ ordered-by user;
+ min-elements 1;
+ }
+ }
+
+ grouping details {
+ uses owner;
+ uses candidates;
+ }
+
+ rpc get-entities {
+ output {
+ list entities {
+ key 'type name';
+ uses entity-id;
+ uses details;
+ }
+ }
+ }
+
+ rpc get-entity {
+ input {
+ uses entity-id;
+ }
+
+ output {
+ uses details;
+ }
+ }
+
+ rpc get-entity-owner {
+ input {
+ uses entity-id;
+ }
+
+ output {
+ uses owner;
+ }
+ }
+}
+