Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 11 additions & 11 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
<!-- Properties -->
<properties>
<!-- Version -->
<revision>5.0.0</revision>
<revision>5.1.0</revision>

<!-- basic project properties -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
Expand All @@ -60,18 +60,18 @@

<!-- plugin versions -->
<flatten-maven-plugin.version>1.6.0</flatten-maven-plugin.version>
<maven-surefire-plugin.version>3.4.0</maven-surefire-plugin.version>
<maven-surefire-plugin.version>3.5.2</maven-surefire-plugin.version>
<maven-source-plugin.version>3.3.1</maven-source-plugin.version>
<maven-install-plugin.version>3.1.2</maven-install-plugin.version>
<maven-deploy-plugin.version>3.1.2</maven-deploy-plugin.version>
<maven-javadoc-plugin.version>3.8.0</maven-javadoc-plugin.version>
<maven-gpg-plugin.version>3.2.5</maven-gpg-plugin.version>
<central-publishing-maven-plugin.version>0.5.0</central-publishing-maven-plugin.version>
<maven-install-plugin.version>3.1.3</maven-install-plugin.version>
<maven-deploy-plugin.version>3.1.3</maven-deploy-plugin.version>
<maven-javadoc-plugin.version>3.11.2</maven-javadoc-plugin.version>
<maven-gpg-plugin.version>3.2.7</maven-gpg-plugin.version>
<central-publishing-maven-plugin.version>0.7.0</central-publishing-maven-plugin.version>

<!-- dependency versions -->
<gson.version>2.11.0</gson.version>
<util.version>4.3.0</util.version>
<junit-jupiter-engine.version>5.11.0</junit-jupiter-engine.version>
<gson.version>2.12.1</gson.version>
<util.version>4.4.0</util.version>
<junit-jupiter-engine.version>5.11.4</junit-jupiter-engine.version>
<jacoco-maven-plugin.version>0.8.12</jacoco-maven-plugin.version>
</properties>

Expand Down Expand Up @@ -418,4 +418,4 @@
</profile>
</profiles>

</project>
</project>
4 changes: 2 additions & 2 deletions protobuf/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@
<maven-replacer-plugin.version>1.4.1</maven-replacer-plugin.version>

<!-- dependency versions -->
<protobuf.version>3.25.4</protobuf.version>
<protoc.version>3.25.4</protoc.version>
<protobuf.version>3.25.6</protobuf.version>
<protoc.version>3.25.6</protoc.version>
</properties>

<!-- Dependencies -->
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
package gov.hhs.aspr.ms.taskit.protobuf.engine;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;

import com.google.protobuf.Descriptors.Descriptor;
import com.google.protobuf.Message;
import com.google.protobuf.ProtocolMessageEnum;

import gov.hhs.aspr.ms.taskit.core.engine.TaskitEngineData;
import gov.hhs.aspr.ms.taskit.core.engine.TaskitError;
import gov.hhs.aspr.ms.taskit.core.translation.ITranslationSpec;
import gov.hhs.aspr.ms.taskit.core.translation.Translator;
import gov.hhs.aspr.ms.taskit.core.translation.TranslatorContext;
import gov.hhs.aspr.ms.taskit.protobuf.translation.ProtobufTranslationSpec;
import gov.hhs.aspr.ms.taskit.protobuf.translation.ProtobufTranslator;
import gov.hhs.aspr.ms.util.errors.ContractException;

