blob: e04f10e12b13908c7cfcc708fa050acb7e8e8e8b [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
Jordan Halterman948d6592017-04-20 17:18:24 -070022import java.util.Objects;
Madan Jampani74da78b2016-02-09 21:18:36 -080023import java.util.function.Function;
24
Madan Jampani3780d4b2016-04-04 18:18:24 -070025import org.onlab.util.ByteArraySizeHashPrinter;
26
Madan Jampani5e5b3d62016-02-01 16:03:33 -080027import com.google.common.base.MoreObjects;
28
29/**
30 * Map update operation.
31 *
32 * @param <K> map key type
33 * @param <V> map value type
34 *
35 */
36public final class MapUpdate<K, V> {
37
38 /**
39 * Type of database update operation.
40 */
41 public enum Type {
42 /**
43 * Insert/Update entry without any checks.
44 */
45 PUT,
Jordan Halterman948d6592017-04-20 17:18:24 -070046
Madan Jampani5e5b3d62016-02-01 16:03:33 -080047 /**
48 * Insert an entry iff there is no existing entry for that key.
49 */
50 PUT_IF_ABSENT,
51
52 /**
53 * Update entry if the current version matches specified version.
54 */
55 PUT_IF_VERSION_MATCH,
56
57 /**
58 * Update entry if the current value matches specified value.
59 */
60 PUT_IF_VALUE_MATCH,
61
62 /**
63 * Remove entry without any checks.
64 */
65 REMOVE,
66
67 /**
68 * Remove entry if the current version matches specified version.
69 */
70 REMOVE_IF_VERSION_MATCH,
71
72 /**
73 * Remove entry if the current value matches specified value.
74 */
75 REMOVE_IF_VALUE_MATCH,
76 }
77
78 private Type type;
79 private K key;
80 private V value;
81 private V currentValue;
82 private long currentVersion = -1;
83
84 /**
85 * Returns the type of update operation.
86 * @return type of update.
87 */
88 public Type type() {
89 return type;
90 }
91
92 /**
93 * Returns the item key being updated.
94 * @return item key
95 */
96 public K key() {
97 return key;
98 }
99
100 /**
101 * Returns the new value.
102 * @return item's target value.
103 */
104 public V value() {
105 return value;
106 }
107
108 /**
109 * Returns the expected current value for the key.
110 * @return current value in database.
111 */
112 public V currentValue() {
113 return currentValue;
114 }
115
116 /**
117 * Returns the expected current version in the database for the key.
118 * @return expected version.
119 */
120 public long currentVersion() {
121 return currentVersion;
122 }
123
Madan Jampani74da78b2016-02-09 21:18:36 -0800124 /**
125 * Transforms this instance into an instance of different paramterized types.
126 *
127 * @param keyMapper transcoder for key type
128 * @param valueMapper transcoder to value type
129 * @return new instance
130 * @param <S> key type of returned instance
131 * @param <T> value type of returned instance
132 */
133 public <S, T> MapUpdate<S, T> map(Function<K, S> keyMapper, Function<V, T> valueMapper) {
134 return MapUpdate.<S, T>newBuilder()
Madan Jampani74da78b2016-02-09 21:18:36 -0800135 .withType(type)
136 .withKey(keyMapper.apply(key))
137 .withValue(value == null ? null : valueMapper.apply(value))
138 .withCurrentValue(currentValue == null ? null : valueMapper.apply(currentValue))
139 .withCurrentVersion(currentVersion)
140 .build();
141 }
142
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800143 @Override
Jordan Halterman948d6592017-04-20 17:18:24 -0700144 public int hashCode() {
145 return Objects.hash(type, key, value, currentValue, currentVersion);
146 }
147
148 @Override
149 public boolean equals(Object object) {
150 if (object instanceof MapUpdate) {
151 MapUpdate that = (MapUpdate) object;
152 return this.type == that.type
153 && Objects.equals(this.key, that.key)
154 && Objects.equals(this.value, that.value)
155 && Objects.equals(this.currentValue, that.currentValue)
156 && Objects.equals(this.currentVersion, that.currentVersion);
157 }
158 return false;
159 }
160
161 @Override
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800162 public String toString() {
163 return MoreObjects.toStringHelper(this)
164 .add("type", type)
165 .add("key", key)
Madan Jampani3780d4b2016-04-04 18:18:24 -0700166 .add("value", value instanceof byte[] ? new ByteArraySizeHashPrinter((byte[]) value) : value)
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800167 .add("currentValue", currentValue)
168 .add("currentVersion", currentVersion)
169 .toString();
170 }
171
172 /**
173 * Creates a new builder instance.
174 *
175 * @param <K> key type
176 * @param <V> value type
177 * @return builder.
178 */
179 public static <K, V> Builder<K, V> newBuilder() {
180 return new Builder<>();
181 }
182
183 /**
184 * MapUpdate builder.
185 *
186 * @param <K> key type
187 * @param <V> value type
188 */
189 public static final class Builder<K, V> {
190
191 private MapUpdate<K, V> update = new MapUpdate<>();
192
193 public MapUpdate<K, V> build() {
194 validateInputs();
195 return update;
196 }
197
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800198 public Builder<K, V> withType(Type type) {
199 update.type = checkNotNull(type, "type cannot be null");
200 return this;
201 }
202
203 public Builder<K, V> withKey(K key) {
204 update.key = checkNotNull(key, "key cannot be null");
205 return this;
206 }
207
208 public Builder<K, V> withCurrentValue(V value) {
Madan Jampani74da78b2016-02-09 21:18:36 -0800209 update.currentValue = value;
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800210 return this;
211 }
212
213 public Builder<K, V> withValue(V value) {
Madan Jampani74da78b2016-02-09 21:18:36 -0800214 update.value = value;
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800215 return this;
216 }
217
218 public Builder<K, V> withCurrentVersion(long version) {
Madan Jampani5e5b3d62016-02-01 16:03:33 -0800219 update.currentVersion = version;
220 return this;
221 }
222
223 private void validateInputs() {
224 checkNotNull(update.type, "type must be specified");
225 checkNotNull(update.key, "key must be specified");
226 switch (update.type) {
227 case PUT:
228 case PUT_IF_ABSENT:
229 checkNotNull(update.value, "value must be specified.");
230 break;
231 case PUT_IF_VERSION_MATCH:
232 checkNotNull(update.value, "value must be specified.");
233 checkState(update.currentVersion >= 0, "current version must be specified");
234 break;
235 case PUT_IF_VALUE_MATCH:
236 checkNotNull(update.value, "value must be specified.");
237 checkNotNull(update.currentValue, "currentValue must be specified.");
238 break;
239 case REMOVE:
240 break;
241 case REMOVE_IF_VERSION_MATCH:
242 checkState(update.currentVersion >= 0, "current version must be specified");
243 break;
244 case REMOVE_IF_VALUE_MATCH:
245 checkNotNull(update.currentValue, "currentValue must be specified.");
246 break;
247 default:
248 throw new IllegalStateException("Unknown operation type");
249 }
250 }
251 }
252}