Fix odlparent-3.0.0 checkstyle issues
[mdsal.git] / dom / mdsal-dom-inmemory-datastore / src / main / java / org / opendaylight / mdsal / dom / store / inmemory / InMemoryDOMDataTreeShard.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.mdsal.dom.store.inmemory;
10
11 import com.google.common.annotations.Beta;
12 import com.google.common.annotations.VisibleForTesting;
13 import com.google.common.base.Preconditions;
14 import com.google.common.collect.ImmutableMap;
15 import com.google.common.collect.Maps;
16 import com.google.common.util.concurrent.ListeningExecutorService;
17 import com.google.common.util.concurrent.MoreExecutors;
18 import java.util.Collection;
19 import java.util.HashMap;
20 import java.util.HashSet;
21 import java.util.Iterator;
22 import java.util.Map;
23 import java.util.Map.Entry;
24 import java.util.concurrent.Executor;
25 import javax.annotation.Nonnull;
26 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
27 import org.opendaylight.mdsal.dom.api.DOMDataTreeChangeListener;
28 import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier;
29 import org.opendaylight.mdsal.dom.api.DOMDataTreeShard;
30 import org.opendaylight.mdsal.dom.spi.DOMDataTreePrefixTable;
31 import org.opendaylight.mdsal.dom.spi.shard.ChildShardContext;
32 import org.opendaylight.mdsal.dom.spi.shard.ForeignShardModificationContext;
33 import org.opendaylight.mdsal.dom.spi.shard.ReadableWriteableDOMDataTreeShard;
34 import org.opendaylight.mdsal.dom.spi.shard.SubshardProducerSpecification;
35 import org.opendaylight.mdsal.dom.spi.shard.WriteableDOMDataTreeShard;
36 import org.opendaylight.yangtools.concepts.ListenerRegistration;
37 import org.opendaylight.yangtools.util.concurrent.CountingRejectedExecutionHandler;
38 import org.opendaylight.yangtools.util.concurrent.FastThreadPoolExecutor;
39 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
40 import org.opendaylight.yangtools.yang.data.api.schema.tree.CursorAwareDataTreeSnapshot;
41 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree;
42 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot;
43 import org.opendaylight.yangtools.yang.data.api.schema.tree.TreeType;
44 import org.opendaylight.yangtools.yang.data.impl.schema.tree.InMemoryDataTreeFactory;
45 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
46 import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
47 import org.slf4j.Logger;
48 import org.slf4j.LoggerFactory;
49
50 @Beta
51 public class InMemoryDOMDataTreeShard implements ReadableWriteableDOMDataTreeShard, SchemaContextListener {
52
53     private static final Logger LOG = LoggerFactory.getLogger(InMemoryDOMDataTreeShard.class);
54     private static final int DEFAULT_SUBMIT_QUEUE_SIZE = 1000;
55
56     private final DOMDataTreePrefixTable<ChildShardContext> childShardsTable = DOMDataTreePrefixTable.create();
57     private final Map<DOMDataTreeIdentifier, ChildShardContext> childShards = new HashMap<>();
58     private final Collection<InMemoryDOMDataTreeShardProducer> producers = new HashSet<>();
59     private final InMemoryDOMDataTreeShardChangePublisher shardChangePublisher;
60     private final ListeningExecutorService executor;
61     private final DOMDataTreeIdentifier prefix;
62     private final DataTree dataTree;
63
64     InMemoryDOMDataTreeShard(final DOMDataTreeIdentifier prefix, final Executor dataTreeChangeExecutor,
65             final int maxDataChangeListenerQueueSize, final int submitQueueSize) {
66         this.prefix = Preconditions.checkNotNull(prefix);
67
68         final TreeType treeType = treeTypeFor(prefix.getDatastoreType());
69         this.dataTree = InMemoryDataTreeFactory.getInstance().create(treeType, prefix.getRootIdentifier());
70
71         this.shardChangePublisher = new InMemoryDOMDataTreeShardChangePublisher(dataTreeChangeExecutor,
72                 maxDataChangeListenerQueueSize, dataTree, prefix.getRootIdentifier(), childShards);
73
74         final FastThreadPoolExecutor fte = new FastThreadPoolExecutor(1, submitQueueSize, "Shard[" + prefix + "]");
75         fte.setRejectedExecutionHandler(CountingRejectedExecutionHandler.newCallerWaitsPolicy());
76         this.executor = MoreExecutors.listeningDecorator(fte);
77     }
78
79     public static InMemoryDOMDataTreeShard create(final DOMDataTreeIdentifier id,
80                                                   final Executor dataTreeChangeExecutor,
81                                                   final int maxDataChangeListenerQueueSize) {
82         return new InMemoryDOMDataTreeShard(id.toOptimized(), dataTreeChangeExecutor,
83                 maxDataChangeListenerQueueSize, DEFAULT_SUBMIT_QUEUE_SIZE);
84     }
85
86     public static InMemoryDOMDataTreeShard create(final DOMDataTreeIdentifier id,
87                                                   final Executor dataTreeChangeExecutor,
88                                                   final int maxDataChangeListenerQueueSize,
89                                                   final int submitQueueSize) {
90         return new InMemoryDOMDataTreeShard(id.toOptimized(), dataTreeChangeExecutor,
91                 maxDataChangeListenerQueueSize, submitQueueSize);
92     }
93
94     @Override
95     public void onGlobalContextUpdated(final SchemaContext context) {
96         dataTree.setSchemaContext(context);
97     }
98
99     @Override
100     public void onChildAttached(final DOMDataTreeIdentifier childPrefix, final DOMDataTreeShard child) {
101         Preconditions.checkArgument(child != this, "Attempted to attach child %s onto self", this);
102         reparentChildShards(childPrefix, child);
103
104         final ChildShardContext context = createContextFor(childPrefix, child);
105         childShards.put(childPrefix, context);
106         childShardsTable.store(childPrefix, context);
107         updateProducers();
108     }
109
110     @Override
111     public void onChildDetached(final DOMDataTreeIdentifier childPrefix, final DOMDataTreeShard child) {
112         childShards.remove(childPrefix);
113         childShardsTable.remove(childPrefix);
114         updateProducers();
115     }
116
117     private void updateProducers() {
118         for (InMemoryDOMDataTreeShardProducer p : producers) {
119             p.setModificationFactory(createModificationFactory(p.getPrefixes()));
120         }
121     }
122
123     @VisibleForTesting
124     InMemoryShardDataModificationFactory createModificationFactory(final Collection<DOMDataTreeIdentifier> prefixes) {
125         final Map<DOMDataTreeIdentifier, SubshardProducerSpecification> affected = new HashMap<>();
126         for (final DOMDataTreeIdentifier producerPrefix : prefixes) {
127             for (final ChildShardContext child : childShards.values()) {
128                 final DOMDataTreeIdentifier bindPath;
129                 if (producerPrefix.contains(child.getPrefix())) {
130                     bindPath = child.getPrefix();
131                 } else if (child.getPrefix().contains(producerPrefix)) {
132                     // Bound path is inside subshard
133                     bindPath = producerPrefix;
134                 } else {
135                     continue;
136                 }
137
138                 SubshardProducerSpecification spec = affected.get(child.getPrefix());
139                 if (spec == null) {
140                     spec = new SubshardProducerSpecification(child);
141                     affected.put(child.getPrefix(), spec);
142                 }
143                 spec.addPrefix(bindPath);
144             }
145         }
146
147         final InmemoryShardDataModificationFactoryBuilder builder =
148                 new InmemoryShardDataModificationFactoryBuilder(prefix);
149         for (final SubshardProducerSpecification spec : affected.values()) {
150             final ForeignShardModificationContext foreignContext =
151                     new ForeignShardModificationContext(spec.getPrefix(), spec.createProducer());
152             builder.addSubshard(foreignContext);
153             builder.addSubshard(spec.getPrefix(), foreignContext);
154         }
155
156         return builder.build();
157     }
158
159     @Override
160     public InMemoryDOMDataTreeShardProducer createProducer(final Collection<DOMDataTreeIdentifier> prefixes) {
161         for (final DOMDataTreeIdentifier prodPrefix : prefixes) {
162             Preconditions.checkArgument(prefix.contains(prodPrefix), "Prefix %s is not contained under shart root",
163                     prodPrefix, prefix);
164         }
165
166         final InMemoryDOMDataTreeShardProducer ret = new InMemoryDOMDataTreeShardProducer(this, prefixes,
167                 createModificationFactory(prefixes));
168         producers.add(ret);
169         return ret;
170     }
171
172     void closeProducer(final InMemoryDOMDataTreeShardProducer producer) {
173         if (!producers.remove(producer)) {
174             LOG.warn("Producer {} not found in shard {}", producer, this);
175         }
176     }
177
178     @Nonnull
179     @Override
180     public <L extends DOMDataTreeChangeListener> ListenerRegistration<L> registerTreeChangeListener(
181             @Nonnull final YangInstanceIdentifier treeId, @Nonnull final L listener) {
182         return shardChangePublisher.registerTreeChangeListener(treeId, listener);
183     }
184
185     private void reparentChildShards(final DOMDataTreeIdentifier newChildPrefix, final DOMDataTreeShard newChild) {
186         final Iterator<Entry<DOMDataTreeIdentifier, ChildShardContext>> actualChildren =
187                 childShards.entrySet().iterator();
188         final Map<DOMDataTreeIdentifier, ChildShardContext> reparented = new HashMap<>();
189         while (actualChildren.hasNext()) {
190             final Entry<DOMDataTreeIdentifier, ChildShardContext> actualChild = actualChildren.next();
191             final DOMDataTreeIdentifier actualPrefix = actualChild.getKey();
192             Preconditions.checkArgument(!newChildPrefix.equals(actualPrefix),
193                     "Child shard with prefix %s already attached", newChildPrefix);
194             if (newChildPrefix.contains(actualPrefix)) {
195                 final ChildShardContext actualContext = actualChild.getValue();
196                 actualChildren.remove();
197                 newChild.onChildAttached(actualPrefix, actualContext.getShard());
198                 reparented.put(actualChild.getKey(), actualContext);
199                 childShardsTable.remove(actualPrefix);
200             }
201         }
202         updateProducersAndListeners(reparented);
203     }
204
205     private void updateProducersAndListeners(final Map<DOMDataTreeIdentifier, ChildShardContext> reparented) {
206         // FIXME: remove reparenting of producers, shards have to be registered from top to bottom
207         if (reparented.isEmpty()) {
208             //nothing was reparented no need to update anything
209             return;
210         }
211         throw new UnsupportedOperationException();
212     }
213
214     private static ChildShardContext createContextFor(final DOMDataTreeIdentifier prefix,
215                                                       final DOMDataTreeShard child) {
216         Preconditions.checkArgument(child instanceof WriteableDOMDataTreeShard,
217                 "Child %s is not a writable shared", child);
218         return new ChildShardContext(prefix, (WriteableDOMDataTreeShard) child);
219     }
220
221     private static TreeType treeTypeFor(final LogicalDatastoreType dsType) {
222         switch (dsType) {
223             case CONFIGURATION:
224                 return TreeType.CONFIGURATION;
225             case OPERATIONAL:
226                 return TreeType.OPERATIONAL;
227             default:
228                 throw new IllegalArgumentException("Unsupported Data Store type:" + dsType);
229         }
230     }
231
232     @VisibleForTesting
233     Map<DOMDataTreeIdentifier, DOMDataTreeShard> getChildShards() {
234         return ImmutableMap.copyOf(Maps.transformValues(childShards, ChildShardContext::getShard));
235     }
236
237     DataTreeSnapshot takeSnapshot() {
238         return dataTree.takeSnapshot();
239     }
240
241     InmemoryDOMDataTreeShardWriteTransaction createTransaction(final String transactionId,
242             final InMemoryDOMDataTreeShardProducer producer, final DataTreeSnapshot snapshot) {
243         Preconditions.checkArgument(snapshot instanceof CursorAwareDataTreeSnapshot);
244
245         return new InmemoryDOMDataTreeShardWriteTransaction(producer,
246                 producer.getModificationFactory().createModification((CursorAwareDataTreeSnapshot) snapshot), dataTree,
247                 shardChangePublisher, executor);
248     }
249 }