blob: e31653ef6e3244b7b5bb26865b8f7015b71ca04f [file] [log] [blame]
Aaron Kruglikov61582a02016-09-06 13:18:58 -07001/*
2 * Copyright 2016 Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.onosproject.store.primitives.impl;
18
19import com.google.common.collect.ImmutableMultiset;
20import com.google.common.collect.Maps;
21import com.google.common.collect.Multiset;
22import org.onlab.util.Tools;
23import org.onosproject.store.service.AsyncConsistentMultimap;
24import org.onosproject.store.service.Versioned;
25
26import java.util.Collection;
27import java.util.EnumSet;
28import java.util.Map;
29import java.util.Set;
30import java.util.concurrent.CompletableFuture;
31import java.util.function.BiConsumer;
32import java.util.function.BinaryOperator;
33import java.util.function.Consumer;
34import java.util.function.Function;
35import java.util.function.Supplier;
36import java.util.stream.Collector;
37import java.util.stream.Collectors;
38
39/**
40 * An {@link AsyncConsistentMultimap} that maps its operation to operations to
41 * a differently typed {@link AsyncConsistentMultimap} by transcoding operation
42 * inputs and outputs while maintaining version numbers.
43 *
44 * @param <K2> key type of other map
45 * @param <V2> value type of other map
46 * @param <K1> key type of this map
47 * @param <V1> value type of this map
48 */
49public class TranscodingAsyncConsistentMultimap<K1, V1, K2, V2>
50 implements AsyncConsistentMultimap<K1, V1> {
51
52 private final AsyncConsistentMultimap<K2, V2> backingMap;
53 private final Function<K1, K2> keyEncoder;
54 private final Function<K2, K1> keyDecoder;
55 private final Function<V2, V1> valueDecoder;
56 private final Function<V1, V2> valueEncoder;
57 private final Function<? extends Versioned<V2>,
58 ? extends Versioned<V1>> versionedValueTransform;
59 private final Function<Versioned<Collection<? extends V2>>,
60 Versioned<Collection<? extends V1>>> versionedValueCollectionDecode;
61 private final Function<Collection<? extends V1>, Collection<V2>>
62 valueCollectionEncode;
63
64 public TranscodingAsyncConsistentMultimap(
65 AsyncConsistentMultimap<K2, V2> backingMap,
66 Function<K1, K2> keyEncoder,
67 Function<K2, K1> keyDecoder,
68 Function<V2, V1> valueDecoder,
69 Function<V1, V2> valueEncoder) {
70 this.backingMap = backingMap;
71 this.keyEncoder = k -> k == null ? null : keyEncoder.apply(k);
72 this.keyDecoder = k -> k == null ? null : keyDecoder.apply(k);
73 this.valueDecoder = v -> v == null ? null : valueDecoder.apply(v);
74 this.valueEncoder = v -> v == null ? null : valueEncoder.apply(v);
75 this.versionedValueTransform = v -> v == null ? null :
76 v.map(valueDecoder);
77 this.versionedValueCollectionDecode = v -> v == null ? null :
78 new Versioned<>(
79 v.value()
80 .stream()
81 .map(valueDecoder)
82 .collect(Collectors.toSet()),
83 v.version(),
84 v.creationTime());
85 this.valueCollectionEncode = v -> v == null ? null :
86 v.stream().map(valueEncoder).collect(Collectors.toSet());
87 }
88
89 @Override
90 public CompletableFuture<Integer> size() {
91 return backingMap.size();
92 }
93
94 @Override
95 public CompletableFuture<Boolean> isEmpty() {
96 return backingMap.isEmpty();
97 }
98
99 @Override
100 public CompletableFuture<Boolean> containsKey(K1 key) {
101 try {
102 return backingMap.containsKey(keyEncoder.apply(key));
103 } catch (Exception e) {
104 return Tools.exceptionalFuture(e);
105 }
106 }
107
108 @Override
109 public CompletableFuture<Boolean> containsValue(V1 value) {
110 try {
111 return backingMap.containsValue(valueEncoder.apply(value));
112 } catch (Exception e) {
113 return Tools.exceptionalFuture(e);
114 }
115 }
116
117 @Override
118 public CompletableFuture<Boolean> containsEntry(K1 key, V1 value) {
119 try {
120 return backingMap.containsEntry(keyEncoder.apply(key),
121 valueEncoder.apply(value));
122 } catch (Exception e) {
123 return Tools.exceptionalFuture(e);
124 }
125 }
126
127 @Override
128 public CompletableFuture<Boolean> put(K1 key, V1 value) {
129 try {
130 return backingMap.put(keyEncoder.apply(key),
131 valueEncoder.apply(value));
132 } catch (Exception e) {
133 return Tools.exceptionalFuture(e);
134 }
135 }
136
137 @Override
138 public CompletableFuture<Boolean> remove(K1 key, V1 value) {
139 try {
140 return backingMap.remove(keyEncoder.apply(key), valueEncoder
141 .apply(value));
142 } catch (Exception e) {
143 return Tools.exceptionalFuture(e);
144 }
145 }
146
147 @Override
148 public CompletableFuture<Boolean> removeAll(
149 K1 key, Collection<? extends V1> values) {
150 try {
151 return backingMap.removeAll(
152 keyEncoder.apply(key),
153 values.stream().map(valueEncoder).collect(
154 Collectors.toSet()));
155 } catch (Exception e) {
156 return Tools.exceptionalFuture(e);
157 }
158 }
159
160 @Override
161 public CompletableFuture<Versioned<Collection<? extends V1>>>
162 removeAll(K1 key) {
163 try {
164 return backingMap.removeAll(keyEncoder.apply(key))
165 .thenApply(versionedValueCollectionDecode);
166 } catch (Exception e) {
167 return Tools.exceptionalFuture(e);
168 }
169 }
170
171 @Override
172 public CompletableFuture<Boolean>
173 putAll(K1 key, Collection<? extends V1> values) {
174 try {
175 return backingMap.putAll(keyEncoder.apply(key),
176 valueCollectionEncode.apply(values));
177 } catch (Exception e) {
178 return Tools.exceptionalFuture(e);
179 }
180 }
181
182 @Override
183 public CompletableFuture<Versioned<Collection<? extends V1>>>
184 replaceValues(K1 key, Collection<V1> values) {
185 try {
186 return backingMap.replaceValues(keyEncoder.apply(key),
187 valueCollectionEncode.apply(values))
188 .thenApply(versionedValueCollectionDecode);
189 } catch (Exception e) {
190 return Tools.exceptionalFuture(e);
191 }
192 }
193
194 @Override
195 public CompletableFuture<Void> clear() {
196 return backingMap.clear();
197 }
198
199 @Override
200 public CompletableFuture<Versioned<Collection<? extends V1>>> get(K1 key) {
201 try {
202 return backingMap.get(keyEncoder.apply(key))
203 .thenApply(versionedValueCollectionDecode);
204 } catch (Exception e) {
205 return Tools.exceptionalFuture(e);
206 }
207 }
208
209 @Override
210 public CompletableFuture<Set<K1>> keySet() {
211 return backingMap.keySet().thenApply(s -> s.stream()
212 .map(keyDecoder)
213 .collect(Collectors.toSet()));
214 }
215
216 @Override
217 public CompletableFuture<Multiset<K1>> keys() {
218 return backingMap.keys().thenApply(s -> s.stream().map(keyDecoder)
219 .collect(new MultisetCollector<>()));
220 }
221
222 @Override
223 public CompletableFuture<Multiset<V1>> values() {
224 return backingMap.values().thenApply(s -> s.stream().map(valueDecoder)
225 .collect(new MultisetCollector<>()));
226 }
227
228 @Override
229 public CompletableFuture<Collection<Map.Entry<K1, V1>>> entries() {
230 return backingMap.entries().thenApply(s -> s.stream()
231 .map(e -> Maps.immutableEntry(keyDecoder.apply(e.getKey()),
232 valueDecoder.apply(e.getValue())))
233 .collect(Collectors.toSet()));
234 }
235
236 @Override
237 public CompletableFuture<Map<K1, Collection<V1>>> asMap() {
238 throw new UnsupportedOperationException("Unsupported operation.");
239 }
240
241 @Override
242 public String name() {
243 return backingMap.name();
244 }
245
246 @Override
247 public void addStatusChangeListener(Consumer<Status> listener) {
248 backingMap.addStatusChangeListener(listener);
249 }
250
251 @Override
252 public void removeStatusChangeListener(Consumer<Status> listener) {
253 backingMap.removeStatusChangeListener(listener);
254 }
255
256 @Override
257 public Collection<Consumer<Status>> statusChangeListeners() {
258 return backingMap.statusChangeListeners();
259 }
260
261 private class MultisetCollector<T> implements Collector<T,
262 ImmutableMultiset.Builder<T>,
263 Multiset<T>> {
264
265 @Override
266 public Supplier<ImmutableMultiset.Builder<T>> supplier() {
267 return ImmutableMultiset::builder;
268 }
269
270 @Override
271 public BiConsumer<ImmutableMultiset.Builder<T>, T> accumulator() {
272 return ((builder, t) -> builder.add(t));
273 }
274
275 @Override
276 public BinaryOperator<ImmutableMultiset.Builder<T>> combiner() {
277 return (a, b) -> {
278 a.addAll(b.build());
279 return a;
280 };
281 }
282
283 @Override
284 public Function<ImmutableMultiset.Builder<T>, Multiset<T>> finisher() {
285 return ImmutableMultiset.Builder::build;
286 }
287
288 @Override
289 public Set<Characteristics> characteristics() {
290 return EnumSet.of(Characteristics.UNORDERED);
291 }
292 }
293}