blob: 24dd35da66252133806b1645ce9676894f8736a6 [file] [log] [blame]
Jordan Halterman400bbe52018-04-05 23:07:47 -07001/*
2 * Copyright 2018-present Open Networking Foundation
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 */
16package org.onosproject.store.primitives.impl;
17
18import java.util.Collection;
19import java.util.Map;
20import java.util.concurrent.CompletableFuture;
21import java.util.function.Consumer;
22import java.util.function.Function;
23
24import com.google.common.collect.Maps;
25import org.onosproject.store.service.AsyncAtomicValue;
26import org.onosproject.store.service.AtomicValueEvent;
27import org.onosproject.store.service.AtomicValueEventListener;
28
29/**
30 * An {@code AsyncAtomicValue} that transcodes values.
31 */
32public class TranscodingAsyncAtomicValue<V1, V2> implements AsyncAtomicValue<V1> {
33 private final AsyncAtomicValue<V2> backingValue;
34 private final Function<V1, V2> valueEncoder;
35 private final Function<V2, V1> valueDecoder;
36 private final Map<AtomicValueEventListener<V1>, InternalValueEventListener> listeners = Maps.newIdentityHashMap();
37
38 public TranscodingAsyncAtomicValue(
39 AsyncAtomicValue<V2> backingValue, Function<V1, V2> valueEncoder, Function<V2, V1> valueDecoder) {
40 this.backingValue = backingValue;
41 this.valueEncoder = k -> k == null ? null : valueEncoder.apply(k);
42 this.valueDecoder = k -> k == null ? null : valueDecoder.apply(k);
43 }
44
45 @Override
46 public String name() {
47 return backingValue.name();
48 }
49
50 @Override
51 public CompletableFuture<Boolean> compareAndSet(V1 expect, V1 update) {
52 return backingValue.compareAndSet(valueEncoder.apply(expect), valueEncoder.apply(update));
53 }
54
55 @Override
56 public CompletableFuture<V1> get() {
57 return backingValue.get().thenApply(valueDecoder);
58 }
59
60 @Override
61 public CompletableFuture<V1> getAndSet(V1 value) {
62 return backingValue.getAndSet(valueEncoder.apply(value)).thenApply(valueDecoder);
63 }
64
65 @Override
66 public CompletableFuture<Void> set(V1 value) {
67 return backingValue.set(valueEncoder.apply(value));
68 }
69
70 @Override
71 public CompletableFuture<Void> addListener(AtomicValueEventListener<V1> listener) {
72 synchronized (listeners) {
73 InternalValueEventListener backingMapListener =
74 listeners.computeIfAbsent(listener, k -> new InternalValueEventListener(listener));
75 return backingValue.addListener(backingMapListener);
76 }
77 }
78
79 @Override
80 public CompletableFuture<Void> removeListener(AtomicValueEventListener<V1> listener) {
81 synchronized (listeners) {
82 InternalValueEventListener backingMapListener = listeners.remove(listener);
83 if (backingMapListener != null) {
84 return backingValue.removeListener(backingMapListener);
85 } else {
86 return CompletableFuture.completedFuture(null);
87 }
88 }
89 }
90
91 @Override
92 public void addStatusChangeListener(Consumer<Status> listener) {
93 backingValue.addStatusChangeListener(listener);
94 }
95
96 @Override
97 public void removeStatusChangeListener(Consumer<Status> listener) {
98 backingValue.removeStatusChangeListener(listener);
99 }
100
101 @Override
102 public Collection<Consumer<Status>> statusChangeListeners() {
103 return backingValue.statusChangeListeners();
104 }
105
106 private class InternalValueEventListener implements AtomicValueEventListener<V2> {
107 private final AtomicValueEventListener<V1> listener;
108
109 InternalValueEventListener(AtomicValueEventListener<V1> listener) {
110 this.listener = listener;
111 }
112
113 @Override
114 public void event(AtomicValueEvent<V2> event) {
115 listener.event(new AtomicValueEvent<>(
116 event.name(),
117 event.newValue() != null ? valueDecoder.apply(event.newValue()) : null,
118 event.oldValue() != null ? valueDecoder.apply(event.oldValue()) : null));
119 }
120 }
121
122}