2 * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
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
9 package org.opendaylight.mdsal.dom.store.inmemory;
11 import com.google.common.annotations.Beta;
12 import com.google.common.annotations.VisibleForTesting;
13 import com.google.common.base.Preconditions;
14 import java.util.ArrayList;
15 import java.util.Collection;
16 import java.util.HashMap;
17 import java.util.Iterator;
19 import java.util.Map.Entry;
20 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
21 import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier;
22 import org.opendaylight.mdsal.dom.api.DOMDataTreeShard;
23 import org.opendaylight.mdsal.dom.spi.DOMDataTreePrefixTable;
24 import org.opendaylight.yangtools.yang.data.api.schema.tree.CursorAwareDataTreeSnapshot;
25 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree;
26 import org.opendaylight.yangtools.yang.data.api.schema.tree.TreeType;
27 import org.opendaylight.yangtools.yang.data.impl.schema.tree.InMemoryDataTreeFactory;
28 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
29 import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
32 public class InMemoryDOMDataTreeShard implements WriteableDOMDataTreeShard, SchemaContextListener {
34 private static final class SubshardProducerSpecification {
35 private final Collection<DOMDataTreeIdentifier> prefixes = new ArrayList<>(1);
36 private final ChildShardContext shard;
38 SubshardProducerSpecification(final ChildShardContext subshard) {
39 this.shard = Preconditions.checkNotNull(subshard);
42 void addPrefix(final DOMDataTreeIdentifier prefix) {
46 DOMDataTreeShardProducer createProducer() {
47 return shard.getShard().createProducer(prefixes);
50 public DOMDataTreeIdentifier getPrefix() {
51 return shard.getPrefix();
55 private static final class ChildShardContext {
56 private final WriteableDOMDataTreeShard shard;
57 private final DOMDataTreeIdentifier prefix;
59 public ChildShardContext(final DOMDataTreeIdentifier prefix, final WriteableDOMDataTreeShard shard) {
60 this.prefix = Preconditions.checkNotNull(prefix);
61 this.shard = Preconditions.checkNotNull(shard);
64 public WriteableDOMDataTreeShard getShard() {
68 public DOMDataTreeIdentifier getPrefix() {
73 private final DOMDataTreePrefixTable<ChildShardContext> childShardsTable = DOMDataTreePrefixTable.create();
74 private final Map<DOMDataTreeIdentifier, ChildShardContext> childShards = new HashMap<>();
75 private final DOMDataTreeIdentifier prefix;
76 private final DataTree dataTree;
78 private InMemoryDOMDataTreeShard(final DOMDataTreeIdentifier prefix) {
79 this.prefix = Preconditions.checkNotNull(prefix);
81 final TreeType treeType = treeTypeFor(prefix.getDatastoreType());
82 this.dataTree = prefix.getRootIdentifier().isEmpty() ? InMemoryDataTreeFactory.getInstance().create(treeType)
83 : InMemoryDataTreeFactory.getInstance().create(treeType, prefix.getRootIdentifier());
86 public static InMemoryDOMDataTreeShard create(final DOMDataTreeIdentifier id) {
87 return new InMemoryDOMDataTreeShard(id);
91 public void onGlobalContextUpdated(final SchemaContext context) {
92 dataTree.setSchemaContext(context);
96 public void onChildAttached(final DOMDataTreeIdentifier prefix, final DOMDataTreeShard child) {
97 Preconditions.checkArgument(child != this, "Attempted to attach child %s onto self", this);
98 reparentChildShards(prefix, child);
99 addChildShard(prefix, child);
103 public void onChildDetached(final DOMDataTreeIdentifier prefix, final DOMDataTreeShard child) {
104 childShards.remove(prefix);
108 public InMemoryDOMDataTreeShardProducer createProducer(final Collection<DOMDataTreeIdentifier> prefixes) {
109 for (DOMDataTreeIdentifier prodPrefix : prefixes) {
110 Preconditions.checkArgument(prefix.contains(prodPrefix), "Prefix %s is not contained under shart root",
113 return new InMemoryDOMDataTreeShardProducer(this, prefixes);
116 private void addChildShard(final DOMDataTreeIdentifier prefix, final DOMDataTreeShard child) {
117 ChildShardContext context = createContextFor(prefix, child);
118 childShards.put(prefix, context);
119 childShardsTable.store(prefix, context);
122 private void reparentChildShards(final DOMDataTreeIdentifier newChildPrefix, final DOMDataTreeShard newChild) {
123 Iterator<Entry<DOMDataTreeIdentifier, ChildShardContext>> actualChildren = childShards.entrySet().iterator();
124 Map<DOMDataTreeIdentifier, ChildShardContext> reparented = new HashMap<>();
125 while (actualChildren.hasNext()) {
126 final Entry<DOMDataTreeIdentifier, ChildShardContext> actualChild = actualChildren.next();
127 final DOMDataTreeIdentifier actualPrefix = actualChild.getKey();
128 Preconditions.checkArgument(!newChildPrefix.equals(actualPrefix),
129 "Child shard with prefix %s already attached", newChildPrefix);
130 if (newChildPrefix.contains(actualPrefix)) {
131 ChildShardContext actualContext = actualChild.getValue();
132 actualChildren.remove();
133 newChild.onChildAttached(actualPrefix, actualContext.getShard());
134 reparented.put(actualChild.getKey(), actualContext);
135 childShardsTable.remove(actualPrefix);
138 updateProducersAndListeners(reparented);
141 private void updateProducersAndListeners(final Map<DOMDataTreeIdentifier, ChildShardContext> reparented) {
142 // FIXME: remove reparenting of producers, shards have to be registered from top to bottom
143 if (reparented.isEmpty()) {
144 //nothing was reparented no need to update anything
147 throw new UnsupportedOperationException();
150 private static ChildShardContext createContextFor(final DOMDataTreeIdentifier prefix, final DOMDataTreeShard child) {
151 Preconditions.checkArgument(child instanceof WriteableDOMDataTreeShard,
152 "Child %s is not a writable shared", child);
153 return new ChildShardContext(prefix, (WriteableDOMDataTreeShard) child);
156 private static TreeType treeTypeFor(final LogicalDatastoreType dsType) {
159 return TreeType.CONFIGURATION;
161 return TreeType.OPERATIONAL;
163 throw new IllegalArgumentException("Unsupported Data Store type:" + dsType);
168 Map<DOMDataTreeIdentifier, DOMDataTreeShard> getChildShards() {
169 Map<DOMDataTreeIdentifier, DOMDataTreeShard> ret = new HashMap<>();
170 for (Entry<DOMDataTreeIdentifier, ChildShardContext> entry : childShards.entrySet()) {
171 ret.put(entry.getKey(), entry.getValue().getShard());
176 InmemoryDOMDataTreeShardWriteTransaction createTransaction(final InmemoryDOMDataTreeShardWriteTransaction previousTx) {
177 // FIXME: implement this
178 throw new UnsupportedOperationException();
181 InmemoryDOMDataTreeShardWriteTransaction createTransaction(final Collection<DOMDataTreeIdentifier> prefixes) {
183 Map<DOMDataTreeIdentifier, SubshardProducerSpecification> affectedSubshards = new HashMap<>();
184 for (DOMDataTreeIdentifier producerPrefix : prefixes) {
185 for (ChildShardContext maybeAffected : childShards.values()) {
186 final DOMDataTreeIdentifier bindPath;
187 if (producerPrefix.contains(maybeAffected.getPrefix())) {
188 bindPath = maybeAffected.getPrefix();
189 } else if (maybeAffected.getPrefix().contains(producerPrefix)) {
190 // Bound path is inside subshard
191 bindPath = producerPrefix;
196 SubshardProducerSpecification spec = affectedSubshards.get(maybeAffected.getPrefix());
198 spec = new SubshardProducerSpecification(maybeAffected);
199 affectedSubshards.put(maybeAffected.getPrefix(), spec);
201 spec.addPrefix(bindPath);
205 ShardRootModificationContext rootContext = new ShardRootModificationContext(prefix,
206 (CursorAwareDataTreeSnapshot) dataTree.takeSnapshot());
207 ShardDataModificationBuilder builder = new ShardDataModificationBuilder(rootContext);
208 for (SubshardProducerSpecification spec : affectedSubshards.values()) {
209 ForeignShardModificationContext foreignContext =
210 new ForeignShardModificationContext(spec.getPrefix(), spec.createProducer());
211 builder.addSubshard(foreignContext);
212 builder.addSubshard(spec.getPrefix(), foreignContext);
215 return new InmemoryDOMDataTreeShardWriteTransaction(builder.build(), dataTree);