Skip to content

Commit

Permalink
creating a baseEvent for custom events
Browse files Browse the repository at this point in the history
Signed-off-by: Jalander Ramagiri <jalander.ramagiri@est.tech>
  • Loading branch information
Jalander Ramagiri committed Jul 12, 2024
1 parent 65856c9 commit 220cb9f
Show file tree
Hide file tree
Showing 63 changed files with 534 additions and 768 deletions.
13 changes: 13 additions & 0 deletions generator/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,19 @@
</sourcePaths>
<targetPackage>dev.cdevents.models.links</targetPackage>
</configuration>
</execution>
<execution>
<id>generate-custom-event-from-schema</id>
<phase>generate-sources</phase>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<sourcePaths>
<sourcePath>${parent.project.dir}/spec/custom/schema.json</sourcePath>
</sourcePaths>
<targetPackage>dev.cdevents.models.custom</targetPackage>
</configuration>
</execution>
<execution>
<id>generate-artifact-deleted-from-schema</id>
Expand Down
68 changes: 61 additions & 7 deletions generator/src/main/resources/template/event-template.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -23,22 +23,40 @@ package dev.cdevents.events;

import dev.cdevents.constants.CDEventConstants;
import dev.cdevents.models.CDEvent;
{{^isCustomEvent}}
import dev.cdevents.models.{{subject}}.{{predicate}}.*;

