blob: 2efa0b0802c70b9ce97b227460da2c7154acc782 [file] [log] [blame]
Jonathan Hart6df90172014-04-03 10:13:11 -07001package net.onrc.onos.core.datastore.utils;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -07002
3import java.util.ArrayList;
4import java.util.HashMap;
5import java.util.Iterator;
6import java.util.List;
7import java.util.Map;
8
Jonathan Hart6df90172014-04-03 10:13:11 -07009import net.onrc.onos.core.datastore.DataStoreClient;
10import net.onrc.onos.core.datastore.IKVClient;
11import net.onrc.onos.core.datastore.IKVTable;
Jonathan Harta99ec672014-04-03 11:30:34 -070012import net.onrc.onos.core.datastore.IKVTable.IKVEntry;
Jonathan Hart6df90172014-04-03 10:13:11 -070013import net.onrc.onos.core.datastore.IKVTableID;
14import net.onrc.onos.core.datastore.IMultiEntryOperation;
15import net.onrc.onos.core.datastore.IMultiObjectOperation;
16import net.onrc.onos.core.datastore.ObjectDoesntExistException;
17import net.onrc.onos.core.datastore.ObjectExistsException;
18import net.onrc.onos.core.datastore.WrongVersionException;
Jonathan Hart6df90172014-04-03 10:13:11 -070019import net.onrc.onos.core.datastore.internal.IModifiableMultiEntryOperation;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070020
21import org.slf4j.Logger;
22import org.slf4j.LoggerFactory;
23
24import com.esotericsoftware.kryo.Kryo;
25import com.esotericsoftware.kryo.io.Input;
26import com.esotericsoftware.kryo.io.Output;
27
28/**
29 * Class to represent an Object represented as a single K-V pair Value blob.
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070030 */
31public class KVObject {
32 private static final Logger log = LoggerFactory.getLogger(KVObject.class);
33
34 // Default Kryo serializer.
35 // each sub-class should prepare their own serializer, which has required
36 // objects registered for better performance.
Ray Milkey5c9f2db2014-04-09 10:31:21 -070037 private static final ThreadLocal<Kryo> DEFAULT_KRYO = new ThreadLocal<Kryo>() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070038 @Override
39 protected Kryo initialValue() {
40 Kryo kryo = new Kryo();
41 // kryo.setRegistrationRequired(true);
42 // kryo.setReferences(false);
43 return kryo;
44 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070045 };
46
47 private final IKVTable table;
48 private final byte[] key;
49
50 /**
51 * serialized value version stored on data store or
Ray Milkey7531a342014-04-11 15:08:12 -070052 * {@link IKVTable.getVersionNonexistant()} if is a new object.
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070053 */
54 private long version;
55
56 /**
Ray Milkeyb41100a2014-04-10 10:42:15 -070057 * Map to store user-defined properties.
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070058 */
59 private Map<Object, Object> propertyMap;
60
61 public KVObject(final IKVTable table, final byte[] key) {
Ray Milkey7531a342014-04-11 15:08:12 -070062 this(table, key, null, table.getVersionNonexistant());
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070063 }
64
65 public KVObject(final IKVTable table, final byte[] key, final byte[] value, final long version) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070066 if (table == null) {
67 throw new IllegalArgumentException("table cannot be null");
68 }
69 if (key == null) {
70 throw new IllegalArgumentException("key cannot be null");
71 }
72 this.table = table;
Yuta HIGUCHIce7e7f82014-04-15 21:37:38 -070073 this.key = key.clone();
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070074 this.version = version;
75 this.propertyMap = new HashMap<Object, Object>();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070076
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070077 if (value != null) {
78 deserialize(value);
79 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070080 }
81
82 protected static KVObject createFromKey(final byte[] key) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070083 // Equivalent of this method is expected to be implemented by SubClasses
84 throw new UnsupportedOperationException(
85 "createFromKey() is not expected to be called for RCObject");
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070086 }
87
88 public IKVTable getTable() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070089 return table;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070090 }
91
92 public IKVTableID getTableId() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -070093 return table.getTableId();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070094 }
95
96 public byte[] getKey() {
Yuta HIGUCHIce7e7f82014-04-15 21:37:38 -070097 return key.clone();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070098 }
99
100 public long getVersion() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700101 return version;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700102 }
103
104 /**
105 * Return user-defined object properties.
106 *
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700107 * @return Will return null, if never been set, or was not deserialized
Ray Milkey269ffb92014-04-03 14:43:30 -0700108 * @note Will not trigger deserialization
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700109 */
110 protected Map<Object, Object> getPropertyMap() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700111 return this.propertyMap;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700112 }
113
114 protected Map<Object, Object> replacePropertyMap(final Map<Object, Object> newMap) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700115 Map<Object, Object> oldMap = this.propertyMap;
116 this.propertyMap = newMap;
117 return oldMap;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700118 }
119
120 /**
121 * Serialize object.
Ray Milkey269ffb92014-04-03 14:43:30 -0700122 * <p/>
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700123 * sub-classes should override this method to customize serialization.
124 *
125 * @return serialized byte array
126 */
127 public byte[] serialize() {
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700128 return serializePropertyMap(DEFAULT_KRYO.get(), this.propertyMap);
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700129 }
130
131 protected byte[] serializePropertyMap(final Kryo kryo,
Ray Milkey269ffb92014-04-03 14:43:30 -0700132 final Map<Object, Object> propMap) {
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700133
134
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700135 // value
136 byte[] rcTemp = new byte[1024 * 1024];
137 Output output = new Output(rcTemp);
138 kryo.writeObject(output, propMap);
139 return output.toBytes();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700140 }
141
142
143 /**
144 * Deserialize using value and version stored in data store.
145 *
Ray Milkey269ffb92014-04-03 14:43:30 -0700146 * @param bytes serialized bytes
Ray Milkey5df613b2014-04-15 10:50:56 -0700147 * @param dataStoreVersion version of this {@code bytes}
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700148 * @return true if success
149 */
Ray Milkey5df613b2014-04-15 10:50:56 -0700150 public boolean deserialize(final byte[] bytes,
151 final long dataStoreVersion) {
152 version = dataStoreVersion;
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700153 return deserialize(bytes);
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700154 }
155
156 /**
157 * Deserialize object.
Ray Milkey269ffb92014-04-03 14:43:30 -0700158 * <p/>
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700159 * sub-classes should override this method to customize deserialization.
160 *
161 * @param bytes serialized byte array
162 * @return true if success
163 */
164 protected boolean deserialize(final byte[] bytes) {
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700165 deserializePropertyMap(DEFAULT_KRYO.get(), bytes);
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700166 return true;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700167 }
168
169 /**
170 * Deserialize and set {@link propertyMap}.
Ray Milkey269ffb92014-04-03 14:43:30 -0700171 *
172 * @param kryo serializer to use
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700173 * @param bytes Kryo serialized Map object
174 * @return true if success
175 */
176 protected boolean deserializePropertyMap(final Kryo kryo, final byte[] bytes) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700177 @SuppressWarnings("unchecked")
178 Map<Object, Object> map = deserializePropertyMap(kryo, bytes, HashMap.class);
179 if (map == null) {
180 map = new HashMap<>();
181 }
182 this.propertyMap = map;
183 return true;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700184 }
185
186 protected <T extends Map<?, ?>> T deserializePropertyMap(final Kryo kryo,
Ray Milkey269ffb92014-04-03 14:43:30 -0700187 final byte[] bytes, final Class<T> type) {
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700188
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700189 if (bytes == null || bytes.length == 0) {
190 return null;
191 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700192
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700193 Input input = new Input(bytes);
194 T map = kryo.readObject(input, type);
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700195
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700196 return map;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700197 }
198
199
200 /**
201 * Create an Object in DataStore.
Ray Milkey269ffb92014-04-03 14:43:30 -0700202 * <p/>
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700203 * Fails if the Object with same key already exists.
204 *
205 * @throws ObjectExistsException
206 */
207 public void create() throws ObjectExistsException {
208
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700209 if (this.propertyMap == null) {
210 log.warn("No object map was set. Setting empty Map.");
211 replacePropertyMap(new HashMap<Object, Object>());
212 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700213
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700214 this.version = table.create(key, this.serialize());
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700215 }
216
217 public void forceCreate() {
218
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700219 if (this.propertyMap == null) {
220 log.warn("No object map was set. Setting empty Map.");
221 replacePropertyMap(new HashMap<Object, Object>());
222 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700223
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700224 this.version = table.forceCreate(key, this.serialize());
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700225 }
226
227 /**
228 * Read an Object from DataStore.
Ray Milkey269ffb92014-04-03 14:43:30 -0700229 * <p/>
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700230 * Fails if the Object with the key does not exist.
231 *
232 * @throws ObjectDoesntExistException
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700233 */
234 public void read() throws ObjectDoesntExistException {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700235 IKVEntry e = table.read(key);
236 deserialize(e.getValue(), e.getVersion());
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700237 }
238
239 /**
240 * Update an existing Object in DataStore checking versions.
Ray Milkey269ffb92014-04-03 14:43:30 -0700241 * <p/>
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700242 * Fails if the Object with key does not exists, or conditional failure.
243 *
244 * @throws WrongVersionException
245 * @throws ObjectDoesntExistException
246 */
247 public void update() throws ObjectDoesntExistException,
Ray Milkey269ffb92014-04-03 14:43:30 -0700248 WrongVersionException {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700249 if (this.propertyMap == null) {
250 replacePropertyMap(new HashMap<Object, Object>());
251 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700252
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700253 this.version = table.update(key, this.serialize(), version);
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700254 }
255
256 /**
257 * Remove an existing Object in DataStore.
Ray Milkey269ffb92014-04-03 14:43:30 -0700258 * <p/>
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700259 * Fails if the Object with key does not exists.
260 *
261 * @throws ObjectDoesntExistException
262 * @throws WrongVersionException
263 */
264 public void delete() throws ObjectDoesntExistException,
Ray Milkey269ffb92014-04-03 14:43:30 -0700265 WrongVersionException {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700266 this.version = table.delete(key, this.version);
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700267 }
268
269 public void forceDelete() {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700270 this.version = table.forceDelete(key);
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700271 }
272
273 public WriteOp forceCreateOp(IKVClient client) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700274 return new WriteOp(client.forceCreateOp(getTableId(), getKey(), serialize()), this);
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700275 }
276
277 public WriteOp createOp(IKVClient client) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700278 return new WriteOp(client.createOp(getTableId(), getKey(), serialize()), this);
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700279 }
280
281 // this might not be needed?
282 public WriteOp readOp(IKVClient client) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700283 return new WriteOp(client.readOp(getTableId(), getKey()), this);
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700284 }
285
286 public WriteOp updateOp(IKVClient client) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700287 return new WriteOp(client.updateOp(getTableId(), getKey(), serialize(), getVersion()), this);
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700288 }
289
290 public WriteOp deleteOp(IKVClient client) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700291 return new WriteOp(client.deleteOp(getTableId(), getKey(), serialize(), getVersion()), this);
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700292 }
293
294 public WriteOp forceDeleteOp(IKVClient client) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700295 return new WriteOp(client.forceDeleteOp(getTableId(), getKey()), this);
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700296 }
297
298 /**
299 * Multi-read RCObjects.
Ray Milkey269ffb92014-04-03 14:43:30 -0700300 * <p/>
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700301 * If the blob value was read successfully, RCObject will deserialize them.
302 *
Ray Milkey269ffb92014-04-03 14:43:30 -0700303 * @param objects RCObjects to read
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700304 * @return true if there exist a failed read.
305 */
306 public static boolean multiRead(final List<? extends KVObject> objects) {
307
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700308 final IKVClient client = DataStoreClient.getClient();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700309
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700310 final ArrayList<IMultiEntryOperation> readOps = new ArrayList<>(objects.size());
311 for (KVObject o : objects) {
312 readOps.add(o.readOp(client));
313 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700314
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700315 boolean failExists = client.multiRead(readOps);
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700316
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700317 for (int i = 0; i < readOps.size(); ++i) {
318 KVObject obj = objects.get(i);
319 IMultiEntryOperation entry = readOps.get(i);
Ray Milkey269ffb92014-04-03 14:43:30 -0700320 if (entry.hasSucceeded()) {
321 if (!obj.deserialize(entry.getValue(), entry.getVersion())) {
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700322 //deserialize return true on success
323 failExists = true;
324 log.error("MultiRead error, failed to deserialize {}, {}", obj.getTable(), obj);
325 }
326 } else {
327 log.error("MultiRead error, skipping {}, {}", obj.getTable(), obj);
Ray Milkey7531a342014-04-11 15:08:12 -0700328 obj.version = obj.getTable().getVersionNonexistant();
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700329 failExists = true;
330 }
331 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700332
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700333 return failExists;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700334 }
335
336 /**
Ray Milkeyb41100a2014-04-10 10:42:15 -0700337 * TODO Extract common interface.
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700338 */
339 public static class WriteOp implements IMultiObjectOperation, IModifiableMultiEntryOperation {
340
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700341 private final IModifiableMultiEntryOperation base;
342 private final KVObject obj;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700343
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700344 public WriteOp(IMultiEntryOperation base, final KVObject obj) {
345 this.base = (IModifiableMultiEntryOperation) base;
346 this.obj = obj;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700347
Ray Milkey269ffb92014-04-03 14:43:30 -0700348 // switch (base.getOperation()) {
349 // case CREATE:
350 // case FORCE_CREATE:
351 // case UPDATE:
352 // break;
353 // default:
354 // throw new UnsupportedOperationException("Unexpected OPERATION:"+base.getOperation());
355 // }
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700356 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700357
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700358 @Override
359 public KVObject getObject() {
360 return obj;
361 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700362
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700363 @Deprecated
364 public OPERATION getOp() {
365 return this.getOperation();
366 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700367
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700368 @Override
369 public boolean hasSucceeded() {
370 return base.hasSucceeded();
371 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700372
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700373 @Override
374 public STATUS getStatus() {
375 return base.getStatus();
376 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700377
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700378 @Override
379 public IKVTableID getTableId() {
380 return base.getTableId();
381 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700382
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700383 @Override
384 public byte[] getKey() {
385 return base.getKey();
386 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700387
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700388 @Override
389 public byte[] getValue() {
390 return base.getValue();
391 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700392
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700393 @Override
394 public long getVersion() {
395 return base.getVersion();
396 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700397
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700398 @Override
399 public OPERATION getOperation() {
400 return base.getOperation();
401 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700402
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700403 @Override
404 public void setStatus(STATUS status) {
405 base.setStatus(status);
406 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700407
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700408 @Override
409 public void setValue(byte[] value, long version) {
410 base.setValue(value, version);
411 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700412
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700413 @Override
414 public void setVersion(long version) {
415 base.setVersion(version);
416 this.obj.version = version;
417 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700418
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700419 @Override
420 public IModifiableMultiEntryOperation getActualOperation() {
421 return base;
422 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700423 }
424
425 public static boolean multiWrite(final List<WriteOp> objects) {
426
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700427 final IKVClient client = DataStoreClient.getClient();
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700428
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700429 final ArrayList<IMultiEntryOperation> writeOps = new ArrayList<>(objects.size());
430 for (WriteOp o : objects) {
431 writeOps.add(o);
432 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700433
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700434 return client.multiWrite(writeOps);
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700435 }
436
437 public abstract static class AbstractObjectIterator<E extends KVObject> implements
Ray Milkey269ffb92014-04-03 14:43:30 -0700438 Iterator<E> {
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700439
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700440 protected Iterator<IKVEntry> enumerator;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700441
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700442 public AbstractObjectIterator(final IKVTable table) {
443 this.enumerator = table.getAllEntries().iterator();
444 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700445
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700446 @Override
447 public boolean hasNext() {
448 return enumerator.hasNext();
449 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700450
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700451 // Implement something similar to below to realize Iterator
Ray Milkey269ffb92014-04-03 14:43:30 -0700452 // @Override
453 // public E next() {
454 // IKVTable.IKVEntry o = enumerator.next();
455 // E obj = E.createFromKey(o.getKey());
456 // obj.deserialize(o.getValue(), o.getVersion());
457 // return obj;
458 // }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700459
Yuta HIGUCHI826b4a42014-03-24 13:10:33 -0700460 @Deprecated
461 @Override
462 public void remove() {
463 // TODO Not implemented, as I cannot find a use-case for it.
464 throw new UnsupportedOperationException("Not implemented yet");
465 }
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -0700466
467 }
468
469}