blob: fcaca0ebe233d41a1d0e8febbc66741c84c38a83 [file] [log] [blame]
Aaron Kruglikoved88ff62016-08-01 16:02:09 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Aaron Kruglikoved88ff62016-08-01 16:02:09 -07003 *
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.Maps;
20import org.onlab.util.Tools;
Jordan Halterman948d6592017-04-20 17:18:24 -070021import org.onosproject.store.primitives.MapUpdate;
Aaron Kruglikoved88ff62016-08-01 16:02:09 -070022import org.onosproject.store.primitives.TransactionId;
23import org.onosproject.store.service.AsyncConsistentTreeMap;
24import org.onosproject.store.service.MapEvent;
25import org.onosproject.store.service.MapEventListener;
Jordan Halterman948d6592017-04-20 17:18:24 -070026import org.onosproject.store.service.TransactionLog;
27import org.onosproject.store.service.Version;
Aaron Kruglikoved88ff62016-08-01 16:02:09 -070028import org.onosproject.store.service.Versioned;
29
30import java.util.Collection;
31import java.util.Map;
32import java.util.NavigableMap;
33import java.util.NavigableSet;
34import java.util.Set;
35import java.util.concurrent.CompletableFuture;
36import java.util.concurrent.Executor;
37import java.util.function.BiFunction;
38import java.util.function.Function;
39import java.util.function.Predicate;
40import java.util.stream.Collectors;
41
42/**
Aaron Kruglikovb06078c2016-08-30 17:28:00 -070043 * An {@code AsyncConsistentTreeMap} that maps its operations to operations on
44 * a differently typed {@code AsyncConsistentTreeMap} by transcoding operation
45 * inputs and outputs.
46 *
47 * @param <V2> value type of other map
48 * @param <V1> value type of this map
Aaron Kruglikoved88ff62016-08-01 16:02:09 -070049 */
50public class TranscodingAsyncConsistentTreeMap<V1, V2>
51 implements AsyncConsistentTreeMap<V1> {
52 private final AsyncConsistentTreeMap<V2> backingMap;
53 private final Function<V2, V1> valueDecoder;
54 private final Function<V1, V2> valueEncoder;
55 private final Function<Versioned<V2>, Versioned<V1>>
56 versionedValueTransform;
57 private final Map<MapEventListener<String, V1>,
58 TranscodingAsyncConsistentTreeMap.InternalBackingMapEventListener>
59 listeners = Maps.newIdentityHashMap();
60
61 public TranscodingAsyncConsistentTreeMap(
62 AsyncConsistentTreeMap<V2> backingMap,
63 Function<V1, V2> valueEncoder,
64 Function<V2, V1> valueDecoder) {
65 this.backingMap = backingMap;
66 this.valueEncoder = v -> v == null ? null : valueEncoder.apply(v);
67 this.valueDecoder = v -> v == null ? null : valueDecoder.apply(v);
68 this.versionedValueTransform = v -> v == null ? null :
69 v.map(valueDecoder);
70 }
Jordan Haltermanf6272442017-04-20 02:18:08 -070071
Aaron Kruglikoved88ff62016-08-01 16:02:09 -070072 @Override
73 public CompletableFuture<String> firstKey() {
74 return backingMap.firstKey();
75 }
76
77 @Override
78 public CompletableFuture<String> lastKey() {
79 return backingMap.lastKey();
80 }
81
82 @Override
83 public CompletableFuture<Map.Entry<String, Versioned<V1>>>
84 ceilingEntry(String key) {
85 return backingMap.ceilingEntry(key)
86 .thenApply(
87 entry ->
88 Maps.immutableEntry(
89 entry.getKey(),
Aaron Kruglikovb06078c2016-08-30 17:28:00 -070090 versionedValueTransform
91 .apply(entry.getValue())));
Aaron Kruglikoved88ff62016-08-01 16:02:09 -070092 }
93
94 @Override
95 public CompletableFuture<Map.Entry<String, Versioned<V1>>>
96 floorEntry(String key) {
97 return backingMap.floorEntry(key)
98 .thenApply(
99 entry ->
100 Maps.immutableEntry(
101 entry.getKey(),
Aaron Kruglikovb06078c2016-08-30 17:28:00 -0700102 versionedValueTransform
103 .apply(entry.getValue())));
Aaron Kruglikoved88ff62016-08-01 16:02:09 -0700104 }
105
106 @Override
107 public CompletableFuture<Map.Entry<String, Versioned<V1>>>
108 higherEntry(String key) {
109 return backingMap
110 .higherEntry(key)
111 .thenApply(entry ->
Aaron Kruglikovb06078c2016-08-30 17:28:00 -0700112 Maps.immutableEntry(
113 entry.getKey(),
114 versionedValueTransform
115 .apply(entry.getValue())));
116 }
Aaron Kruglikoved88ff62016-08-01 16:02:09 -0700117
118 @Override
119 public CompletableFuture<Map.Entry<String, Versioned<V1>>>
120 lowerEntry(String key) {
121 return backingMap.lowerEntry(key).thenApply(
122 entry ->
Aaron Kruglikovb06078c2016-08-30 17:28:00 -0700123 Maps.immutableEntry(
124 entry.getKey(),
125 versionedValueTransform
126 .apply(entry.getValue())));
Aaron Kruglikoved88ff62016-08-01 16:02:09 -0700127 }
128
129 @Override
130 public CompletableFuture<Map.Entry<String, Versioned<V1>>>
131 firstEntry() {
132 return backingMap.firstEntry()
133 .thenApply(entry ->
134 Maps.immutableEntry(
Aaron Kruglikovb06078c2016-08-30 17:28:00 -0700135 entry.getKey(),
136 versionedValueTransform
137 .apply(entry.getValue())));
Aaron Kruglikoved88ff62016-08-01 16:02:09 -0700138 }
139
140 @Override
141 public CompletableFuture<Map.Entry<String, Versioned<V1>>>
142 lastEntry() {
143 return backingMap.lastEntry()
144 .thenApply(
145 entry -> Maps.immutableEntry(
146 entry.getKey(),
Aaron Kruglikovb06078c2016-08-30 17:28:00 -0700147 versionedValueTransform
148 .apply(entry.getValue())));
Aaron Kruglikoved88ff62016-08-01 16:02:09 -0700149 }
150
151 @Override
152 public CompletableFuture<Map.Entry<String, Versioned<V1>>>
153 pollFirstEntry() {
154 return backingMap.pollFirstEntry()
155 .thenApply(
156 entry -> Maps.immutableEntry(
157 entry.getKey(),
Aaron Kruglikovb06078c2016-08-30 17:28:00 -0700158 versionedValueTransform
159 .apply(entry.getValue())));
Aaron Kruglikoved88ff62016-08-01 16:02:09 -0700160 }
161
162 @Override
163 public CompletableFuture<Map.Entry<String, Versioned<V1>>>
164 pollLastEntry() {
165 return backingMap.pollLastEntry()
166 .thenApply(entry -> Maps.immutableEntry(
167 entry.getKey(),
Aaron Kruglikovb06078c2016-08-30 17:28:00 -0700168 versionedValueTransform.apply(entry.getValue())));
Aaron Kruglikoved88ff62016-08-01 16:02:09 -0700169 }
170
171 @Override
172 public CompletableFuture<String> lowerKey(String key) {
173 return backingMap.lowerKey(key);
174 }
175
176 @Override
177 public CompletableFuture<String> floorKey(String key) {
178 return backingMap.floorKey(key);
179 }
180
181 @Override
182 public CompletableFuture<String> ceilingKey(String key) {
183 return backingMap.ceilingKey(key);
184 }
185
186 @Override
187 public CompletableFuture<String> higherKey(String key) {
188 return backingMap.higherKey(key);
189 }
190
191 @Override
192 public CompletableFuture<NavigableSet<String>> navigableKeySet() {
193 return backingMap.navigableKeySet();
194 }
195
196 @Override
197 public CompletableFuture<NavigableMap<String, V1>> subMap(
198 String upperKey,
199 String lowerKey,
200 boolean inclusiveUpper,
201 boolean inclusiveLower) {
202 throw new UnsupportedOperationException("This operation is not yet" +
203 "supported.");
204 }
205
206 @Override
207 public String name() {
208 return backingMap.name();
209 }
210
211 @Override
212 public CompletableFuture<Integer> size() {
213 return backingMap.size();
214 }
215
216 @Override
217 public CompletableFuture<Boolean> containsKey(String key) {
218 return backingMap.containsKey(key);
219 }
220
221 @Override
222 public CompletableFuture<Boolean> containsValue(V1 value) {
223 return backingMap.containsValue(valueEncoder.apply(value));
224 }
225
226 @Override
227 public CompletableFuture<Versioned<V1>> get(String key) {
Aaron Kruglikovb06078c2016-08-30 17:28:00 -0700228 return backingMap.get(key).thenApply(versionedValueTransform);
Aaron Kruglikoved88ff62016-08-01 16:02:09 -0700229 }
230
231 @Override
Jordan Haltermanf6272442017-04-20 02:18:08 -0700232 public CompletableFuture<Versioned<V1>> getOrDefault(String key, V1 defaultValue) {
233 return backingMap.getOrDefault(key, valueEncoder.apply(defaultValue)).thenApply(versionedValueTransform);
234 }
235
236 @Override
Aaron Kruglikoved88ff62016-08-01 16:02:09 -0700237 public CompletableFuture<Versioned<V1>> computeIf(
238 String key, Predicate<? super V1> condition,
239 BiFunction<? super String, ? super V1, ? extends V1>
240 remappingFunction) {
241 try {
242 return backingMap
243 .computeIf(
244 key,
245 v -> condition.test(valueDecoder.apply(v)),
246 (k, v) -> valueEncoder
247 .apply(
248 remappingFunction.apply(
249 key,
250 valueDecoder.apply(v))))
251 .thenApply(versionedValueTransform);
252 } catch (Exception e) {
253 return Tools.exceptionalFuture(e);
254 }
255 }
256
257 @Override
258 public CompletableFuture<Versioned<V1>> put(String key, V1 value) {
259 return backingMap.put(key, valueEncoder.apply(value))
Aaron Kruglikovb06078c2016-08-30 17:28:00 -0700260 .thenApply(versionedValueTransform);
Aaron Kruglikoved88ff62016-08-01 16:02:09 -0700261 }
262
263 @Override
264 public CompletableFuture<Versioned<V1>> putAndGet(String key, V1 value) {
265 return backingMap.putAndGet(key, valueEncoder.apply(value))
Aaron Kruglikovb06078c2016-08-30 17:28:00 -0700266 .thenApply(versionedValueTransform);
Aaron Kruglikoved88ff62016-08-01 16:02:09 -0700267 }
268
269 @Override
270 public CompletableFuture<Versioned<V1>> remove(String key) {
Aaron Kruglikovb06078c2016-08-30 17:28:00 -0700271 return backingMap.remove(key).thenApply(versionedValueTransform);
Aaron Kruglikoved88ff62016-08-01 16:02:09 -0700272 }
273
274 @Override
275 public CompletableFuture<Void> clear() {
276 return backingMap.clear();
277 }
278
279 @Override
280 public CompletableFuture<Set<String>> keySet() {
281 return backingMap.keySet();
282 }
283
284 @Override
285 public CompletableFuture<Collection<Versioned<V1>>> values() {
286 return backingMap.values().thenApply(valueSet -> valueSet.stream()
Aaron Kruglikovb06078c2016-08-30 17:28:00 -0700287 .map(versionedValueTransform).collect(Collectors.toSet()));
Aaron Kruglikoved88ff62016-08-01 16:02:09 -0700288 }
289
290 @Override
291 public CompletableFuture<Set<Map.Entry<String, Versioned<V1>>>>
292 entrySet() {
293 return backingMap.entrySet()
294 .thenApply(
Aaron Kruglikovb06078c2016-08-30 17:28:00 -0700295 entries -> entries
296 .stream()
297 .map(entry ->
298 Maps.immutableEntry(
299 entry.getKey(),
300 versionedValueTransform
301 .apply(entry.getValue())
302 ))
303 .collect(Collectors.toSet()));
304 }
Aaron Kruglikoved88ff62016-08-01 16:02:09 -0700305
306 @Override
307 public CompletableFuture<Versioned<V1>> putIfAbsent(String key, V1 value) {
308 return backingMap.putIfAbsent(key, valueEncoder.apply(value))
Aaron Kruglikovb06078c2016-08-30 17:28:00 -0700309 .thenApply(versionedValueTransform);
Aaron Kruglikoved88ff62016-08-01 16:02:09 -0700310 }
311
312 @Override
313 public CompletableFuture<Boolean> remove(String key, V1 value) {
314 return backingMap.remove(key, valueEncoder.apply(value));
315 }
316
317 @Override
318 public CompletableFuture<Boolean> remove(String key, long version) {
319 return backingMap.remove(key, version);
320 }
321
322 @Override
323 public CompletableFuture<Versioned<V1>> replace(String key, V1 value) {
324 return backingMap.replace(key, valueEncoder.apply(value))
Aaron Kruglikovb06078c2016-08-30 17:28:00 -0700325 .thenApply(versionedValueTransform);
Aaron Kruglikoved88ff62016-08-01 16:02:09 -0700326 }
327
328 @Override
329 public CompletableFuture<Boolean> replace(String key, V1 oldValue,
330 V1 newValue) {
331 return backingMap.replace(key, valueEncoder.apply(oldValue),
332 valueEncoder.apply(newValue));
333 }
334
335 @Override
336 public CompletableFuture<Boolean> replace(String key, long oldVersion,
337 V1 newValue) {
338 return backingMap.replace(key, oldVersion,
339 valueEncoder.apply(newValue));
340 }
341
342 @Override
343 public CompletableFuture<Void> addListener(
344 MapEventListener<String, V1> listener,
345 Executor executor) {
346 InternalBackingMapEventListener backingMapEventListener =
347 listeners.computeIfAbsent(
348 listener,
349 k -> new InternalBackingMapEventListener(listener));
350 return backingMap.addListener(backingMapEventListener, executor);
351 }
352
353 @Override
354 public CompletableFuture<Void> removeListener(
355 MapEventListener<String, V1> listener) {
356 InternalBackingMapEventListener backingMapEventListener =
357 listeners.remove(listener);
358 if (backingMapEventListener == null) {
359 return CompletableFuture.completedFuture(null);
360 } else {
361 return backingMap.removeListener(backingMapEventListener);
362 }
363 }
364
365 @Override
Jordan Halterman948d6592017-04-20 17:18:24 -0700366 public CompletableFuture<Version> begin(TransactionId transactionId) {
367 throw new UnsupportedOperationException("This operation is not yet supported.");
368 }
369
370 @Override
371 public CompletableFuture<Boolean> prepare(TransactionLog<MapUpdate<String, V1>> transactionLog) {
372 throw new UnsupportedOperationException("This operation is not yet supported.");
373 }
374
375 @Override
376 public CompletableFuture<Boolean> prepareAndCommit(TransactionLog<MapUpdate<String, V1>> transactionLog) {
377 throw new UnsupportedOperationException("This operation is not yet supported.");
Aaron Kruglikoved88ff62016-08-01 16:02:09 -0700378 }
379
380 @Override
381 public CompletableFuture<Void> commit(TransactionId transactionId) {
Jordan Halterman948d6592017-04-20 17:18:24 -0700382 throw new UnsupportedOperationException("This operation is not yet supported.");
383 }
Aaron Kruglikoved88ff62016-08-01 16:02:09 -0700384
385 @Override
386 public CompletableFuture<Void> rollback(TransactionId transactionId) {
Jordan Halterman948d6592017-04-20 17:18:24 -0700387 throw new UnsupportedOperationException("This operation is not yet supported.");
388 }
Aaron Kruglikoved88ff62016-08-01 16:02:09 -0700389
Aaron Kruglikoved88ff62016-08-01 16:02:09 -0700390 private class InternalBackingMapEventListener
391 implements MapEventListener<String, V2> {
392
393 private final MapEventListener<String, V1> listener;
394
395 InternalBackingMapEventListener(
396 MapEventListener<String, V1> listener) {
397 this.listener = listener;
398 }
399
400 @Override
401 public void event(MapEvent<String, V2> event) {
402 listener.event(new MapEvent<String, V1>(
Jordan Halterman71635ae2017-07-28 10:35:43 -0700403 event.type(),
Aaron Kruglikoved88ff62016-08-01 16:02:09 -0700404 event.name(),
405 event.key(),
406 event.newValue() != null ?
407 event.newValue().map(valueDecoder) : null,
408 event.oldValue() != null ?
409 event.oldValue().map(valueDecoder) : null));
410 }
411 }
412}