{{/isCustomEvent}}
{{#isCustomEvent}}
import dev.cdevents.models.custom.*;
import java.util.Map;
{{/isCustomEvent}}
import java.net.URI;
import java.util.Date;
import java.util.UUID;
import java.util.List;


{{^isCustomEvent}}
public class {{capitalizedSubject}}{{capitalizedPredicate}}CDEvent extends {{capitalizedSubject}}{{predicate}} implements CDEvent {
{{/isCustomEvent}}
{{#isCustomEvent}}
public class CustomTypeEvent extends Schema implements CDEvent {
{{/isCustomEvent}}


{{^isCustomEvent}}
/**
* Constructor to init CDEvent and set the Subject for {@link {{capitalizedSubject}}{{capitalizedPredicate}}CDEvent}.
*/

public {{capitalizedSubject}}{{capitalizedPredicate}}CDEvent() {
{{/isCustomEvent}}
{{#isCustomEvent}}
/**
* Constructor to init CustomTypeEvent
*/

public CustomTypeEvent() {
{{/isCustomEvent}}
initCDEvent();
}

Expand All @@ -58,10 +76,12 @@ public class {{capitalizedSubject}}{{capitalizedPredicate}}CDEvent extends {{cap
context.setTimestamp(new Date());
context.setVersion(CDEventConstants.CDEVENTS_SPEC_VERSION);
getSubject().setContent(new Content());
{{#getContentObjects}}
{{^isCustomEvent}}
{{#getContentObjects}}
getSubject().getContent().set{{capitalizedObjectName}}(new {{capitalizedObjectName}}());
{{/getContentObjects}}
{{/getContentObjects}}
getSubject().setType(Subject.Type.{{upperCaseSubject}});
{{/isCustomEvent}}
}

/**
Expand All @@ -80,7 +100,12 @@ public class {{capitalizedSubject}}{{capitalizedPredicate}}CDEvent extends {{cap

@Override
public String currentCDEventType() {
{{^isCustomEvent}}
return getContext().getType().value();
{{/isCustomEvent}}
{{#isCustomEvent}}
return getContext().getType();
{{/isCustomEvent}}
}


Expand Down Expand Up @@ -114,10 +139,10 @@ public class {{capitalizedSubject}}{{capitalizedPredicate}}CDEvent extends {{cap

/**
*
* @return custom schema URI
* @return context schema URI
*/
@Override
public URI customSchemaUri() {
public URI contextSchemaUri() {
return getContext().getSchemaUri();
}

Expand Down Expand Up @@ -145,7 +170,7 @@ public class {{capitalizedSubject}}{{capitalizedPredicate}}CDEvent extends {{cap
* Sets the {@link Context} custom schemaUri value
*/

public void setCustomSchemaUri(URI schemaUri) {
public void setContextSchemaUri(URI schemaUri) {
getContext().setSchemaUri(schemaUri);
}

Expand All @@ -168,6 +193,34 @@ public class {{capitalizedSubject}}{{capitalizedPredicate}}CDEvent extends {{cap
getSubject().setSource(subjectSource.toString());
}

{{#isCustomEvent}}
/**
* @param type
* Sets the {@link Context} type value,
* must be in the format dev.cdeventsx.<tool-name>-<subject-name>.<predicate-name>.<major.minor.patch>
*/

public void setType(String type) {
getContext().setType(type);
}

/**
* @param subjectType
* sets the subject type, must be in the format <tool-name>-<subject-name>
*/
public void setSubjectType(String subjectType) {
getSubject().setType(subjectType);
}

/**
* @param contentProperty
* sets the subject content custom properties
*/
public void setSubjectContentProperty(Map<String, Object> contentProperty) {
contentProperty.forEach((key, value) -> getSubject().getContent().setAdditionalProperty(key, value));
}
{{/isCustomEvent}}
{{^isCustomEvent}}
//getContentFields starts

{{#getContentFields}}
Expand All @@ -190,5 +243,6 @@ public class {{capitalizedSubject}}{{capitalizedPredicate}}CDEvent extends {{cap
getSubject().getContent().get{{capitalizedObjectName}}().set{{capitalizedFieldName}}({{fieldName}});
}
{{/getContentObjectFields}}
{{/isCustomEvent}}

}
44 changes: 43 additions & 1 deletion preprocessor/src/main/java/dev/cdevents/PreprocessSchemas.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,21 @@

import dev.cdevents.process.ProcessSchemas;
import dev.cdevents.process.ProcessSchemasImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.nio.file.FileAlreadyExistsException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;

/**
* Adapts incoming schemas to a format that jsonschema2pojo.
*/
public final class PreprocessSchemas {

private static Logger log = LoggerFactory.getLogger(PreprocessSchemas.class);
private PreprocessSchemas() {
}
/**
Expand All @@ -16,11 +25,44 @@ private PreprocessSchemas() {
*/
public static void main(String[] args) {
if (args == null || args.length != 1) {
System.err.println("Usage: PreprocessSchemas <spec_schemas_directory_path>");
log.error("Usage: PreprocessSchemas <spec_schemas_directory_path>");
throw new IllegalArgumentException("spec schemas directory path argument not passed to PreprocessSchemas");
}
String specSchemasDir = args[0];
ProcessSchemas processSchemas = new ProcessSchemasImpl();
processSchemas.updateSchemas(specSchemasDir);
processSchemas.updateSchemas(specSchemasDir + "/../custom/schema.json");

// copy links to the spec/custom folder for jsonschema2pojo to generate classes
String targetDir = specSchemasDir + "/../custom/links/";
createTargetDir(targetDir);
try {
Files.walk(Paths.get(specSchemasDir + "/links/"))
.filter(Files::isRegularFile)
.filter(path -> path.toString().endsWith(".json"))
.forEach(path -> {
try {
log.info("copying {} to targetDir {} ", path, targetDir);
Files.copy(path, Paths.get(targetDir + path.getFileName()), StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
log.error("Exception occurred while copying links to custom directory {}", e.getMessage());
throw new IllegalStateException("Exception occurred while copying links to custom directory", e);
}
});
} catch (IOException e) {
log.error("Exception occurred while processing links directory {}", e.getMessage());
throw new IllegalStateException("Exception occurred while processing links directory", e);
}
}

private static void createTargetDir(String targetDir) {
try {
Files.createDirectory(Paths.get(targetDir));
} catch (FileAlreadyExistsException e) {
log.info("Ignore if the targetDir {} is already created ", targetDir);
} catch (IOException e) {
log.error("Exception occurred while creating {} directory", targetDir);
throw new IllegalStateException("Exception occurred while processing links directory", e);
}
}
}
120 changes: 43 additions & 77 deletions sdk/src/main/java/dev/cdevents/CDEvents.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@
import com.networknt.schema.ValidationMessage;
import dev.cdevents.config.CustomObjectMapper;
import dev.cdevents.constants.CDEventConstants;
import static dev.cdevents.constants.CDEventConstants.CUSTOM_EVENT_PREFIX;
import static dev.cdevents.constants.CDEventConstants.CUSTOM_SCHEMA_CLASSPATH;
import static dev.cdevents.constants.CDEventConstants.EVENT_PREFIX;
import dev.cdevents.events.CustomTypeEvent;
import dev.cdevents.exception.CDEventsException;
import dev.cdevents.models.CDEvent;
import io.cloudevents.CloudEvent;
Expand Down Expand Up @@ -77,15 +80,11 @@ public static CloudEvent cdEventAsCloudEvent(CDEvent cdEvent) {
* @return valid cdEvent
*/
public static boolean validateCDEvent(CDEvent cdEvent) {
Map<String, String> schemaMap = new HashMap<>();
schemaMap.put(cdEvent.schemaURL(), SCHEMA_CLASSPATH + cdEvent.schemaFileName());
schemaMap.put(cdEvent.baseURI() + "links/embeddedlinksarray", SCHEMA_CLASSPATH + "links/embeddedlinksarray.json");
Set<ValidationMessage> errors = getJsonSchemaValidationMessages(cdEvent, schemaMap);
if (!errors.isEmpty()) {
log.error("CDEvent validation failed with errors {}", errors);
return false;
if (cdEvent.currentCDEventType().startsWith(EVENT_PREFIX)) {
return validateWithOfficialSchema(cdEvent);
} else {
return validateWithOfficialCustomSchema(cdEvent);
}
return true;
}

/**
Expand All @@ -109,74 +108,17 @@ public static CDEvent cdEventFromJson(String cdEventJson) {
}

/**
* Creates a CloudEvent from the custom cdEvent.
* @param <T> customCDEvent class
* @param customCDEvent custom CDEvent class object of type <T>
* @param validateContextSchema true If validation needed against context.schemaUri
* @return CloudEvent
*/
public static <T extends CDEvent> CloudEvent customCDEventAsCloudEvent(T customCDEvent, boolean validateContextSchema) {
if (!validateCustomCDEvent(customCDEvent, validateContextSchema)) {
throw new CDEventsException("Custom CDEvent validation failed.");
}
try {
return buildCloudEvent(customCDEvent);
} catch (URISyntaxException e) {
throw new CDEventsException("Exception occurred while building CloudEvent from custom CDEvent ", e);
}
}

/**
* Creates customCDEvent from Json string and validates against context and official schemas.
* @param customCDEventJson Json string of customCDEvent class type <T>
* @param <T> customCDEvent class
* @param eventClass custom CDEvent class of type <T>
* @param validateContextSchema true If validation needed against context.schemaUri
* @return CDEvent
*/
public static <T extends CDEvent> T customCDEventFromJson(String customCDEventJson, Class<T> eventClass, boolean validateContextSchema) {
try {
T cdEvent = new ObjectMapper().readValue(customCDEventJson, eventClass);
if (!validateCustomCDEvent(cdEvent, validateContextSchema)) {
throw new CDEventsException("Custom CDEvent validation failed.");
}
return cdEvent;
} catch (JsonProcessingException e) {
throw new CDEventsException("Exception occurred while processing cdEventJson with the event class " + eventClass.getName(), e);
}
}

/**
* Validates the custom CDEvent against the official and context schemas.
* @param customCDEvent custom CDEvent to validate
* @param validateContextSchema true to validate custom CDEvent against context schema
* @return valid cdEvent
*/
public static boolean validateCustomCDEvent(CDEvent customCDEvent, boolean validateContextSchema) {
if (validateContextSchema) {
return validateWithContextSchemaUri(customCDEvent) && validateWithOfficialCustomSchema(customCDEvent);
} else {
return validateWithOfficialCustomSchema(customCDEvent);
}
}

/**
* Validates the custom CDEvent against the provided context Schema URI.
* @param customCDEvent custom CDEvent to validate
* @return valid cdEvent
* Validates the CDEvent against the official spec/schemas/.
* @param cdEvent
* @return true if valid cdEvent
*/
public static boolean validateWithContextSchemaUri(CDEvent customCDEvent) {
if (customCDEvent.customSchemaUri() == null) {
log.error("Context schemaUri does not exist, required for custom schema validation.");
throw new CDEventsException("Context schemaUri does not exist.");
}
log.info("Validate custom CDEvent against context.schemaUri - {}", customCDEvent.customSchemaUri());
JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V202012);
JsonSchema jsonSchema = factory.getSchema(customCDEvent.customSchemaUri());
JsonNode jsonNode = objectMapper.convertValue(customCDEvent, ObjectNode.class);
Set<ValidationMessage> errors = jsonSchema.validate(jsonNode);
private static boolean validateWithOfficialSchema(CDEvent cdEvent) {
Map<String, String> schemaMap = new HashMap<>();
schemaMap.put(cdEvent.schemaURL(), SCHEMA_CLASSPATH + cdEvent.schemaFileName());
schemaMap.put(cdEvent.baseURI() + "links/embeddedlinksarray", SCHEMA_CLASSPATH + "links/embeddedlinksarray.json");
Set<ValidationMessage> errors = getJsonSchemaValidationMessages(cdEvent, schemaMap);
if (!errors.isEmpty()) {
log.error("Custom CDEvent validation failed against context.schemaUri - {}, with errors {}", customCDEvent.customSchemaUri(), errors);
log.error("CDEvent validation failed with errors {}", errors);
return false;
}
return true;
Expand All @@ -185,9 +127,9 @@ public static boolean validateWithContextSchemaUri(CDEvent customCDEvent) {
/**
* Validates the custom CDEvent against the official spec/custom/schema.json.
* @param customCDEvent
* @return valid cdEvent
* @return true if valid cdEvent
*/
public static boolean validateWithOfficialCustomSchema(CDEvent customCDEvent) {
private static boolean validateWithOfficialCustomSchema(CDEvent customCDEvent) {
Map<String, String> schemaMap = new HashMap<>();
schemaMap.put(customCDEvent.schemaURL(), CUSTOM_SCHEMA_CLASSPATH + "schema.json");
schemaMap.put(customCDEvent.baseURI() + "links/embeddedlinksarray", SCHEMA_CLASSPATH + "links/embeddedlinksarray.json");
Expand All @@ -200,9 +142,31 @@ public static boolean validateWithOfficialCustomSchema(CDEvent customCDEvent) {
return true;
}

/**
* Validates the CDEvent against the provided context Schema URI.
* @param cdEvent
* @return true if valid cdEvent
*/
private static boolean validateWithContextSchemaUri(CDEvent cdEvent) {
if (cdEvent.contextSchemaUri() == null) {
log.error("Context schemaUri does not exist, required for custom schema validation.");
throw new CDEventsException("Context schemaUri does not exist.");
}
log.info("Validate custom CDEvent against context.schemaUri - {}", cdEvent.contextSchemaUri());
JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V202012);
JsonSchema jsonSchema = factory.getSchema(cdEvent.contextSchemaUri());
JsonNode jsonNode = objectMapper.convertValue(cdEvent, ObjectNode.class);
Set<ValidationMessage> errors = jsonSchema.validate(jsonNode);
if (!errors.isEmpty()) {
log.error("Custom CDEvent validation failed against context.schemaUri - {}, with errors {}", cdEvent.contextSchemaUri(), errors);
return false;
}
return true;
}

private static CloudEvent buildCloudEvent(CDEvent cdEvent) throws URISyntaxException {
String cdEventJson = cdEventAsJson(cdEvent);
log.info("CDEvent with type {} as json - {}", cdEvent.currentCDEventType(), cdEventJson);
log.debug("CDEvent with type {} as json - {}", cdEvent.currentCDEventType(), cdEventJson);
return new CloudEventBuilder()
.withId(UUID.randomUUID().toString())
.withSource(new URI(cdEvent.eventSource()))
Expand Down Expand Up @@ -248,6 +212,8 @@ private static String getUnVersionedEventTypeFromJson(String cdEventJson) {
String subject = type[CDEventConstants.EVENT_SUBJECT_INDEX];
String predicate = type[CDEventConstants.EVENT_PREDICATE_INDEX];
return CDEventConstants.EVENT_PREFIX + subject + "." + predicate + ".";
} else if (versionedEventType.startsWith(CUSTOM_EVENT_PREFIX)) {
return CUSTOM_EVENT_PREFIX;
} else {
throw new CDEventsException("Invalid CDEvent type found in CDEvent Json " + versionedEventType);
}
Expand Down
Loading

0 comments on commit 220cb9f

Please sign in to comment.