public EntityIdVersionAndEventIds updateEvent(String entityId, Int128 entityVersion, String eventData) { List<EventTypeAndData> events = Collections.singletonList(new EventTypeAndData(AccountCreatedEvent.class.getTypeName(), eventData, Optional.empty())); return localAggregateCrud.update(new EntityIdAndType(entityId, Account.class.getTypeName()), entityVersion, events, Optional.empty()); }
public OptimisticLockingException(EntityIdAndType entityIdAndType, Int128 entityVersion) { super(String.format("Couldn't update entity: %s, %s, %s", entityIdAndType.getEntityType(), entityIdAndType.getEntityId(), entityVersion)); this.entityIdAndType = entityIdAndType; this.entityVersion = entityVersion; }
@Override public <T extends Aggregate<T>> CompletableFuture<EntityIdAndVersion> update(Class<T> clasz, EntityIdAndVersion entityIdAndVersion, List<Event> events, Optional<UpdateOptions> updateOptions) { Optional<String> serializedMetadata = updateOptions.flatMap(UpdateOptions::getEventMetadata).map(JSonMapper::toJson); List<EventTypeAndData> serializedEvents = events.stream().map(event -> toEventTypeAndData(event, serializedMetadata)).collect(Collectors.toList()); CompletableFuture<EntityIdVersionAndEventIds> outcome = aggregateCrud.update(new EntityIdAndType(entityIdAndVersion.getEntityId(), clasz.getName()), entityIdAndVersion.getEntityVersion(), serializedEvents, AggregateCrudMapping.toAggregateCrudUpdateOptions(updateOptions)); if (activityLogger.isDebugEnabled()) return CompletableFutureUtil.tap(outcome, (result, throwable) -> { if (throwable == null) activityLogger.debug("Updated entity: {} {} {}", clasz.getName(), result.getEntityId(), AggregateCrudMapping.toSerializedEventsWithIds(serializedEvents, result.getEventIds())); else activityLogger.error(String.format("Update entity failed: %s %s", clasz.getName(), entityIdAndVersion), throwable); }).thenApply(EntityIdVersionAndEventIds::toEntityIdAndVersion); else return outcome.thenApply(EntityIdVersionAndEventIds::toEntityIdAndVersion); }
public OptimisticLockingException(EntityIdAndType entityIdAndType, Int128 entityVersion) { super(String.format("Couldn't update entity: %s, %s, %s", entityIdAndType.getEntityType(), entityIdAndType.getEntityId(), entityVersion)); this.entityIdAndType = entityIdAndType; this.entityVersion = entityVersion; }
@Override public <T extends Aggregate<T>> EntityIdAndVersion update(Class<T> clasz, EntityIdAndVersion entityIdAndVersion, List<Event> events, Optional<UpdateOptions> updateOptions) { try { Optional<String> serializedEventMetadata = updateOptions.flatMap(UpdateOptions::getEventMetadata).map(JSonMapper::toJson); List<EventTypeAndData> serializedEvents = events.stream().map(event -> toEventTypeAndData(event, serializedEventMetadata)).collect(Collectors.toList()); EntityIdVersionAndEventIds result = aggregateCrud.update(new EntityIdAndType(entityIdAndVersion.getEntityId(), clasz.getName()), entityIdAndVersion.getEntityVersion(), serializedEvents, toAggregateCrudUpdateOptions(updateOptions)); if (activityLogger.isDebugEnabled()) activityLogger.debug("Updated entity: {} {} {}", clasz.getName(), result.getEntityId(), toSerializedEventsWithIds(serializedEvents, result.getEventIds())); return result.toEntityIdAndVersion(); } catch (RuntimeException e) { if (activityLogger.isDebugEnabled()) activityLogger.error(String.format("Update entity failed: %s %s", clasz.getName(), entityIdAndVersion), e); throw e; } }
String entityType = entityIdAndType.getEntityType(); String aggregateType = entityIdAndType.getEntityType(); String entityId = entityIdAndType.getEntityId();
@Override public <T extends Aggregate<T>> CompletableFuture<EntityIdAndVersion> update(Class<T> clasz, EntityIdAndVersion entityIdAndVersion, List<Event> events, Optional<UpdateOptions> updateOptions) { Optional<String> serializedMetadata = updateOptions.flatMap(UpdateOptions::getEventMetadata).map(JSonMapper::toJson); List<EventTypeAndData> serializedEvents = events.stream().map(event -> toEventTypeAndData(event, serializedMetadata)).collect(Collectors.toList()); CompletableFuture<EntityIdVersionAndEventIds> outcome = aggregateCrud.update(new EntityIdAndType(entityIdAndVersion.getEntityId(), clasz.getName()), entityIdAndVersion.getEntityVersion(), serializedEvents, AggregateCrudMapping.toAggregateCrudUpdateOptions(updateOptions)); if (activityLogger.isDebugEnabled()) return CompletableFutureUtil.tap(outcome, (result, throwable) -> { if (throwable == null) activityLogger.debug("Updated entity: {} {} {}", clasz.getName(), result.getEntityId(), AggregateCrudMapping.toSerializedEventsWithIds(serializedEvents, result.getEventIds())); else activityLogger.error(String.format("Update entity failed: %s %s", clasz.getName(), entityIdAndVersion), throwable); }).thenApply(EntityIdVersionAndEventIds::toEntityIdAndVersion); else return outcome.thenApply(EntityIdVersionAndEventIds::toEntityIdAndVersion); }
return withRetry(() -> { if (logger.isDebugEnabled()) logger.debug("update: " + aggregateIdAndType.getEntityType() + ", " + aggregateIdAndType.getEntityId() + ", " + ", events" + events + ", " + updateOptions); httpClient.post(makePath() + "/" + aggregateIdAndType.getEntityType() + "/" + aggregateIdAndType.getEntityId()) .handler(response -> { if (logger.isDebugEnabled())
@Override public <T extends Aggregate<T>> EntityIdAndVersion update(Class<T> clasz, EntityIdAndVersion entityIdAndVersion, List<Event> events, Optional<UpdateOptions> updateOptions) { try { Optional<String> serializedEventMetadata = updateOptions.flatMap(UpdateOptions::getEventMetadata).map(JSonMapper::toJson); List<EventTypeAndData> serializedEvents = events.stream().map(event -> toEventTypeAndData(event, serializedEventMetadata)).collect(Collectors.toList()); EntityIdVersionAndEventIds result = aggregateCrud.update(new EntityIdAndType(entityIdAndVersion.getEntityId(), clasz.getName()), entityIdAndVersion.getEntityVersion(), serializedEvents, toAggregateCrudUpdateOptions(updateOptions)); if (activityLogger.isDebugEnabled()) activityLogger.debug("Updated entity: {} {} {}", clasz.getName(), result.getEntityId(), toSerializedEventsWithIds(serializedEvents, result.getEventIds())); return result.toEntityIdAndVersion(); } catch (RuntimeException e) { if (activityLogger.isDebugEnabled()) activityLogger.error(String.format("Update entity failed: %s %s", clasz.getName(), entityIdAndVersion), e); throw e; } }
return withRetry(() -> { if (logger.isDebugEnabled()) logger.debug("update: " + aggregateIdAndType.getEntityType() + ", " + aggregateIdAndType.getEntityId() + ", " + ", events" + events + ", " + updateOptions); httpClient.post(makePath() + "/" + aggregateIdAndType.getEntityType() + "/" + aggregateIdAndType.getEntityId()) .handler(response -> { if (logger.isDebugEnabled())
private CompletableFuture<EntityIdVersionAndEventIds> update() { return client.update(new EntityIdAndType(RequestResponseJsonObjects.ENTITY_ID, RequestResponseJsonObjects.aggregateType), new Int128(5, 6), Collections.singletonList(new EventTypeAndData(RequestResponseJsonObjects.debitedEvent, RequestResponseJsonObjects.eventData, Optional.empty())), Optional.empty()); }
private CompletableFuture<EntityIdVersionAndEventIds> updateWithEventContext() { return client.update(new EntityIdAndType(RequestResponseJsonObjects.ENTITY_ID, RequestResponseJsonObjects.aggregateType), new Int128(5, 6), Collections.singletonList(new EventTypeAndData(RequestResponseJsonObjects.debitedEvent, RequestResponseJsonObjects.eventData, Optional.empty())), Optional.of(new AggregateCrudUpdateOptions().withTriggeringEvent(RequestResponseJsonObjects.makeEventContext()))); }
handleErrorResponse(cf, response, new EntityIdAndType(entityId, aggregateType), null);
handleErrorResponse(cf, response, new EntityIdAndType(entityId, aggregateType), null);
@Test public void updateShouldCompleteWithOptimisticLockingException() throws ExecutionException, InterruptedException { EntityIdVersionAndEventIds eidv = eventStore.save(aggregateType, singletonList(new EventTypeAndData("MyEventType", "{}", Optional.empty())), Optional.of(new AggregateCrudSaveOptions().withEventContext(ectx))); shouldCompletedExceptionally(OptimisticLockingException.class, () -> eventStore.update(new EntityIdAndType(eidv.getEntityId(), aggregateType), new Int128(0,0), singletonList(new EventTypeAndData("MyEventType", "{}", Optional.empty())), Optional.of(new AggregateCrudUpdateOptions()))); }
@Test public void shouldHandleErrorAfterServiceUnavailable() throws InterruptedException, ExecutionException, TimeoutException { mockHttpServer.expect().respondingWith(503); mockHttpServer.expect().respondingWith(409, RequestResponseJsonObjects.makeOptimisticLockingErrorResponse()); CompletableFuture<EntityIdVersionAndEventIds> f = client.update(new EntityIdAndType(RequestResponseJsonObjects.ENTITY_ID, RequestResponseJsonObjects.aggregateType), new Int128(5, 6), Collections.singletonList(new EventTypeAndData(RequestResponseJsonObjects.debitedEvent, RequestResponseJsonObjects.eventData, Optional.empty())), Optional.empty()); try { f.get(4, TimeUnit.SECONDS); fail(); } catch (ExecutionException e) { if (!(e.getCause() instanceof OptimisticLockingException)) throw e; } mockHttpServer.assertSatisfied(); }
@Test public void shouldSaveAndLoadSnapshot() { EntityIdVersionAndEventIds eidv = eventStore.save(aggregateType, singletonList(new EventTypeAndData("MyEventType", "{}", Optional.empty())), Optional.of(new AggregateCrudSaveOptions().withEventContext(ectx))); EntityIdVersionAndEventIds updateResult = eventStore.update( new EntityIdAndType(eidv.getEntityId(), aggregateType), eidv.getEntityVersion(), singletonList(new EventTypeAndData("MyEventType", "{}", Optional.empty())), Optional.of(new AggregateCrudUpdateOptions().withSnapshot(new SerializedSnapshot("X", "Y")))); LoadedEvents findResult = eventStore.find(aggregateType, eidv.getEntityId(), Optional.of(new AggregateCrudFindOptions())); assertTrue(findResult.getSnapshot().isPresent()); assertTrue(findResult.getEvents().isEmpty()); }
handleErrorResponse(cf, response, new EntityIdAndType(null, aggregateType), null);
handleErrorResponse(cf, response, new EntityIdAndType(null, aggregateType), null);
@Test public void shouldSaveAndLoadEventMetadata() throws InterruptedException { String saveMetadata = "MyMetaData"; String updateMetadata = "MyMetaDataForUpdate"; LinkedBlockingQueue<SerializedEvent> events = new LinkedBlockingQueue<>(); aggregateEvents.subscribe("shouldSaveAndLoadEventMetadata", singletonMap(aggregateType, singleton("MyEventType")), new SubscriberOptions(), se -> { events.add(se); return new CompletableFuture<Object>(); }); EntityIdVersionAndEventIds eidv = eventStore.save(aggregateType, singletonList(new EventTypeAndData("MyEventType", "{}", Optional.of(saveMetadata))), Optional.empty()); LoadedEvents findResult = eventStore.find(aggregateType, eidv.getEntityId(), Optional.of(new AggregateCrudFindOptions())); assertEquals(Optional.of(saveMetadata), findResult.getEvents().get(0).getMetadata()); EntityIdVersionAndEventIds updateResult = eventStore.update( new EntityIdAndType(eidv.getEntityId(), aggregateType), eidv.getEntityVersion(), singletonList(new EventTypeAndData("MyEventType", "{}", Optional.of(updateMetadata))), Optional.empty()); LoadedEvents findResult2 = eventStore.find(aggregateType, eidv.getEntityId(), Optional.of(new AggregateCrudFindOptions())); assertEquals(Optional.of(saveMetadata), findResult2.getEvents().get(0).getMetadata()); assertEquals(Optional.of(updateMetadata), findResult2.getEvents().get(1).getMetadata()); assertContainsEventWithMetadata(eidv.getEventIds().get(0), saveMetadata, events); assertContainsEventWithMetadata(updateResult.getEventIds().get(0), updateMetadata, events); }