blob: 3b1202197d95f24b08c6a2b54f92c132c152b83a [file] [log] [blame]
Madan Jampani5e5b3d62016-02-01 16:03:33 -08001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2016-present Open Networking Laboratory
Madan Jampani5e5b3d62016-02-01 16:03:33 -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
Madan Jampani74da78b2016-02-09 21:18:36 -080017package org.onosproject.store.primitives;
Madan Jampani5e5b3d62016-02-01 16:03:33 -080018
Madan Jampani5e5b3d62016-02-01 16:03:33 -080019import static com.google.common.base.Preconditions.checkNotNull;
20import static com.google.common.base.Preconditions.checkState;
21
Madan Jampani74da78b2016-02-09 21:18:36 -080022import java.util.function.Function;
23
Madan Jampani3780d4b2016-04-04 18:18:24 -070024import org.onlab.util.ByteArraySizeHashPrinter;
25
Madan Jampani5e5b3d62016-02-01 16:03:33 -080026import com.google.common.base.MoreObjects;
27
28/**
29 * Map update operation.
30 *
31 * @param <K> map key type
32 * @param <V> map value type
33 *
34 */
35public final class MapUpdate<K, V> {
36
37 /**
38 * Type of database update operation.
39 */
40 public enum Type {
41 /**
42 * Insert/Update entry without any checks.
43 */
44 PUT,
45 /**
46 * Insert an entry iff there is no existing entry for that key.
47 */
48 PUT_IF_ABSENT,
49
50 /**
51 * Update entry if the current version matches specified version.
52 */
53 PUT_IF_VERSION_MATCH,
54
55 /**
56 * Update entry if the current value matches specified value.
57 */
58 PUT_IF_VALUE_MATCH,
59
60 /**
61 * Remove entry without any checks.
62 */
63 REMOVE,
64
65 /**
66 * Remove entry if the current version matches specified version.
67 */
68 REMOVE_IF_VERSION_MATCH,
69
70 /**
71 * Remove entry if the current value matches specified value.
72 */
73 REMOVE_IF_VALUE_MATCH,
74 }
75
Madan Jampanicadd70b2016-02-08 13:45:43 -080076 private String mapName;
Madan Jampani5e5b3d62016-02-01 16:03:33 -080077 private Type type;
78 private K key;
79 private V value;
80 private V currentValue;
81 private long currentVersion = -1;
82
83 /**
Madan Jampanicadd70b2016-02-08 13:45:43 -080084 * Returns the name of the map.
85 *
86 * @return map name
87 */
88 public String mapName() {
89 return mapName;
90 }
91
92 /**
Madan Jampani5e5b3d62016-02-01 16:03:33 -080093 * Returns the type of update operation.
94 * @return type of update.
95 */
96 public Type type() {
97 return type;
98 }
99
100 /**
101 * Returns the item key being updated.
102 * @return item key
103 */
104 public K key() {
105 return key;
106 }
107
108 /**
109 * Returns the new value.
110 * @return item's target value.
111 */
112 public V value() {
113 return value;
114 }
115
116 /**
117 * Returns the expected current value for the key.
118 * @return current value in database.
119 */
120 public V currentValue() {
121 return currentValue;
122 }
123
124 /**
125 * Returns the expected current version in the database for the key.
126 * @return expected version.
127 */
128 public long currentVersion() {
129 return currentVersion;
130 }
131
Madan Jampani74da78b2016-02-09 21:18:36 -0800132 /**
133 * Transforms this instance into an instance of different paramterized types.
134 *
135 * @param keyMapper transcoder for key type
136 * @param valueMapper transcoder to value type
137 * @return new instance
138 * @param <S> key type of returned instance
139 * @param <T> value type of returned instance
140 */
141 public <S, T> MapUpdate<S, T> map(Function<K, S> keyMapper, Function<V, T> valueMapper) {
142 return MapUpdate.<S, T>newBuilder()
143 .withMapName(mapName)
144 .withType(type)
145 .withKey(keyMapper.apply(key))
146 .withValue(value == null ? null : valueMapper.apply(value))
147 .withCurrentValue(currentValue == null ? null : valueMapper.apply(currentValue))
148 .withCurrentVersion(currentVersion)
149 .build();
150 }
151
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800152 @Override
153 public String toString() {
154 return MoreObjects.toStringHelper(this)
Madan Jampanicadd70b2016-02-08 13:45:43 -0800155 .add("mapName", mapName)
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800156 .add("type", type)
157 .add("key", key)
Madan Jampani3780d4b2016-04-04 18:18:24 -0700158 .add("value", value instanceof byte[] ? new ByteArraySizeHashPrinter((byte[]) value) : value)
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800159 .add("currentValue", currentValue)
160 .add("currentVersion", currentVersion)
161 .toString();
162 }
163
164 /**
165 * Creates a new builder instance.
166 *
167 * @param <K> key type
168 * @param <V> value type
169 * @return builder.
170 */
171 public static <K, V> Builder<K, V> newBuilder() {
172 return new Builder<>();
173 }
174
175 /**
176 * MapUpdate builder.
177 *
178 * @param <K> key type
179 * @param <V> value type
180 */
181 public static final class Builder<K, V> {
182
183 private MapUpdate<K, V> update = new MapUpdate<>();
184
185 public MapUpdate<K, V> build() {
186 validateInputs();
187 return update;
188 }
189
Madan Jampanicadd70b2016-02-08 13:45:43 -0800190 public Builder<K, V> withMapName(String name) {
191 update.mapName = checkNotNull(name, "name cannot be null");
192 return this;
193 }
194
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800195 public Builder<K, V> withType(Type type) {
196 update.type = checkNotNull(type, "type cannot be null");
197 return this;
198 }
199
200 public Builder<K, V> withKey(K key) {
201 update.key = checkNotNull(key, "key cannot be null");
202 return this;
203 }
204
205 public Builder<K, V> withCurrentValue(V value) {
Madan Jampani74da78b2016-02-09 21:18:36 -0800206 update.currentValue = value;
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800207 return this;
208 }
209
210 public Builder<K, V> withValue(V value) {
Madan Jampani74da78b2016-02-09 21:18:36 -0800211 update.value = value;
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800212 return this;
213 }
214
215 public Builder<K, V> withCurrentVersion(long version) {
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800216 update.currentVersion = version;
217 return this;
218 }
219
220 private void validateInputs() {
221 checkNotNull(update.type, "type must be specified");
222 checkNotNull(update.key, "key must be specified");
223 switch (update.type) {
224 case PUT:
225 case PUT_IF_ABSENT:
226 checkNotNull(update.value, "value must be specified.");
227 break;
228 case PUT_IF_VERSION_MATCH:
229 checkNotNull(update.value, "value must be specified.");
230 checkState(update.currentVersion >= 0, "current version must be specified");
231 break;
232 case PUT_IF_VALUE_MATCH:
233 checkNotNull(update.value, "value must be specified.");
234 checkNotNull(update.currentValue, "currentValue must be specified.");
235 break;
236 case REMOVE:
237 break;
238 case REMOVE_IF_VERSION_MATCH:
239 checkState(update.currentVersion >= 0, "current version must be specified");
240 break;
241 case REMOVE_IF_VALUE_MATCH:
242 checkNotNull(update.currentValue, "currentValue must be specified.");
243 break;
244 default:
245 throw new IllegalStateException("Unknown operation type");
246 }
247 }
248 }
249}