@Override public Optional<String> lookup(Map<String, Object> coordinates) throws LookupFailureException { try { final Bucket bucket = couchbaseClusterService.openBucket(bucketName); final Optional<String> docId = Optional.ofNullable(coordinates.get(KEY)).map(Object::toString); if (!StringUtils.isBlank(subDocPath)) { return docId.map(key -> { try { return bucket.lookupIn(key).get(subDocPath).execute(); } catch (DocumentDoesNotExistException e) { getLogger().debug("Document was not found for {}", new Object[]{key}); return null; } }).map(fragment -> fragment.content(0)).map(Object::toString); } else { return docId.map(key -> CouchbaseUtils.getStringContent(bucket, key)); } } catch (CouchbaseException e) { throw new LookupFailureException("Failed to lookup from Couchbase using this coordinates: " + coordinates); } }
@Override public boolean containsKey(Object key) { return (Boolean) bucket .lookupIn(id).exists(String.valueOf(key)) .execute() .content(0); }
@Override public V get(Object key) { if (key == null) { throw new NullPointerException("Unsupported null key"); } try { return (V) bucket.lookupIn(id) .get(String.valueOf(key)) .execute() .content(0); } catch (PathNotFoundException e) { return null; } }
@Override public E get(int index) { //fail fast on negative values, as they are interpreted as "starting from the back of the array" otherwise if (index < 0) { throw new IndexOutOfBoundsException("Index: " + index); } String idx = "[" + index + "]"; DocumentFragment<Lookup> result = bucket.lookupIn(id).get(idx).execute(); if (result.status(idx) == ResponseStatus.SUBDOC_PATH_NOT_FOUND) { throw new IndexOutOfBoundsException("Index: " + index); } return (E) result.content(idx); }
@Override public boolean isEmpty() { DocumentFragment<Lookup> current = bucket.lookupIn(id).exists("[0]").execute(); return current.status("[0]") == ResponseStatus.SUBDOC_PATH_NOT_FOUND; }
@Override public boolean isEmpty() { DocumentFragment<Lookup> current = bucket.lookupIn(id).exists("[0]").execute(); return current.status(0) == ResponseStatus.SUBDOC_PATH_NOT_FOUND; }
@Override public E peek() { try { DocumentFragment<Lookup> current = bucket.lookupIn(id).get("[0]").execute(); Object result = current.content(0); return (E) result; } catch (MultiMutationException ex) { if (ex.firstFailureStatus() == ResponseStatus.SUBDOC_PATH_NOT_FOUND) { return null; //the queue is empty } throw ex; } } }
private JsonNode readDocument(String documentId) throws IOException { if (xattrs) { try { final DocumentFragment<Lookup> lookup = bucket.lookupIn(documentId) .get(XATTR_NAME, new SubdocOptionsBuilder().xattr(true)) .execute(); final JsonObject content = (JsonObject) lookup.content(0); return mapper.readTree(content.toString()); } catch (Exception e) { return null; } } else { RawJsonDocument doc = bucket.get(RawJsonDocument.create(documentId)); if (doc == null) { return null; } return mapper.readTree(doc.content()); } } }
@Override public V remove(Object key) { if (key == null) { throw new NullPointerException("Unsupported null key"); } String idx = String.valueOf(key); for(int i = 0; i < MAX_OPTIMISTIC_LOCKING_ATTEMPTS; i++) { try { DocumentFragment<Lookup> current = bucket.lookupIn(id).get(idx).execute(); long returnCas = current.cas(); Object result = current.content(idx); DocumentFragment<Mutation> updated = bucket.mutateIn(id).remove(idx).withCas(returnCas).execute(); return (V) result; } catch (CASMismatchException ex) { //will have to retry get-and-remove } catch (MultiMutationException ex) { if (ex.firstFailureStatus() == ResponseStatus.SUBDOC_PATH_NOT_FOUND) { return null; } throw ex; } } throw new ConcurrentModificationException("Couldn't perform remove in less than " + MAX_OPTIMISTIC_LOCKING_ATTEMPTS + " iterations"); }
@Override public E remove(int index) { //fail fast on negative values, as they are interpreted as "starting from the back of the array" otherwise if (index < 0) { throw new IndexOutOfBoundsException("Index: " + index); } String idx = "[" + index + "]"; for(int i = 0; i < MAX_OPTIMISTIC_LOCKING_ATTEMPTS; i++) { try { DocumentFragment<Lookup> current = bucket.lookupIn(id).get(idx).execute(); long returnCas = current.cas(); Object result = current.content(idx); DocumentFragment<Mutation> updated = bucket.mutateIn(id).remove(idx).withCas(returnCas).execute(); return (E) result; } catch (CASMismatchException ex) { //will have to retry get-and-remove } catch (MultiMutationException ex) { if (ex.firstFailureStatus() == ResponseStatus.SUBDOC_PATH_NOT_FOUND) { throw new IndexOutOfBoundsException("Index: " + index); } throw ex; } } throw new ConcurrentModificationException("Couldn't perform remove in less than " + MAX_OPTIMISTIC_LOCKING_ATTEMPTS + " iterations"); }
@Override public E set(int index, E element) { //fail fast on negative values, as they are interpreted as "starting from the back of the array" otherwise if (index < 0) { throw new IndexOutOfBoundsException("Index: " + index); } if (!JsonValue.checkType(element)) { throw new IllegalArgumentException("Unsupported value type."); } String idx = "["+index+"]"; for(int i = 0; i < MAX_OPTIMISTIC_LOCKING_ATTEMPTS; i++) { try { DocumentFragment<Lookup> current = bucket.lookupIn(id).get(idx).execute(); long returnCas = current.cas(); Object result = current.content(idx); bucket.mutateIn(id).replace(idx, element).withCas(returnCas).execute(); return (E) result; } catch (CASMismatchException ex) { //will need to retry get-and-set } catch (MultiMutationException ex) { if (ex.firstFailureStatus() == ResponseStatus.SUBDOC_PATH_NOT_FOUND || ex.firstFailureStatus() == ResponseStatus.SUBDOC_PATH_INVALID) { throw new IndexOutOfBoundsException("Index: " + index); } throw ex; } } throw new ConcurrentModificationException("Couldn't perform set in less than " + MAX_OPTIMISTIC_LOCKING_ATTEMPTS + " iterations"); }
@Override public V put(String key, V value) { if (key == null) { throw new NullPointerException("Unsupported null key"); } if (!JsonValue.checkType(value)) { throw new IllegalArgumentException("Unsupported value type."); } for(int i = 0; i < MAX_OPTIMISTIC_LOCKING_ATTEMPTS; i++) { try { DocumentFragment<Lookup> current = bucket.lookupIn(id).get(key).execute(); long returnCas = current.cas(); Object result = null; if (current.exists(key)) { result = current.content(key); } bucket.mutateIn(id).upsert(key, value, false).withCas(returnCas).execute(); return (V) result; } catch (CASMismatchException ex) { //will need to retry get-and-set } } throw new ConcurrentModificationException("Couldn't perform put in less than " + MAX_OPTIMISTIC_LOCKING_ATTEMPTS + " iterations"); }
@Override public E poll() { String idx = "[-1]"; //FIFO queue as offer uses ARRAY_PREPEND for(int i = 0; i < MAX_OPTIMISTIC_LOCKING_ATTEMPTS; i++) { try { DocumentFragment<Lookup> current = bucket.lookupIn(id).get(idx).execute(); long returnCas = current.cas(); Object result = current.content(idx); DocumentFragment<Mutation> updated = bucket.mutateIn(id).remove(idx).withCas(returnCas).execute(); return (E) result; } catch (CASMismatchException ex) { //will have to retry get-and-remove } catch (MultiMutationException ex) { if (ex.firstFailureStatus() == ResponseStatus.SUBDOC_PATH_NOT_FOUND) { return null; //the queue is empty } throw ex; } } throw new ConcurrentModificationException("Couldn't perform poll in less than " + MAX_OPTIMISTIC_LOCKING_ATTEMPTS + " iterations"); }