blob: f3938ce4509dfc6cfb9d2b920c3a5baeabd94a6c [file] [log] [blame]
Madan Jampani551d0d22016-02-01 12:51:48 -08001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2016-present Open Networking Laboratory
Madan Jampani551d0d22016-02-01 12:51:48 -08003 *
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 java.util.Collection;
20import java.util.Map;
21import java.util.Map.Entry;
22import java.util.Set;
23import java.util.concurrent.CompletableFuture;
Madan Jampani0463cf92016-05-04 14:46:08 -070024import java.util.concurrent.Executor;
Madan Jampani551d0d22016-02-01 12:51:48 -080025import java.util.function.BiFunction;
Madan Jampani1d3b6172016-04-28 13:22:57 -070026import java.util.function.Consumer;
Madan Jampani551d0d22016-02-01 12:51:48 -080027import java.util.function.Function;
28import java.util.function.Predicate;
29import java.util.stream.Collectors;
30
Madan Jampanie9c9a712016-04-18 10:58:04 -070031import org.onlab.util.Tools;
Madan Jampani74da78b2016-02-09 21:18:36 -080032import org.onosproject.store.primitives.TransactionId;
Madan Jampani551d0d22016-02-01 12:51:48 -080033import org.onosproject.store.service.AsyncConsistentMap;
34import org.onosproject.store.service.MapEvent;
35import org.onosproject.store.service.MapEventListener;
Madan Jampani74da78b2016-02-09 21:18:36 -080036import org.onosproject.store.service.MapTransaction;
Madan Jampani551d0d22016-02-01 12:51:48 -080037import org.onosproject.store.service.Versioned;
Madan Jampani0463cf92016-05-04 14:46:08 -070038
Madan Jampani551d0d22016-02-01 12:51:48 -080039import com.google.common.collect.Maps;
40
41/**
42 * An {@code AsyncConsistentMap} that maps its operations to operations on a
43 * differently typed {@code AsyncConsistentMap} by transcoding operation inputs and outputs.
44 *
45 * @param <K2> key type of other map
46 * @param <V2> value type of other map
47 * @param <K1> key type of this map
48 * @param <V1> value type of this map
49 */
50public class TranscodingAsyncConsistentMap<K1, V1, K2, V2> implements AsyncConsistentMap<K1, V1> {
51
52 private final AsyncConsistentMap<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<Versioned<V2>, Versioned<V1>> versionedValueTransform;
58 private final Map<MapEventListener<K1, V1>, InternalBackingMapEventListener> listeners =
59 Maps.newIdentityHashMap();
60
61 public TranscodingAsyncConsistentMap(AsyncConsistentMap<K2, V2> backingMap,
62 Function<K1, K2> keyEncoder,
63 Function<K2, K1> keyDecoder,
64 Function<V1, V2> valueEncoder,
65 Function<V2, V1> valueDecoder) {
66 this.backingMap = backingMap;
67 this.keyEncoder = k -> k == null ? null : keyEncoder.apply(k);
Madan Jampani1e8e89c2016-02-02 08:53:56 -080068 this.keyDecoder = k -> k == null ? null : keyDecoder.apply(k);
Madan Jampani551d0d22016-02-01 12:51:48 -080069 this.valueEncoder = v -> v == null ? null : valueEncoder.apply(v);
Madan Jampani1e8e89c2016-02-02 08:53:56 -080070 this.valueDecoder = v -> v == null ? null : valueDecoder.apply(v);
Madan Jampani551d0d22016-02-01 12:51:48 -080071 this.versionedValueTransform = v -> v == null ? null : v.map(valueDecoder);
72 }
73
74 @Override
75 public String name() {
76 return backingMap.name();
77 }
78
79 @Override
80 public CompletableFuture<Integer> size() {
81 return backingMap.size();
82 }
83
84 @Override
85 public CompletableFuture<Boolean> containsKey(K1 key) {
Madan Jampanie9c9a712016-04-18 10:58:04 -070086 try {
87 return backingMap.containsKey(keyEncoder.apply(key));
88 } catch (Exception e) {
89 return Tools.exceptionalFuture(e);
90 }
Madan Jampani551d0d22016-02-01 12:51:48 -080091 }
92
93 @Override
94 public CompletableFuture<Boolean> containsValue(V1 value) {
Madan Jampanie9c9a712016-04-18 10:58:04 -070095 try {
96 return backingMap.containsValue(valueEncoder.apply(value));
97 } catch (Exception e) {
98 return Tools.exceptionalFuture(e);
99 }
Madan Jampani551d0d22016-02-01 12:51:48 -0800100 }
101
102 @Override
103 public CompletableFuture<Versioned<V1>> get(K1 key) {
Madan Jampanie9c9a712016-04-18 10:58:04 -0700104 try {
105 return backingMap.get(keyEncoder.apply(key)).thenApply(versionedValueTransform);
106 } catch (Exception e) {
107 return Tools.exceptionalFuture(e);
108 }
Madan Jampani551d0d22016-02-01 12:51:48 -0800109 }
110
111 @Override
112 public CompletableFuture<Versioned<V1>> computeIf(K1 key,
113 Predicate<? super V1> condition,
114 BiFunction<? super K1, ? super V1, ? extends V1> remappingFunction) {
Madan Jampanie9c9a712016-04-18 10:58:04 -0700115 try {
116 return backingMap.computeIf(keyEncoder.apply(key),
117 v -> condition.test(valueDecoder.apply(v)),
118 (k, v) -> valueEncoder.apply(remappingFunction.apply(keyDecoder.apply(k),
119 valueDecoder.apply(v))))
120 .thenApply(versionedValueTransform);
121 } catch (Exception e) {
122 return Tools.exceptionalFuture(e);
123 }
Madan Jampani551d0d22016-02-01 12:51:48 -0800124 }
125
126 @Override
127 public CompletableFuture<Versioned<V1>> put(K1 key, V1 value) {
Madan Jampanie9c9a712016-04-18 10:58:04 -0700128 try {
129 return backingMap.put(keyEncoder.apply(key), valueEncoder.apply(value))
130 .thenApply(versionedValueTransform);
131 } catch (Exception e) {
132 return Tools.exceptionalFuture(e);
133 }
Madan Jampani551d0d22016-02-01 12:51:48 -0800134 }
135
136 @Override
137 public CompletableFuture<Versioned<V1>> putAndGet(K1 key, V1 value) {
Madan Jampanie9c9a712016-04-18 10:58:04 -0700138 try {
139 return backingMap.putAndGet(keyEncoder.apply(key), valueEncoder.apply(value))
140 .thenApply(versionedValueTransform);
141 } catch (Exception e) {
142 return Tools.exceptionalFuture(e);
143 }
Madan Jampani551d0d22016-02-01 12:51:48 -0800144 }
145
146 @Override
147 public CompletableFuture<Versioned<V1>> remove(K1 key) {
Madan Jampanie9c9a712016-04-18 10:58:04 -0700148 try {
149 return backingMap.remove(keyEncoder.apply(key)).thenApply(versionedValueTransform);
150 } catch (Exception e) {
151 return Tools.exceptionalFuture(e);
152 }
Madan Jampani551d0d22016-02-01 12:51:48 -0800153 }
154
155 @Override
156 public CompletableFuture<Void> clear() {
157 return backingMap.clear();
158 }
159
160 @Override
161 public CompletableFuture<Set<K1>> keySet() {
162 return backingMap.keySet()
163 .thenApply(s -> s.stream().map(keyDecoder).collect(Collectors.toSet()));
164 }
165
166 @Override
167 public CompletableFuture<Collection<Versioned<V1>>> values() {
168 return backingMap.values()
169 .thenApply(c -> c.stream().map(versionedValueTransform).collect(Collectors.toList()));
170 }
171
172 @Override
173 public CompletableFuture<Set<Entry<K1, Versioned<V1>>>> entrySet() {
174 return backingMap.entrySet()
175 .thenApply(s -> s.stream()
176 .map(e -> Maps.immutableEntry(keyDecoder.apply(e.getKey()),
177 versionedValueTransform.apply(e.getValue())))
178 .collect(Collectors.toSet()));
179 }
180
181 @Override
182 public CompletableFuture<Versioned<V1>> putIfAbsent(K1 key, V1 value) {
Madan Jampanie9c9a712016-04-18 10:58:04 -0700183 try {
184 return backingMap.putIfAbsent(keyEncoder.apply(key), valueEncoder.apply(value))
185 .thenApply(versionedValueTransform);
186 } catch (Exception e) {
187 return Tools.exceptionalFuture(e);
188 }
Madan Jampani551d0d22016-02-01 12:51:48 -0800189 }
190
191 @Override
192 public CompletableFuture<Boolean> remove(K1 key, V1 value) {
Madan Jampanie9c9a712016-04-18 10:58:04 -0700193 try {
194 return backingMap.remove(keyEncoder.apply(key), valueEncoder.apply(value));
195 } catch (Exception e) {
196 return Tools.exceptionalFuture(e);
197 }
Madan Jampani551d0d22016-02-01 12:51:48 -0800198 }
199
200 @Override
201 public CompletableFuture<Boolean> remove(K1 key, long version) {
Madan Jampanie9c9a712016-04-18 10:58:04 -0700202 try {
203 return backingMap.remove(keyEncoder.apply(key), version);
204 } catch (Exception e) {
205 return Tools.exceptionalFuture(e);
206 }
Madan Jampani551d0d22016-02-01 12:51:48 -0800207 }
208
209 @Override
210 public CompletableFuture<Versioned<V1>> replace(K1 key, V1 value) {
Madan Jampanie9c9a712016-04-18 10:58:04 -0700211 try {
212 return backingMap.replace(keyEncoder.apply(key), valueEncoder.apply(value))
213 .thenApply(versionedValueTransform);
214 } catch (Exception e) {
215 return Tools.exceptionalFuture(e);
216 }
Madan Jampani551d0d22016-02-01 12:51:48 -0800217 }
218
219 @Override
220 public CompletableFuture<Boolean> replace(K1 key, V1 oldValue, V1 newValue) {
Madan Jampanie9c9a712016-04-18 10:58:04 -0700221 try {
222 return backingMap.replace(keyEncoder.apply(key),
223 valueEncoder.apply(oldValue),
224 valueEncoder.apply(newValue));
225 } catch (Exception e) {
226 return Tools.exceptionalFuture(e);
227 }
Madan Jampani551d0d22016-02-01 12:51:48 -0800228 }
229
230 @Override
231 public CompletableFuture<Boolean> replace(K1 key, long oldVersion, V1 newValue) {
Madan Jampanie9c9a712016-04-18 10:58:04 -0700232 try {
233 return backingMap.replace(keyEncoder.apply(key), oldVersion, valueEncoder.apply(newValue));
234 } catch (Exception e) {
235 return Tools.exceptionalFuture(e);
236 }
Madan Jampani551d0d22016-02-01 12:51:48 -0800237 }
238
239 @Override
Madan Jampani0463cf92016-05-04 14:46:08 -0700240 public CompletableFuture<Void> addListener(MapEventListener<K1, V1> listener, Executor executor) {
Madan Jampani551d0d22016-02-01 12:51:48 -0800241 synchronized (listeners) {
242 InternalBackingMapEventListener backingMapListener =
243 listeners.computeIfAbsent(listener, k -> new InternalBackingMapEventListener(listener));
Madan Jampani0463cf92016-05-04 14:46:08 -0700244 return backingMap.addListener(backingMapListener, executor);
Madan Jampani551d0d22016-02-01 12:51:48 -0800245 }
246 }
247
248 @Override
249 public CompletableFuture<Void> removeListener(MapEventListener<K1, V1> listener) {
250 InternalBackingMapEventListener backingMapListener = listeners.remove(listener);
251 if (backingMapListener != null) {
252 return backingMap.removeListener(backingMapListener);
253 } else {
254 return CompletableFuture.completedFuture(null);
255 }
256 }
257
Madan Jampani74da78b2016-02-09 21:18:36 -0800258 @Override
259 public CompletableFuture<Boolean> prepare(MapTransaction<K1, V1> transaction) {
Madan Jampanie9c9a712016-04-18 10:58:04 -0700260 try {
261 return backingMap.prepare(transaction.map(keyEncoder, valueEncoder));
262 } catch (Exception e) {
263 return Tools.exceptionalFuture(e);
264 }
Madan Jampani74da78b2016-02-09 21:18:36 -0800265 }
266
267 @Override
268 public CompletableFuture<Void> commit(TransactionId transactionId) {
269 return backingMap.commit(transactionId);
270 }
271
272 @Override
273 public CompletableFuture<Void> rollback(TransactionId transactionId) {
274 return backingMap.rollback(transactionId);
275 }
276
Madan Jampani542d9e22016-04-05 15:39:55 -0700277 @Override
278 public CompletableFuture<Boolean> prepareAndCommit(MapTransaction<K1, V1> transaction) {
Madan Jampanie9c9a712016-04-18 10:58:04 -0700279 try {
280 return backingMap.prepareAndCommit(transaction.map(keyEncoder, valueEncoder));
281 } catch (Exception e) {
282 return Tools.exceptionalFuture(e);
283 }
Madan Jampani542d9e22016-04-05 15:39:55 -0700284 }
285
Madan Jampani1d3b6172016-04-28 13:22:57 -0700286 @Override
287 public void addStatusChangeListener(Consumer<Status> listener) {
288 backingMap.addStatusChangeListener(listener);
289 }
290
291 @Override
292 public void removeStatusChangeListener(Consumer<Status> listener) {
293 backingMap.removeStatusChangeListener(listener);
294 }
295
296 @Override
297 public Collection<Consumer<Status>> statusChangeListeners() {
298 return backingMap.statusChangeListeners();
299 }
300
Madan Jampani551d0d22016-02-01 12:51:48 -0800301 private class InternalBackingMapEventListener implements MapEventListener<K2, V2> {
302
303 private final MapEventListener<K1, V1> listener;
304
305 InternalBackingMapEventListener(MapEventListener<K1, V1> listener) {
306 this.listener = listener;
307 }
308
309 @Override
310 public void event(MapEvent<K2, V2> event) {
311 listener.event(new MapEvent<K1, V1>(event.name(),
312 keyDecoder.apply(event.key()),
Madan Jampania9673fd2016-02-02 13:01:29 -0800313 event.newValue() != null ? event.newValue().map(valueDecoder) : null,
314 event.oldValue() != null ? event.oldValue().map(valueDecoder) : null));
Madan Jampani551d0d22016-02-01 12:51:48 -0800315 }
316 }
317}