Encapsulate ShardedDOMDataTreeProducer layout
[mdsal.git] / dom / mdsal-dom-broker / src / main / java / org / opendaylight / mdsal / dom / broker / ProducerLayout.java
1 /*
2  * Copyright (c) 2015 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 package org.opendaylight.mdsal.dom.broker;
9
10 import com.google.common.base.Preconditions;
11 import com.google.common.collect.ArrayListMultimap;
12 import com.google.common.collect.BiMap;
13 import com.google.common.collect.ImmutableBiMap;
14 import com.google.common.collect.ImmutableBiMap.Builder;
15 import com.google.common.collect.ImmutableMap;
16 import com.google.common.collect.Maps;
17 import com.google.common.collect.Multimap;
18 import java.util.ArrayList;
19 import java.util.Collection;
20 import java.util.Map;
21 import java.util.Map.Entry;
22 import java.util.Set;
23 import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier;
24 import org.opendaylight.mdsal.dom.api.DOMDataTreeProducer;
25 import org.opendaylight.mdsal.dom.api.DOMDataTreeShard;
26 import org.opendaylight.mdsal.dom.store.inmemory.DOMDataTreeShardProducer;
27 import org.opendaylight.mdsal.dom.store.inmemory.DOMDataTreeShardWriteTransaction;
28 import org.opendaylight.mdsal.dom.store.inmemory.WriteableDOMDataTreeShard;
29 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
30 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33
34 final class ProducerLayout {
35     private static final Logger LOG = LoggerFactory.getLogger(ProducerLayout.class);
36
37     private final BiMap<DOMDataTreeIdentifier, DOMDataTreeShardProducer> idToProducer;
38     private final Map<DOMDataTreeIdentifier, DOMDataTreeProducer> children;
39     private final Map<DOMDataTreeIdentifier, DOMDataTreeShard> shardMap;
40
41     private ProducerLayout(final Map<DOMDataTreeIdentifier, DOMDataTreeShard> shardMap,
42             final BiMap<DOMDataTreeIdentifier, DOMDataTreeShardProducer> idToProducer,
43             final Map<DOMDataTreeIdentifier, DOMDataTreeProducer> children) {
44         this.shardMap = ImmutableMap.copyOf(shardMap);
45         this.idToProducer = Preconditions.checkNotNull(idToProducer);
46         this.children = Preconditions.checkNotNull(children);
47     }
48
49     static ProducerLayout create(final Map<DOMDataTreeIdentifier, DOMDataTreeShard> shardMap) {
50         return new ProducerLayout(shardMap, mapIdsToProducer(shardMap), ImmutableMap.of());
51     }
52
53     private static BiMap<DOMDataTreeIdentifier, DOMDataTreeShardProducer> mapIdsToProducer(
54             final Map<DOMDataTreeIdentifier, DOMDataTreeShard> shardMap) {
55         final Multimap<DOMDataTreeShard, DOMDataTreeIdentifier> shardToId = ArrayListMultimap.create();
56         // map which identifier belongs to which shard
57         for (final Entry<DOMDataTreeIdentifier, DOMDataTreeShard> entry : shardMap.entrySet()) {
58             shardToId.put(entry.getValue(), entry.getKey());
59         }
60
61         final Builder<DOMDataTreeIdentifier, DOMDataTreeShardProducer> idToProducerBuilder = ImmutableBiMap.builder();
62         for (final Entry<DOMDataTreeShard, Collection<DOMDataTreeIdentifier>> entry : shardToId.asMap().entrySet()) {
63             if (entry.getKey() instanceof WriteableDOMDataTreeShard) {
64                 //create a single producer for all prefixes in a single shard
65                 final DOMDataTreeShardProducer producer = ((WriteableDOMDataTreeShard) entry.getKey())
66                         .createProducer(entry.getValue());
67                 // id mapped to producers
68                 for (final DOMDataTreeIdentifier id : entry.getValue()) {
69                     idToProducerBuilder.put(id, producer);
70                 }
71             } else {
72                 LOG.error("Unable to create a producer for shard that's not a WriteableDOMDataTreeShard");
73             }
74         }
75
76         return idToProducerBuilder.build();
77     }
78
79     ProducerLayout addChild(final DOMDataTreeProducer producer, final Collection<DOMDataTreeIdentifier> subtrees) {
80         final ImmutableMap.Builder<DOMDataTreeIdentifier, DOMDataTreeProducer> cb = ImmutableMap.builder();
81         cb.putAll(children);
82         for (final DOMDataTreeIdentifier s : subtrees) {
83             cb.put(s, producer);
84         }
85
86         return new ProducerLayout(shardMap, idToProducer, cb.build());
87     }
88
89     ProducerLayout reshard(final Map<DOMDataTreeIdentifier, DOMDataTreeShard> shardMap) {
90         return new ProducerLayout(shardMap, mapIdsToProducer(shardMap), children);
91     }
92
93     boolean haveSubtree(final DOMDataTreeIdentifier subtree) {
94         for (final DOMDataTreeIdentifier i : shardMap.keySet()) {
95             if (i.contains(subtree)) {
96                 return true;
97             }
98         }
99
100         return false;
101     }
102
103     DOMDataTreeProducer lookupChild(final DOMDataTreeIdentifier path) {
104         for (final Entry<DOMDataTreeIdentifier, DOMDataTreeProducer> e : children.entrySet()) {
105             if (e.getKey().contains(path)) {
106                 // FIXME: does this match wildcards?
107                 return e.getValue();
108             }
109         }
110
111         return null;
112     }
113
114     Set<DOMDataTreeIdentifier> getChildTrees() {
115         return children.keySet();
116     }
117
118     void checkAvailable(final Collection<PathArgument> base, final PathArgument child) {
119         if (!children.isEmpty()) {
120             final Collection<PathArgument> args = new ArrayList<>(base.size() + 1);
121             args.addAll(base);
122             args.add(child);
123
124             final YangInstanceIdentifier path = YangInstanceIdentifier.create(args);
125             for (final DOMDataTreeIdentifier c : children.keySet()) {
126                 Preconditions.checkArgument(!c.getRootIdentifier().contains(path),
127                     "Path {%s} is not available to this cursor since it's already claimed by a child producer", path);
128             }
129         }
130     }
131
132     Map<DOMDataTreeIdentifier, DOMDataTreeShardWriteTransaction> createTransactions() {
133         return Maps.transformValues(idToProducer, DOMDataTreeShardProducer::createTransaction);
134     }
135 }