blob: b679925b4968175107e2786aea742336ab8547db [file] [log] [blame]
Madan Jampani551d0d22016-02-01 12:51:48 -08001/*
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 java.util.Collection;
20import java.util.Map;
21import java.util.Map.Entry;
22import java.util.Set;
23import java.util.concurrent.CompletableFuture;
24import java.util.function.BiFunction;
25import java.util.function.Function;
26import java.util.function.Predicate;
27import java.util.stream.Collectors;
28
Madan Jampani74da78b2016-02-09 21:18:36 -080029import org.onosproject.store.primitives.TransactionId;
Madan Jampani551d0d22016-02-01 12:51:48 -080030import org.onosproject.store.service.AsyncConsistentMap;
31import org.onosproject.store.service.MapEvent;
32import org.onosproject.store.service.MapEventListener;
Madan Jampani74da78b2016-02-09 21:18:36 -080033import org.onosproject.store.service.MapTransaction;
Madan Jampani551d0d22016-02-01 12:51:48 -080034import org.onosproject.store.service.Versioned;
35
36import com.google.common.collect.Maps;
37
38/**
39 * An {@code AsyncConsistentMap} that maps its operations to operations on a
40 * differently typed {@code AsyncConsistentMap} by transcoding operation inputs and outputs.
41 *
42 * @param <K2> key type of other map
43 * @param <V2> value type of other map
44 * @param <K1> key type of this map
45 * @param <V1> value type of this map
46 */
47public class TranscodingAsyncConsistentMap<K1, V1, K2, V2> implements AsyncConsistentMap<K1, V1> {
48
49 private final AsyncConsistentMap<K2, V2> backingMap;
50 private final Function<K1, K2> keyEncoder;
51 private final Function<K2, K1> keyDecoder;
52 private final Function<V2, V1> valueDecoder;
53 private final Function<V1, V2> valueEncoder;
54 private final Function<Versioned<V2>, Versioned<V1>> versionedValueTransform;
55 private final Map<MapEventListener<K1, V1>, InternalBackingMapEventListener> listeners =
56 Maps.newIdentityHashMap();
57
58 public TranscodingAsyncConsistentMap(AsyncConsistentMap<K2, V2> backingMap,
59 Function<K1, K2> keyEncoder,
60 Function<K2, K1> keyDecoder,
61 Function<V1, V2> valueEncoder,
62 Function<V2, V1> valueDecoder) {
63 this.backingMap = backingMap;
64 this.keyEncoder = k -> k == null ? null : keyEncoder.apply(k);
Madan Jampani1e8e89c2016-02-02 08:53:56 -080065 this.keyDecoder = k -> k == null ? null : keyDecoder.apply(k);
Madan Jampani551d0d22016-02-01 12:51:48 -080066 this.valueEncoder = v -> v == null ? null : valueEncoder.apply(v);
Madan Jampani1e8e89c2016-02-02 08:53:56 -080067 this.valueDecoder = v -> v == null ? null : valueDecoder.apply(v);
Madan Jampani551d0d22016-02-01 12:51:48 -080068 this.versionedValueTransform = v -> v == null ? null : v.map(valueDecoder);
69 }
70
71 @Override
72 public String name() {
73 return backingMap.name();
74 }
75
76 @Override
77 public CompletableFuture<Integer> size() {
78 return backingMap.size();
79 }
80
81 @Override
82 public CompletableFuture<Boolean> containsKey(K1 key) {
83 return backingMap.containsKey(keyEncoder.apply(key));
84 }
85
86 @Override
87 public CompletableFuture<Boolean> containsValue(V1 value) {
88 return backingMap.containsValue(valueEncoder.apply(value));
89 }
90
91 @Override
92 public CompletableFuture<Versioned<V1>> get(K1 key) {
93 return backingMap.get(keyEncoder.apply(key)).thenApply(versionedValueTransform);
94 }
95
96 @Override
97 public CompletableFuture<Versioned<V1>> computeIf(K1 key,
98 Predicate<? super V1> condition,
99 BiFunction<? super K1, ? super V1, ? extends V1> remappingFunction) {
100 return backingMap.computeIf(keyEncoder.apply(key),
101 v -> condition.test(valueDecoder.apply(v)),
102 (k, v) -> valueEncoder.apply(remappingFunction.apply(keyDecoder.apply(k),
103 valueDecoder.apply(v))))
104 .thenApply(versionedValueTransform);
105 }
106
107 @Override
108 public CompletableFuture<Versioned<V1>> put(K1 key, V1 value) {
109 return backingMap.put(keyEncoder.apply(key), valueEncoder.apply(value))
110 .thenApply(versionedValueTransform);
111 }
112
113 @Override
114 public CompletableFuture<Versioned<V1>> putAndGet(K1 key, V1 value) {
115 return backingMap.putAndGet(keyEncoder.apply(key), valueEncoder.apply(value))
116 .thenApply(versionedValueTransform);
117 }
118
119 @Override
120 public CompletableFuture<Versioned<V1>> remove(K1 key) {
121 return backingMap.remove(keyEncoder.apply(key)).thenApply(versionedValueTransform);
122 }
123
124 @Override
125 public CompletableFuture<Void> clear() {
126 return backingMap.clear();
127 }
128
129 @Override
130 public CompletableFuture<Set<K1>> keySet() {
131 return backingMap.keySet()
132 .thenApply(s -> s.stream().map(keyDecoder).collect(Collectors.toSet()));
133 }
134
135 @Override
136 public CompletableFuture<Collection<Versioned<V1>>> values() {
137 return backingMap.values()
138 .thenApply(c -> c.stream().map(versionedValueTransform).collect(Collectors.toList()));
139 }
140
141 @Override
142 public CompletableFuture<Set<Entry<K1, Versioned<V1>>>> entrySet() {
143 return backingMap.entrySet()
144 .thenApply(s -> s.stream()
145 .map(e -> Maps.immutableEntry(keyDecoder.apply(e.getKey()),
146 versionedValueTransform.apply(e.getValue())))
147 .collect(Collectors.toSet()));
148 }
149
150 @Override
151 public CompletableFuture<Versioned<V1>> putIfAbsent(K1 key, V1 value) {
152 return backingMap.putIfAbsent(keyEncoder.apply(key), valueEncoder.apply(value))
153 .thenApply(versionedValueTransform);
154 }
155
156 @Override
157 public CompletableFuture<Boolean> remove(K1 key, V1 value) {
158 return backingMap.remove(keyEncoder.apply(key), valueEncoder.apply(value));
159 }
160
161 @Override
162 public CompletableFuture<Boolean> remove(K1 key, long version) {
163 return backingMap.remove(keyEncoder.apply(key), version);
164 }
165
166 @Override
167 public CompletableFuture<Versioned<V1>> replace(K1 key, V1 value) {
168 return backingMap.replace(keyEncoder.apply(key), valueEncoder.apply(value))
169 .thenApply(versionedValueTransform);
170 }
171
172 @Override
173 public CompletableFuture<Boolean> replace(K1 key, V1 oldValue, V1 newValue) {
174 return backingMap.replace(keyEncoder.apply(key), valueEncoder.apply(oldValue), valueEncoder.apply(newValue));
175 }
176
177 @Override
178 public CompletableFuture<Boolean> replace(K1 key, long oldVersion, V1 newValue) {
179 return backingMap.replace(keyEncoder.apply(key), oldVersion, valueEncoder.apply(newValue));
180 }
181
182 @Override
183 public CompletableFuture<Void> addListener(MapEventListener<K1, V1> listener) {
184 synchronized (listeners) {
185 InternalBackingMapEventListener backingMapListener =
186 listeners.computeIfAbsent(listener, k -> new InternalBackingMapEventListener(listener));
187 return backingMap.addListener(backingMapListener);
188 }
189 }
190
191 @Override
192 public CompletableFuture<Void> removeListener(MapEventListener<K1, V1> listener) {
193 InternalBackingMapEventListener backingMapListener = listeners.remove(listener);
194 if (backingMapListener != null) {
195 return backingMap.removeListener(backingMapListener);
196 } else {
197 return CompletableFuture.completedFuture(null);
198 }
199 }
200
Madan Jampani74da78b2016-02-09 21:18:36 -0800201 @Override
202 public CompletableFuture<Boolean> prepare(MapTransaction<K1, V1> transaction) {
203 return backingMap.prepare(transaction.map(keyEncoder, valueEncoder));
204 }
205
206 @Override
207 public CompletableFuture<Void> commit(TransactionId transactionId) {
208 return backingMap.commit(transactionId);
209 }
210
211 @Override
212 public CompletableFuture<Void> rollback(TransactionId transactionId) {
213 return backingMap.rollback(transactionId);
214 }
215
Madan Jampani542d9e22016-04-05 15:39:55 -0700216 @Override
217 public CompletableFuture<Boolean> prepareAndCommit(MapTransaction<K1, V1> transaction) {
218 return backingMap.prepareAndCommit(transaction.map(keyEncoder, valueEncoder));
219 }
220
Madan Jampani551d0d22016-02-01 12:51:48 -0800221 private class InternalBackingMapEventListener implements MapEventListener<K2, V2> {
222
223 private final MapEventListener<K1, V1> listener;
224
225 InternalBackingMapEventListener(MapEventListener<K1, V1> listener) {
226 this.listener = listener;
227 }
228
229 @Override
230 public void event(MapEvent<K2, V2> event) {
231 listener.event(new MapEvent<K1, V1>(event.name(),
232 keyDecoder.apply(event.key()),
Madan Jampania9673fd2016-02-02 13:01:29 -0800233 event.newValue() != null ? event.newValue().map(valueDecoder) : null,
234 event.oldValue() != null ? event.oldValue().map(valueDecoder) : null));
Madan Jampani551d0d22016-02-01 12:51:48 -0800235 }
236 }
237}