Skip to content

Commit

Permalink
Add artifact metadata update event and artifact delete event
Browse files Browse the repository at this point in the history
  • Loading branch information
carlesarnal committed Oct 1, 2024
1 parent 826fef7 commit 5d4261b
Show file tree
Hide file tree
Showing 12 changed files with 188 additions and 30 deletions.
Original file line number Diff line number Diff line change
@@ -1,42 +1,46 @@
package io.apicurio.registry.storage.dto;
package io.apicurio.registry.events;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.apicurio.registry.storage.dto.ArtifactMetaDataDto;
import io.apicurio.registry.storage.dto.OutboxEvent;

import java.util.UUID;

import static io.apicurio.registry.storage.StorageEventType.ARTIFACT_CREATED;

public class ArtifactCreatedEvent extends OutboxEvent {
public class ArtifactCreated extends OutboxEvent {

private static final ObjectMapper mapper = new ObjectMapper();

private final JsonNode designPayload;
private final JsonNode eventPayload;

private ArtifactCreatedEvent(String id, String aggregateId, JsonNode designPayload) {
super(id, aggregateId, ARTIFACT_CREATED.name());
this.designPayload = designPayload;
private ArtifactCreated(String id, String aggregateId, JsonNode eventPayload) {
super(id, aggregateId);
this.eventPayload = eventPayload;
}

public static ArtifactCreatedEvent of(ArtifactMetaDataDto artifactMetaDataDto) {
public static ArtifactCreated of(ArtifactMetaDataDto artifactMetaDataDto) {
String id = UUID.randomUUID().toString();
// TODO here we have to define the internal structure of the event, maybe use cloudevents?
ObjectNode asJson = mapper.createObjectNode().put("id", id)
.put("artifactId", artifactMetaDataDto.getArtifactId())
.put("name", artifactMetaDataDto.getName())
.put("description", artifactMetaDataDto.getDescription());
.put("description", artifactMetaDataDto.getDescription())
.put("eventType", ARTIFACT_CREATED.name());

return new ArtifactCreatedEvent(id, artifactMetaDataDto.getArtifactId(), asJson);
return new ArtifactCreated(id,
artifactMetaDataDto.getGroupId() + "-" + artifactMetaDataDto.getArtifactId(), asJson);
}

@Override
public String getType() {
return getEventType();
return ARTIFACT_CREATED.name();
}

@Override
public JsonNode getPayload() {
return designPayload;
return eventPayload;
}
}
41 changes: 41 additions & 0 deletions app/src/main/java/io/apicurio/registry/events/ArtifactDeleted.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package io.apicurio.registry.events;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.apicurio.registry.storage.dto.OutboxEvent;

import java.util.UUID;

import static io.apicurio.registry.storage.StorageEventType.ARTIFACT_DELETED;

public class ArtifactDeleted extends OutboxEvent {

private static final ObjectMapper mapper = new ObjectMapper();

private final JsonNode eventPayload;

private ArtifactDeleted(String id, String aggregateId, JsonNode eventPayload) {
super(id, aggregateId);
this.eventPayload = eventPayload;
}

public static ArtifactDeleted of(String groupId, String artifactId) {
String id = UUID.randomUUID().toString();
// TODO here we have to define the internal structure of the event, maybe use cloudevents?
ObjectNode asJson = mapper.createObjectNode().put("id", id).put("groupId", groupId)
.put("artifactId", artifactId).put("eventType", ARTIFACT_DELETED.name());

return new ArtifactDeleted(id, groupId + "-" + artifactId, asJson);
}

@Override
public String getType() {
return ARTIFACT_DELETED.name();
}

@Override
public JsonNode getPayload() {
return eventPayload;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package io.apicurio.registry.events;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.apicurio.registry.storage.dto.EditableArtifactMetaDataDto;
import io.apicurio.registry.storage.dto.OutboxEvent;

import java.util.UUID;

import static io.apicurio.registry.storage.StorageEventType.ARTIFACT_METADATA_UPDATED;

public class ArtifactMetadataUpdated extends OutboxEvent {

private static final ObjectMapper mapper = new ObjectMapper();

private final JsonNode eventPayload;

private ArtifactMetadataUpdated(String id, String aggregateId, JsonNode eventPayload) {
super(id, aggregateId);
this.eventPayload = eventPayload;
}

public static ArtifactMetadataUpdated of(String groupId, String artifactId,
EditableArtifactMetaDataDto artifactMetaDataDto) {
String id = UUID.randomUUID().toString();
// TODO here we have to define the internal structure of the event, maybe use cloudevents?
ObjectNode asJson = mapper.createObjectNode().put("id", id).put("groupId", groupId)
.put("artifactId", artifactId).put("name", artifactMetaDataDto.getName())
.put("owner", artifactMetaDataDto.getOwner())
.put("description", artifactMetaDataDto.getDescription())
.put("eventType", ARTIFACT_METADATA_UPDATED.name());

return new ArtifactMetadataUpdated(id, groupId + "-" + artifactId, asJson);
}

@Override
public String getType() {
return ARTIFACT_METADATA_UPDATED.name();
}

@Override
public JsonNode getPayload() {
return eventPayload;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@
import io.apicurio.registry.rest.v3.beans.VersionMetaData;
import io.apicurio.registry.rest.v3.beans.VersionSearchResults;
import io.apicurio.registry.rest.v3.beans.VersionSortBy;
import io.apicurio.registry.rest.v3.shared.CommonResourceOperations;
import io.apicurio.registry.rules.RuleApplicationType;
import io.apicurio.registry.rules.RulesService;
import io.apicurio.registry.storage.RegistryStorage.RetrievalBehavior;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ public enum StorageEventType {
/**
* The READY event type MUST be fired only once.
*/
READY, ARTIFACT_CREATED
READY, ARTIFACT_CREATED, ARTIFACT_DELETED, ARTIFACT_METADATA_UPDATED
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,10 @@ public abstract class OutboxEvent {

private final String id;
private final String aggregateId;
private final String eventType;

protected OutboxEvent(String id, String aggregateId, String eventType) {
protected OutboxEvent(String id, String aggregateId) {
this.id = id;
this.aggregateId = aggregateId;
this.eventType = eventType;
}

public String getId() {
Expand All @@ -22,10 +20,6 @@ public String getAggregateId() {
return aggregateId;
}

public String getEventType() {
return eventType;
}

public String getAggregateType() {
return "registry-events";
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
import io.apicurio.common.apps.config.Info;
import io.apicurio.common.apps.core.System;
import io.apicurio.registry.content.TypedContent;
import io.apicurio.registry.events.ArtifactCreated;
import io.apicurio.registry.events.ArtifactDeleted;
import io.apicurio.registry.events.ArtifactMetadataUpdated;
import io.apicurio.registry.exception.UnreachableCodeException;
import io.apicurio.registry.model.BranchId;
import io.apicurio.registry.model.GA;
Expand Down Expand Up @@ -530,7 +533,7 @@ public Pair<ArtifactMetaDataDto, ArtifactVersionMetaDataDto> createArtifact(Stri
pair = ImmutablePair.of(amdDto, null);
}

outboxEvent.fire(ArtifactCreatedEvent.of(amdDto));
outboxEvent.fire(ArtifactCreated.of(amdDto));
return pair;
});
} catch (Exception ex) {
Expand Down Expand Up @@ -607,8 +610,11 @@ private ArtifactVersionMetaDataDto createArtifactVersionRaw(Handle handle, boole
});
}

return handle.createQuery(sqlStatements.selectArtifactVersionMetaDataByGlobalId()).bind(0, globalId)
ArtifactVersionMetaDataDto avmd = handle
.createQuery(sqlStatements.selectArtifactVersionMetaDataByGlobalId()).bind(0, globalId)
.map(ArtifactVersionMetaDataDtoMapper.instance).one();

return avmd;
}

/**
Expand Down Expand Up @@ -767,6 +773,7 @@ public List<String> deleteArtifact(String groupId, String artifactId)

deleteAllOrphanedContentRaw(handle);

outboxEvent.fire(ArtifactDeleted.of(groupId, artifactId));
return versions;
});
}
Expand Down Expand Up @@ -1179,8 +1186,9 @@ public void updateArtifactMetaData(String groupId, String artifactId,
modified = true;
if (rowCount == 0) {
throw new ArtifactNotFoundException(groupId, artifactId);
} else {
outboxEvent.fire(ArtifactMetadataUpdated.of(groupId, artifactId, metaData));
}

}

return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

CREATE TABLE apicurio (propName VARCHAR(255) NOT NULL, propValue VARCHAR(255));
ALTER TABLE apicurio ADD PRIMARY KEY (propName);
INSERT INTO apicurio (propName, propValue) VALUES ('db_version', 100);
INSERT INTO apicurio (propName, propValue) VALUES ('db_version', 101);

CREATE TABLE sequences (seqName VARCHAR(32) NOT NULL, seqValue BIGINT NOT NULL);
ALTER TABLE sequences ADD PRIMARY KEY (seqName);
Expand Down Expand Up @@ -102,3 +102,6 @@ ALTER TABLE branch_versions ADD CONSTRAINT FK_branch_versions_2 FOREIGN KEY (gro
CREATE INDEX IDX_branch_versions_1 ON branch_versions(groupId, artifactId, branchId, branchOrder);
CREATE INDEX IDX_branch_versions_2 ON branch_versions(branchId);
CREATE INDEX IDX_branch_versions_3 ON branch_versions(branchOrder);

CREATE TABLE outbox (id VARCHAR(128) NOT NULL, aggregatetype VARCHAR(255) NOT NULL, aggregateid VARCHAR(255) NOT NULL, type VARCHAR(255) NOT NULL, payload JSONB NOT NULL);
ALTER TABLE outbox ADD PRIMARY KEY (id);
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

CREATE TABLE apicurio (propName NVARCHAR(255) NOT NULL, propValue NVARCHAR(255));
ALTER TABLE apicurio ADD PRIMARY KEY (propName);
INSERT INTO apicurio (propName, propValue) VALUES ('db_version', 100);
INSERT INTO apicurio (propName, propValue) VALUES ('db_version', 101);

CREATE TABLE sequences (seqName NVARCHAR(32) NOT NULL, seqValue BIGINT NOT NULL);
ALTER TABLE sequences ADD PRIMARY KEY (seqName);
Expand Down Expand Up @@ -102,3 +102,6 @@ ALTER TABLE branch_versions ADD CONSTRAINT FK_branch_versions_2 FOREIGN KEY (gro
CREATE INDEX IDX_branch_versions_1 ON branch_versions(groupId, artifactId, branchId, branchOrder);
CREATE INDEX IDX_branch_versions_2 ON branch_versions(branchId);
CREATE INDEX IDX_branch_versions_3 ON branch_versions(branchOrder);

CREATE TABLE outbox (id VARCHAR(128) NOT NULL, aggregatetype VARCHAR(255) NOT NULL, aggregateid VARCHAR(255) NOT NULL, type VARCHAR(255) NOT NULL, payload JSONB NOT NULL);
ALTER TABLE outbox ADD PRIMARY KEY (id);
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

CREATE TABLE apicurio (propName VARCHAR(255) NOT NULL, propValue VARCHAR(255));
ALTER TABLE apicurio ADD PRIMARY KEY (propName);
INSERT INTO apicurio (propName, propValue) VALUES ('db_version', 100);
INSERT INTO apicurio (propName, propValue) VALUES ('db_version', 101);

CREATE TABLE sequences (seqName VARCHAR(32) NOT NULL, seqValue BIGINT NOT NULL);
ALTER TABLE sequences ADD PRIMARY KEY (seqName);
Expand Down Expand Up @@ -102,3 +102,6 @@ ALTER TABLE branch_versions ADD CONSTRAINT FK_branch_versions_2 FOREIGN KEY (gro
CREATE INDEX IDX_branch_versions_1 ON branch_versions(groupId, artifactId, branchId, branchOrder);
CREATE INDEX IDX_branch_versions_2 ON branch_versions(branchId);
CREATE INDEX IDX_branch_versions_3 ON branch_versions(branchOrder);

CREATE TABLE outbox (id VARCHAR(128) NOT NULL, aggregatetype VARCHAR(255) NOT NULL, aggregateid VARCHAR(255) NOT NULL, type VARCHAR(255) NOT NULL, payload JSONB NOT NULL);
ALTER TABLE outbox ADD PRIMARY KEY (id);
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@
import io.apicurio.registry.utils.tests.DebeziumContainerResource;
import io.quarkus.test.junit.QuarkusTestProfile;

import java.util.Collections;
import java.util.List;
import java.util.Map;

public class EventsTestProfile implements QuarkusTestProfile {

@Override
public Map<String, String> getConfigOverrides() {
return Collections.singletonMap("apicurio.storage.sql.kind", "postgresql");
return Map.of("apicurio.storage.sql.kind", "postgresql", "apicurio.rest.deletion.artifact.enabled",
"true", "apicurio.rest.deletion.artifact-version.enabled", "true");
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import io.apicurio.registry.AbstractResourceTestBase;
import io.apicurio.registry.rest.client.models.CreateArtifactResponse;
import io.apicurio.registry.rest.client.models.EditableArtifactMetaData;
import io.apicurio.registry.storage.StorageEventType;
import io.apicurio.registry.types.ArtifactType;
import io.apicurio.registry.types.ContentTypes;
import io.apicurio.registry.utils.tests.ApicurioTestTags;
Expand Down Expand Up @@ -44,7 +46,7 @@ public void init() {
}

@Test
void createArtifactEventTest() throws Exception {
void createArtifactEvent() throws Exception {
// Preparation
final String groupId = "testCreateArtifact";
final String artifactId = generateArtifactId();
Expand All @@ -53,6 +55,58 @@ void createArtifactEventTest() throws Exception {
final String name = "testCreateArtifactName";
final String description = "testCreateArtifactDescription";

ensureArtifactCreatedEvent(groupId, artifactId, version, name, description);
}

@Test
public void updateArtifactMetadataEvent() throws Exception {
// Preparation
final String groupId = "updateArtifactMetadataEvent";
final String artifactId = generateArtifactId();

final String version = "1";
final String name = "updateArtifactMetadataEventName";
final String description = "updateArtifactMetadataEventDescription";

CreateArtifactResponse createdArtifact = ensureArtifactCreatedEvent(groupId, artifactId, version,
name, description);

EditableArtifactMetaData emd = new EditableArtifactMetaData();
emd.setName("updateArtifactMetadataEventNameEdited");
clientV3.groups().byGroupId(groupId).artifacts().byArtifactId(artifactId).put(emd);

// Consume the update events from the broker
List<ConsumerRecord<String, String>> updateEvents = drain(consumer, 1);
Assertions.assertTrue(
updateEvents.get(0).value().contains(createdArtifact.getArtifact().getArtifactId()));
Assertions.assertTrue(
updateEvents.get(0).value().contains(StorageEventType.ARTIFACT_METADATA_UPDATED.name()));
}

@Test
public void deleteArtifactEvent() throws Exception {
// Preparation
final String groupId = "deleteArtifactEvent";
final String artifactId = generateArtifactId();

final String version = "1";
final String name = "deleteArtifactEventName";
final String description = "deleteArtifactEventDescription";

CreateArtifactResponse createdArtifact = ensureArtifactCreatedEvent(groupId, artifactId, version,
name, description);

clientV3.groups().byGroupId(groupId).artifacts().byArtifactId(artifactId).delete();

// Consume the delete event from the broker
List<ConsumerRecord<String, String>> deleteEvents = drain(consumer, 1);
Assertions.assertTrue(
deleteEvents.get(0).value().contains(createdArtifact.getArtifact().getArtifactId()));
Assertions.assertTrue(deleteEvents.get(0).value().contains(StorageEventType.ARTIFACT_DELETED.name()));
}

public CreateArtifactResponse ensureArtifactCreatedEvent(String groupId, String artifactId,
String version, String name, String description) throws Exception {
// Execution
CreateArtifactResponse created = createArtifact(groupId, artifactId, ArtifactType.JSON,
ARTIFACT_CONTENT, ContentTypes.APPLICATION_JSON, (createArtifact -> {
Expand All @@ -74,9 +128,12 @@ void createArtifactEventTest() throws Exception {
.byVersionExpression("branch=latest").content().get().readAllBytes(),
StandardCharsets.UTF_8));

// Consume the event from the broker
// Consume the create event from the broker
List<ConsumerRecord<String, String>> changeEvents = drain(consumer, 1);
Assertions.assertTrue(changeEvents.get(0).value().contains(created.getArtifact().getArtifactId()));
Assertions.assertTrue(changeEvents.get(0).value().contains(StorageEventType.ARTIFACT_CREATED.name()));

return created;
}

private KafkaConsumer<String, String> getConsumer(String bootstrapServers) {
Expand Down

0 comments on commit 5d4261b

Please sign in to comment.