public class ProtobufBinaryTaskitEngine extends ProtobufTaskitEngine {

protected ProtobufBinaryTaskitEngine(Map<String, Class<?>> typeUrlToClassMap, TaskitEngineData taskitEngineData) {
super(typeUrlToClassMap, taskitEngineData, ProtobufTaskitEngineId.BINARY_ENGINE_ID);
}

/**
* Builder for the ProtobufJsonTaskitEngine.
*/
public final static class Builder implements IProtobufTaskitEngineBuilder {
private Set<Descriptor> descriptorSet = new LinkedHashSet<>();

// this is used specifically for Any message types to pack and unpack them
private final Map<String, Class<?>> typeUrlToClassMap = new LinkedHashMap<>();

private TaskitEngineData.Builder taskitEngineDataBuilder = TaskitEngineData.builder();

private Builder() {
}

/**
* Returns a new instance of a ProtobufTaskitEngine that has a jsonParser and
* jsonWriter that include all the typeUrls for all added TranslationSpecs and
* their respective Protobuf Message types.
*
* @throws ContractException
* <ul>
* <li>{@link TaskitError#UNINITIALIZED_TRANSLATORS}
* if translators were added to the engine but their
* initialized flag was still set to false</li>
* <li>{@link TaskitError#DUPLICATE_TRANSLATOR} if a
* duplicate translator is found</li>
* <li>{@link TaskitError#MISSING_TRANSLATOR} if an
* added translator has a unmet dependency</li>
* <li>{@link TaskitError#CIRCULAR_TRANSLATOR_DEPENDENCIES}
* if the added translators have a circular dependency
* graph</li>
* <li>{@link TaskitError#NO_TRANSLATION_SPECS} if no
* translation specs were added to the engine</li>
* </ul>
*/
public ProtobufBinaryTaskitEngine build() {
this.addTranslator(ProtobufTranslator.getTranslator());

ProtobufBinaryTaskitEngine protoBinaryTaskitEngine = new ProtobufBinaryTaskitEngine(this.typeUrlToClassMap,
this.taskitEngineDataBuilder.build());

protoBinaryTaskitEngine.init();

return protoBinaryTaskitEngine;
}

/**
* Adds the given {@link ITranslationSpec} to the TaskitEngine.
* <p>
* Additionally will populate typeUrls and field descriptors associated with the
* Protobuf types on the given TranslationSpec.
* </p>
*
* @throws ContractException
* <ul>
* <li>{@linkplain TaskitError#NULL_TRANSLATION_SPEC}
* if the given translationSpec is null</li>
* <li>{@linkplain TaskitError#NULL_TRANSLATION_SPEC_CLASS_MAP}
* if the given translationSpec's class map is
* null</li>
* <li>{@linkplain TaskitError#EMPTY_TRANSLATION_SPEC_CLASS_MAP}
* if the given translationSpec's class map is
* empty</li>
* <li>{@linkplain TaskitError#DUPLICATE_TRANSLATION_SPEC}
* if the given translationSpec is already known</li>
* <li>{@link ProtobufTaskitError#INVALID_TRANSLATION_SPEC}
* if the given translation spec is not assignable
* from {@linkplain ProtobufTranslationSpec}</li>
* <li>{@link ProtobufTaskitError#INVALID_TRANSLATION_SPEC_INPUT_CLASS}
* if the given inputClassRef is not assignable from
* {@linkplain Message} nor
* {@linkplain ProtocolMessageEnum}</li>
* </ul>
*/
@Override
public Builder addTranslationSpec(ITranslationSpec translationSpec) {
this.taskitEngineDataBuilder.addTranslationSpec(translationSpec);

if (!ProtobufTranslationSpec.class.isAssignableFrom(translationSpec.getClass())) {
throw new ContractException(ProtobufTaskitError.INVALID_TRANSLATION_SPEC);
}

ProtobufTranslationSpec<?, ?> protobufTranslationSpec = ProtobufTranslationSpec.class.cast(translationSpec);

populate(protobufTranslationSpec.getInputObjectClass());
return this;
}

/**
* Adds a {@link Translator}.
*
* @throws ContractException {@linkplain TaskitError#NULL_TRANSLATOR} if
* translator is null
*/
@Override
public Builder addTranslator(Translator translator) {
this.taskitEngineDataBuilder.addTranslator(translator);

translator.initialize(new TranslatorContext(this));

return this;
}

/**
* Checks the class to determine if it is a ProtocolMessageEnum or a Message.
* <p>
* If it is a Message, gets the Descriptor (which is akin to a class but for a
* Protobuf
* Message) for it to get the full name and add the typeUrl to the internal
* descriptorMap and typeUrlToClassMap.
* </p>
* <p>
* Package access for testing.
* </p>
*
* @param <U> the type of the classRef
* @param classRef the classRef to use
*
* @throws ContractException {@link ProtobufTaskitError#INVALID_TRANSLATION_SPEC_INPUT_CLASS}
* if the given inputClassRef is not assignable from
* {@linkplain Message} nor
* {@linkplain ProtocolMessageEnum}
*
* @throws RuntimeException if there is any issue using reflection to invoke
* either the 'getDefaultInstance' method on a
* {@link Message} type or invoking the 'forNumber(0)'
* method on the {@link ProtocolMessageEnum} type
*/
<U> void populate(Class<U> classRef) {
String typeUrl;
if (ProtocolMessageEnum.class.isAssignableFrom(classRef) && ProtocolMessageEnum.class != classRef) {
typeUrl = ProtobufTaskitEngineHelper.getDefaultEnum(classRef.asSubclass(ProtocolMessageEnum.class))
.getDescriptorForType().getFullName();
this.typeUrlToClassMap.putIfAbsent(typeUrl, classRef);
return;
}

if (Message.class.isAssignableFrom(classRef) && Message.class != classRef) {
Message message = ProtobufTaskitEngineHelper.getDefaultMessage(classRef.asSubclass(Message.class));
typeUrl = message.getDescriptorForType().getFullName();

this.typeUrlToClassMap.putIfAbsent(typeUrl, classRef);
this.descriptorSet.add(message.getDescriptorForType());
return;
}

throw new ContractException(ProtobufTaskitError.INVALID_TRANSLATION_SPEC_INPUT_CLASS);
}

}

/**
* Returns a new builder for the Protobuf Json Taskit engine.
*/
public static Builder builder() {
return new Builder();
}

@Override
protected void writeToFile(File file, Message message) throws IOException {
BufferedOutputStream bOutputStream = new BufferedOutputStream(new FileOutputStream(file));

message.writeTo(bOutputStream);

bOutputStream.flush();
}

@Override
protected Message readFile(File file, Message.Builder builder) throws IOException {
BufferedInputStream bInputStream = new BufferedInputStream(new FileInputStream(file));

builder.mergeFrom(bInputStream);

return builder.build();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ public enum ProtobufTaskitError implements ContractError {
INVALID_TRANSLATION_SPEC("Added Translation Specs need to be of parent type Protobuf TranslationSpecs"),
NULL_FIELD_DESCRIPTOR("The provided field descriptor is null"),
UNKNOWN_TYPE_URL(
"The given type url does not have a corresponding classRef. Either the typeUrl was never provided, or the typeUrl is malformed.");
"The given type url does not have a corresponding classRef. Either the typeUrl was never provided, or the typeUrl is malformed."),
MALFORMED_TASKIT_OBJECT("The given taskit object does not have any fields set on it"),
INVALID_RETRIEVAL("Tried to get value on Taskit Object which was not set"),
;

private final String description;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package gov.hhs.aspr.ms.taskit.protobuf.engine;

import com.google.protobuf.Any;
import com.google.type.Date;

import gov.hhs.aspr.ms.taskit.protobuf.objects.TaskitObjectInput;
import gov.hhs.aspr.ms.taskit.protobuf.objects.WrapperEnumValue;
import gov.hhs.aspr.ms.util.errors.ContractException;

public final class TaskitObjectHelper {

private TaskitObjectHelper() {
}

public static Object getValue(TaskitObjectInput taskitObjectInput) {
TaskitObjectInput.ValueCase valueCase = taskitObjectInput.getValueCase();

switch (valueCase) {
case BVAL:
return taskitObjectInput.getBVal();
case DATEVAL:
return taskitObjectInput.getDateVal();
case DVAL:
return taskitObjectInput.getDVal();
case ENUMVAL:
return taskitObjectInput.getEnumVal();
case FVAL:
return taskitObjectInput.getFVal();
case I32VAL:
return taskitObjectInput.getI32Val();
case I64VAL:
return taskitObjectInput.getI64Val();
case MVAL:
return taskitObjectInput.getMVal();
case SVAL:
return taskitObjectInput.getSVal();
case VALUE_NOT_SET:
default:
throw new ContractException(ProtobufTaskitError.INVALID_RETRIEVAL);
}
}

public static TaskitObjectInput getTaskitObjectInput(Object value, ProtobufTaskitEngine taskitEngine) {
String valClass = value.getClass().getSimpleName();

if (value instanceof Enum) {
valClass = "Enum";
}

switch (valClass) {
case "int":
case "Integer":
return getIntegerTaskitInput((Integer) value);
case "long":
case "Long":
return getLongTaskitInput((Long) value);
case "double":
case "Double":
return getDoubleTaskitInput((Double) value);
case "float":
case "Float":
return getFloatTaskitInput((Float) value);
case "boolean":
case "Boolean":
return getBooleanTaskitInput((Boolean) value);
case "String":
return getStringTaskitInput((String) value);
case "LocalDate":
return getDateTaskitInput((Date) taskitEngine.translateObject(value));
case "Enum":
return getEnumTaskitInput(taskitEngine.translateObjectAsClassSafe(Enum.class.cast(value), Enum.class));
default:
return getAnyTaskitInput(taskitEngine.getAnyFromObject(value));
}
}

static TaskitObjectInput getIntegerTaskitInput(Integer value) {
return TaskitObjectInput.newBuilder().setI32Val(value).build();
}

static TaskitObjectInput getAnyTaskitInput(Any value) {
return TaskitObjectInput.newBuilder().setMVal(value).build();
}

static TaskitObjectInput getLongTaskitInput(Long value) {
return TaskitObjectInput.newBuilder().setI64Val(value).build();
}

static TaskitObjectInput getFloatTaskitInput(Float value) {
return TaskitObjectInput.newBuilder().setFVal(value).build();
}

static TaskitObjectInput getDoubleTaskitInput(Double value) {
return TaskitObjectInput.newBuilder().setDVal(value).build();
}

static TaskitObjectInput getDateTaskitInput(Date value) {
return TaskitObjectInput.newBuilder().setDateVal(value).build();
}

static TaskitObjectInput getStringTaskitInput(String value) {
return TaskitObjectInput.newBuilder().setSVal(value).build();
}

static TaskitObjectInput getEnumTaskitInput(WrapperEnumValue value) {
return TaskitObjectInput.newBuilder().setEnumVal(value).build();
}

static TaskitObjectInput getBooleanTaskitInput(Boolean value) {
return TaskitObjectInput.newBuilder().setBVal(value).build();
}
}
Loading