default Document getPatchedDocument(RetrieveLatestDao retrieveLatestDao, PatchRequest request, Optional<Long> optionalTimestamp ) throws OriginalNotFoundException, IOException { String guid = request.getGuid(); String sensorType = request.getSensorType(); String documentID = null; Long timestamp = optionalTimestamp.orElse(System.currentTimeMillis()); Map<String, Object> originalSource = request.getSource(); if (originalSource == null) { // no document source provided, lookup the latest Document toPatch = retrieveLatestDao.getLatest(guid, sensorType); if(toPatch != null && toPatch.getDocument() != null) { originalSource = toPatch.getDocument(); documentID = toPatch.getDocumentID().orElse(null); } else { String error = format("Document does not exist, but is required; guid=%s, sensorType=%s", guid, sensorType); throw new OriginalNotFoundException(error); } } Map<String, Object> patchedSource = JSONUtils.INSTANCE.applyPatch(request.getPatch(), originalSource); return new Document(patchedSource, guid, sensorType, timestamp, documentID); } }
/** * Update a document in an index given a JSON Patch (see RFC 6902 at * https://tools.ietf.org/html/rfc6902) * @param request The patch request * @param timestamp Optionally a timestamp to set. If not specified then current time is used. * @return The patched document. * @throws OriginalNotFoundException If the original is not found, then it cannot be patched. * @throws IOException If an error occurs while patching. */ default Document patch(RetrieveLatestDao retrieveLatestDao, PatchRequest request , Optional<Long> timestamp ) throws OriginalNotFoundException, IOException { Document d = getPatchedDocument(retrieveLatestDao, request, timestamp); return update(d, Optional.ofNullable(request.getIndex())); }
private void escalateMetaAlert(String guid) throws Exception { // create the patch that 'escalates' the meta-alert Map<String, Object> patch = new HashMap<>(); patch.put("op", "add"); patch.put("path", "/alert_status"); patch.put("value", "escalate"); // 'escalate' the meta-alert PatchRequest patchRequest = new PatchRequest(); patchRequest.setGuid(guid); patchRequest.setIndex(getMetaAlertIndex()); patchRequest.setSensorType(METAALERT_TYPE); patchRequest.setPatch(Collections.singletonList(patch)); metaDao.patch(metaDao, patchRequest, Optional.of(System.currentTimeMillis())); // ensure the alert status was changed to 'escalate' assertEventually(() -> { Document updated = metaDao.getLatest(guid, METAALERT_TYPE); Assert.assertEquals("escalate", updated.getDocument().get("alert_status")); }); }
@Test @SuppressWarnings("unchecked") public void testPatchNotAllowedAlert() throws ParseException { PatchRequest pr = new PatchRequest(); Map<String, Object> patch = (JSONObject) new JSONParser().parse(alertPatchRequest); pr.setPatch(Collections.singletonList((JSONObject) ((JSONArray) patch.get("patch")).get(0))); assertFalse(dao.isPatchAllowed(pr)); }
/** * Determines if a given patch request is allowed or not. By default patching the 'alert' or * 'status' fields are not allowed, because they should be updated via the specific methods. * @param request The patch request to examine * @return True if patch can be performed, false otherwise */ default boolean isPatchAllowed(PatchRequest request) { if (request.getPatch() != null && !request.getPatch().isEmpty()) { for (Map<String, Object> patch : request.getPatch()) { Object pathObj = patch.get("path"); if (pathObj != null && pathObj instanceof String) { String path = (String) pathObj; if (STATUS_PATH.equals(path) || ALERT_PATH.equals(path)) { return false; } } } } return true; }
@Test public void testPatchDocumentThatHasComment() throws Exception { Document document = createAndIndexDocument("testPatchDocumentWithComment"); // comment on the document String commentText = "New Comment"; String commentUser = "test_user"; long commentTimestamp = 152630493050L; Document withComment = addAlertComment(document.getGuid(), commentText, commentUser, commentTimestamp); // create a patch List<Map<String, Object>> patches = new ArrayList<>(); Map<String, Object> patch = new HashMap<>(); patch.put("op", "add"); patch.put("path", "/project"); patch.put("value", "metron"); patches.add(patch); PatchRequest pr = new PatchRequest(); pr.setGuid(withComment.getGuid()); pr.setIndex(SENSOR_NAME); pr.setSensorType(SENSOR_NAME); pr.setPatch(patches); // patch the document that has been commented on Document patched = getDao().patch(getDao(), pr, Optional.of(withComment.getTimestamp())); Assert.assertEquals("metron", patched.getDocument().get("project")); // ensure the patch was made on the indexed document Document indexed = findUpdatedDoc(patched.getDocument(), patched.getGuid(), SENSOR_NAME); Assert.assertEquals("metron", indexed.getDocument().get("project")); }
@Test @SuppressWarnings("unchecked") public void testPatchNotAllowedStatus() throws ParseException { PatchRequest pr = new PatchRequest(); Map<String, Object> patch = (JSONObject) new JSONParser().parse(statusPatchRequest); pr.setPatch(Collections.singletonList((JSONObject) ((JSONArray) patch.get("patch")).get(0))); assertFalse(dao.isPatchAllowed(pr)); }
@Test @SuppressWarnings("unchecked") public void testPatchAllowedName() throws ParseException { PatchRequest pr = new PatchRequest(); Map<String, Object> patch = (JSONObject) new JSONParser().parse(namePatchRequest); pr.setPatch(Collections.singletonList((JSONObject) ((JSONArray) patch.get("patch")).get(0))); assertTrue(dao.isPatchAllowed(pr)); }