Remove use of {String,UUID}Identifier
[controller.git] / opendaylight / md-sal / sal-distributed-datastore / src / main / java / org / opendaylight / controller / cluster / datastore / DataTreeCohortActorRegistry.java
1 /*
2  * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.controller.cluster.datastore;
10
11 import akka.actor.ActorRef;
12 import akka.actor.PoisonPill;
13 import akka.actor.Status;
14 import com.google.common.base.Preconditions;
15 import java.util.ArrayList;
16 import java.util.Collection;
17 import java.util.HashMap;
18 import java.util.List;
19 import java.util.Map;
20 import javax.annotation.concurrent.NotThreadSafe;
21 import org.opendaylight.controller.cluster.datastore.DataTreeCohortActor.CanCommit;
22 import org.opendaylight.controller.md.sal.dom.spi.AbstractRegistrationTree;
23 import org.opendaylight.controller.md.sal.dom.spi.RegistrationTreeNode;
24 import org.opendaylight.controller.md.sal.dom.spi.RegistrationTreeSnapshot;
25 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
26 import org.opendaylight.mdsal.dom.api.DOMDataTreeCandidate;
27 import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier;
28 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
29 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
30 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
31 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNode;
32 import org.opendaylight.yangtools.yang.data.api.schema.tree.ModificationType;
33 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36
37 /**
38  * Registry of user commit cohorts, which is responsible for handling registration and calculation
39  * of affected cohorts based on {@link DataTreeCandidate}.
40  *
41  */
42 @NotThreadSafe
43 class DataTreeCohortActorRegistry extends AbstractRegistrationTree<ActorRef> {
44
45     private static final Logger LOG = LoggerFactory.getLogger(DataTreeCohortActorRegistry.class);
46
47     private final Map<ActorRef, RegistrationTreeNode<ActorRef>> cohortToNode = new HashMap<>();
48
49
50     void registerCohort(ActorRef sender, RegisterCohort cohort) {
51         takeLock();
52         try {
53             final ActorRef cohortRef = cohort.getCohort();
54             final RegistrationTreeNode<ActorRef> node =
55                     findNodeFor(cohort.getPath().getRootIdentifier().getPathArguments());
56             addRegistration(node, cohort.getCohort());
57             cohortToNode.put(cohortRef, node);
58         } catch (final Exception e) {
59             sender.tell(new Status.Failure(e), ActorRef.noSender());
60             return;
61         } finally {
62             releaseLock();
63         }
64         sender.tell(new Status.Success(null), ActorRef.noSender());
65     }
66
67     void removeCommitCohort(ActorRef sender, RemoveCohort message) {
68         final ActorRef cohort = message.getCohort();
69         final RegistrationTreeNode<ActorRef> node = cohortToNode.get(cohort);
70         if (node != null) {
71             removeRegistration(node, cohort);
72             cohortToNode.remove(cohort);
73         }
74         sender.tell(new Status.Success(null), ActorRef.noSender());
75         cohort.tell(PoisonPill.getInstance(), cohort);
76     }
77
78     Collection<DataTreeCohortActor.CanCommit> createCanCommitMessages(String txId, DataTreeCandidate candidate,
79             SchemaContext schema) {
80         try (RegistrationTreeSnapshot<ActorRef> cohorts = takeSnapshot()) {
81             return new CanCommitMessageBuilder(txId, candidate, schema).perform(cohorts.getRootNode());
82         }
83     }
84
85     void process(ActorRef sender, CohortRegistryCommand message) {
86         if (message instanceof RegisterCohort) {
87             registerCohort(sender, (RegisterCohort) message);
88         } else if (message instanceof RemoveCohort) {
89             removeCommitCohort(sender, (RemoveCohort) message);
90         }
91     }
92
93     static abstract class CohortRegistryCommand {
94
95         private final ActorRef cohort;
96
97         CohortRegistryCommand(ActorRef cohort) {
98             this.cohort = Preconditions.checkNotNull(cohort);
99         }
100
101         ActorRef getCohort() {
102             return cohort;
103         }
104     }
105
106     static class RegisterCohort extends CohortRegistryCommand {
107
108         private final DOMDataTreeIdentifier path;
109
110         RegisterCohort(DOMDataTreeIdentifier path, ActorRef cohort) {
111             super(cohort);
112             this.path = path;
113
114         }
115
116         public DOMDataTreeIdentifier getPath() {
117             return path;
118         }
119
120     }
121
122     static class RemoveCohort extends CohortRegistryCommand {
123
124         RemoveCohort(ActorRef cohort) {
125             super(cohort);
126         }
127
128     }
129
130     private static class CanCommitMessageBuilder {
131
132         private final String txId;
133         private final DataTreeCandidate candidate;
134         private final SchemaContext schema;
135         private final Collection<DataTreeCohortActor.CanCommit> messages =
136                 new ArrayList<>();
137
138         CanCommitMessageBuilder(String txId, DataTreeCandidate candidate, SchemaContext schema) {
139             this.txId = Preconditions.checkNotNull(txId);
140             this.candidate = Preconditions.checkNotNull(candidate);
141             this.schema = schema;
142         }
143
144         private void lookupAndCreateCanCommits(List<PathArgument> args, int offset,
145                 RegistrationTreeNode<ActorRef> node) {
146
147             if (args.size() != offset) {
148                 final PathArgument arg = args.get(offset);
149                 final RegistrationTreeNode<ActorRef> exactChild = node.getExactChild(arg);
150                 if (exactChild != null) {
151                     lookupAndCreateCanCommits(args, offset + 1, exactChild);
152                 }
153                 for (final RegistrationTreeNode<ActorRef> c : node.getInexactChildren(arg)) {
154                     lookupAndCreateCanCommits(args, offset + 1, c);
155                 }
156             } else {
157                 lookupAndCreateCanCommits(candidate.getRootPath(), node, candidate.getRootNode());
158             }
159         }
160
161         private void lookupAndCreateCanCommits(YangInstanceIdentifier path, RegistrationTreeNode<ActorRef> regNode,
162                 DataTreeCandidateNode candNode) {
163             if (candNode.getModificationType() == ModificationType.UNMODIFIED) {
164                 LOG.debug("Skipping unmodified candidate {}", path);
165                 return;
166             }
167             final Collection<ActorRef> regs = regNode.getRegistrations();
168             if (!regs.isEmpty()) {
169                 createCanCommits(regs, path, candNode);
170             }
171
172             for (final DataTreeCandidateNode candChild : candNode.getChildNodes()) {
173                 if (candChild.getModificationType() != ModificationType.UNMODIFIED) {
174                     final RegistrationTreeNode<ActorRef> regChild =
175                             regNode.getExactChild(candChild.getIdentifier());
176                     if (regChild != null) {
177                         lookupAndCreateCanCommits(path.node(candChild.getIdentifier()), regChild, candChild);
178                     }
179
180                     for (final RegistrationTreeNode<ActorRef> rc : regNode
181                             .getInexactChildren(candChild.getIdentifier())) {
182                         lookupAndCreateCanCommits(path.node(candChild.getIdentifier()), rc, candChild);
183                     }
184                 }
185             }
186         }
187
188         private void createCanCommits(Collection<ActorRef> regs, YangInstanceIdentifier path,
189                 DataTreeCandidateNode node) {
190             final DOMDataTreeCandidate candidate = DOMDataTreeCandidateTO.create(treeIdentifier(path), node);
191             for (final ActorRef reg : regs) {
192                 final CanCommit message = new DataTreeCohortActor.CanCommit(txId, candidate, schema, reg);
193                 messages.add(message);
194             }
195         }
196
197         private static DOMDataTreeIdentifier treeIdentifier(YangInstanceIdentifier path) {
198             return new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, path);
199         }
200
201         private Collection<DataTreeCohortActor.CanCommit> perform(RegistrationTreeNode<ActorRef> rootNode) {
202             final List<PathArgument> toLookup = candidate.getRootPath().getPathArguments();
203             lookupAndCreateCanCommits(toLookup, 0, rootNode);
204             return messages;
205         }
206     }
207
208 }