diff --git a/README.md b/README.md
index a5bce548..b50ef808 100644
--- a/README.md
+++ b/README.md
@@ -30,6 +30,7 @@ The root `pom.xml` (`packaging=pom`) aggregates this Maven reactor:
## Documentation
- [skyvault API Reference](docs/api_reference.md) — full list of request builder methods, response getters, enums, and service-account utilities
+- [Detect API Reference](docs/api_reference.md#detect-api) — request, response, configuration and enum classes for Detect, shared by both SDKs
- [Migrate from v1 to v2](docs/migrate_to_v2.md)
## Reporting a Vulnerability
diff --git a/common/pom.xml b/common/pom.xml
index 72fff275..99f43063 100644
--- a/common/pom.xml
+++ b/common/pom.xml
@@ -21,4 +21,13 @@
8UTF-8
+
+
+
+ com.squareup.okhttp3
+ mockwebserver
+ ${okhttp-version}
+ test
+
+
\ No newline at end of file
diff --git a/common/src/main/java/com/skyflow/BaseSkyflow.java b/common/src/main/java/com/skyflow/BaseSkyflow.java
index d02dc45a..fdca3f26 100644
--- a/common/src/main/java/com/skyflow/BaseSkyflow.java
+++ b/common/src/main/java/com/skyflow/BaseSkyflow.java
@@ -4,7 +4,7 @@
import com.skyflow.config.Credentials;
import com.skyflow.enums.LogLevel;
import com.skyflow.errors.ErrorCode;
-import com.skyflow.errors.ErrorMessage;
+import com.skyflow.errors.BaseErrorMessage;
import com.skyflow.errors.SkyflowException;
import com.skyflow.logs.ErrorLogs;
import com.skyflow.logs.InfoLogs;
@@ -66,7 +66,7 @@ public LogLevel getLogLevel() {
}
protected static T resolveOrThrow(Map map, String key,
- ErrorLogs errorLog, ErrorMessage errorMessage) throws SkyflowException {
+ ErrorLogs errorLog, BaseErrorMessage errorMessage) throws SkyflowException {
T value = key != null ? map.get(key) : map.values().stream().findFirst().orElse(null);
if (value == null) {
// The log line carries a %s1 placeholder for the id. Callers that resolve the single
@@ -125,7 +125,7 @@ protected final void addVaultConfigTemplate(V vaultConfig) throws SkyflowExcepti
ErrorLogs.VAULT_CONFIG_EXISTS.getLog(), vaultId
));
throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(),
- ErrorMessage.VaultIdAlreadyInConfigList.getMessage());
+ BaseErrorMessage.VaultIdAlreadyInConfigList.getMessage());
}
onVaultConfigAdded(vaultConfigCopy);
this.vaultConfigMap.put(vaultId, vaultConfigCopy);
@@ -139,7 +139,7 @@ protected final void updateVaultConfigTemplate(V vaultConfig) throws SkyflowExce
LogUtil.printErrorLog(BaseUtils.parameterizedString(
ErrorLogs.VAULT_CONFIG_DOES_NOT_EXIST.getLog(), vaultId
));
- throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.VaultIdNotInConfigList.getMessage());
+ throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), BaseErrorMessage.VaultIdNotInConfigList.getMessage());
}
V previousConfig = this.vaultConfigMap.get(vaultId);
V merged = mergeVaultConfig(vaultConfig, cloneVaultConfig(previousConfig));
@@ -150,7 +150,7 @@ protected final void updateVaultConfigTemplate(V vaultConfig) throws SkyflowExce
protected final void removeVaultConfigTemplate(String vaultId) throws SkyflowException {
if (!hasVaultClient(vaultId)) {
LogUtil.printErrorLog(BaseUtils.parameterizedString(ErrorLogs.VAULT_CONFIG_DOES_NOT_EXIST.getLog(), vaultId));
- throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.VaultIdNotInConfigList.getMessage());
+ throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), BaseErrorMessage.VaultIdNotInConfigList.getMessage());
}
onVaultConfigRemoved(vaultId);
this.vaultConfigMap.remove(vaultId);
diff --git a/common/src/main/java/com/skyflow/BaseVaultClient.java b/common/src/main/java/com/skyflow/BaseVaultClient.java
index 82084c4a..e31687b6 100644
--- a/common/src/main/java/com/skyflow/BaseVaultClient.java
+++ b/common/src/main/java/com/skyflow/BaseVaultClient.java
@@ -1,12 +1,12 @@
package com.skyflow;
-import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.skyflow.config.BaseCredentials;
import com.skyflow.config.BaseVaultConfig;
import com.skyflow.errors.ErrorCode;
-import com.skyflow.errors.ErrorMessage;
+import com.skyflow.errors.BaseErrorMessage;
import com.skyflow.errors.SkyflowException;
+import com.skyflow.generated.common.rest.core.ObjectMappers;
import com.skyflow.logs.ErrorLogs;
import com.skyflow.logs.InfoLogs;
import com.skyflow.logs.WarningLogs;
@@ -29,7 +29,7 @@
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
-class BaseVaultClient {
+public class BaseVaultClient {
protected V vaultConfig;
protected OkHttpClient sharedHttpClient;
protected String currentVaultURL;
@@ -182,7 +182,7 @@ protected synchronized void prioritiseCredentials(BaseCredentials vaultSpecificC
sysCredentials = dotenv.get(BaseConstants.ENV_CREDENTIALS_KEY_NAME);
}
if (sysCredentials == null) {
- throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyCredentials.getMessage());
+ throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), BaseErrorMessage.EmptyCredentials.getMessage());
} else {
this.finalCredentials = new BaseCredentials();
this.finalCredentials.setCredentialsString(sysCredentials);
@@ -194,7 +194,7 @@ protected synchronized void prioritiseCredentials(BaseCredentials vaultSpecificC
refreshFailedFor = null;
}
} catch (DotenvException e) {
- throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyCredentials.getMessage());
+ throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), BaseErrorMessage.EmptyCredentials.getMessage());
} catch (SkyflowException e) {
throw e;
} catch (Exception e) {
@@ -222,7 +222,27 @@ protected static SkyflowException wrapApiException(int statusCode, Throwable cau
Map> headers,
Object responseBody, ErrorLogs errorLog) {
LogUtil.printErrorLog(errorLog.getLog());
- Gson gson = new GsonBuilder().serializeNulls().create();
- return new SkyflowException(statusCode, cause, headers, gson.toJson(responseBody));
+ return new SkyflowException(statusCode, cause, headers, errorBodyAsJson(responseBody));
+ }
+
+ /**
+ * Serializes an API error body back to the JSON the server sent. The generated clients hand us either a
+ * plain {@code Map} or a typed {@code ErrorResponse}; the typed form carries Jackson annotations for the wire
+ * names ({@code grpc_code}, {@code http_status}) and {@code Optional} fields, so Jackson must do the
+ * serialization. Gson would emit the Java field names, which {@link SkyflowException} cannot parse, and
+ * fails outright on {@code Optional} under JDK 17+.
+ */
+ static String errorBodyAsJson(Object responseBody) {
+ if (responseBody == null) {
+ return null;
+ }
+ if (responseBody instanceof String) {
+ return (String) responseBody;
+ }
+ try {
+ return ObjectMappers.JSON_MAPPER.writeValueAsString(responseBody);
+ } catch (Exception e) {
+ return new GsonBuilder().serializeNulls().create().toJson(responseBody);
+ }
}
}
diff --git a/common/src/main/java/com/skyflow/detect/Audio.java b/common/src/main/java/com/skyflow/detect/Audio.java
new file mode 100644
index 00000000..6d4e46f9
--- /dev/null
+++ b/common/src/main/java/com/skyflow/detect/Audio.java
@@ -0,0 +1,93 @@
+package com.skyflow.detect;
+
+/**
+ * Audio processing options.
+ */
+public final class Audio {
+ private final Boolean outputProcessedAudio;
+ private final OutputTranscriptionType outputTranscription;
+ private final Bleep bleep;
+
+ private Audio(AudioBuilder builder) {
+ this.outputProcessedAudio = builder.outputProcessedAudio;
+ this.outputTranscription = builder.outputTranscription;
+ this.bleep = builder.bleep;
+ }
+
+ /**
+ * @return a new builder
+ */
+ public static AudioBuilder builder() {
+ return new AudioBuilder();
+ }
+
+ /**
+ * @return Whether to return the processed audio file.
+ */
+ public Boolean getOutputProcessedAudio() {
+ return outputProcessedAudio;
+ }
+
+ /**
+ * @return Transcription output to produce.
+ */
+ public OutputTranscriptionType getOutputTranscription() {
+ return outputTranscription;
+ }
+
+ /**
+ * @return Bleep configuration.
+ */
+ public Bleep getBleep() {
+ return bleep;
+ }
+
+ @Override
+ public String toString() {
+ return "Audio{" +
+ "outputProcessedAudio=" + outputProcessedAudio +
+ ", outputTranscription=" + outputTranscription +
+ ", bleep=" + bleep +
+ '}';
+ }
+
+ public static final class AudioBuilder {
+ private Boolean outputProcessedAudio;
+ private OutputTranscriptionType outputTranscription;
+ private Bleep bleep;
+
+ private AudioBuilder() {
+ }
+
+ /**
+ * @param outputProcessedAudio Whether to return the processed audio file.
+ * @return this builder
+ */
+ public AudioBuilder outputProcessedAudio(Boolean outputProcessedAudio) {
+ this.outputProcessedAudio = outputProcessedAudio;
+ return this;
+ }
+
+ /**
+ * @param outputTranscription Transcription output to produce.
+ * @return this builder
+ */
+ public AudioBuilder outputTranscription(OutputTranscriptionType outputTranscription) {
+ this.outputTranscription = outputTranscription;
+ return this;
+ }
+
+ /**
+ * @param bleep Bleep configuration.
+ * @return this builder
+ */
+ public AudioBuilder bleep(Bleep bleep) {
+ this.bleep = bleep;
+ return this;
+ }
+
+ public Audio build() {
+ return new Audio(this);
+ }
+ }
+}
diff --git a/common/src/main/java/com/skyflow/detect/Bleep.java b/common/src/main/java/com/skyflow/detect/Bleep.java
new file mode 100644
index 00000000..63346aeb
--- /dev/null
+++ b/common/src/main/java/com/skyflow/detect/Bleep.java
@@ -0,0 +1,113 @@
+package com.skyflow.detect;
+
+/**
+ * Bleep tone applied over detected speech in audio.
+ */
+public final class Bleep {
+ private final Float startPadding;
+ private final Float stopPadding;
+ private final Integer frequency;
+ private final Integer gain;
+
+ private Bleep(BleepBuilder builder) {
+ this.startPadding = builder.startPadding;
+ this.stopPadding = builder.stopPadding;
+ this.frequency = builder.frequency;
+ this.gain = builder.gain;
+ }
+
+ /**
+ * @return a new builder
+ */
+ public static BleepBuilder builder() {
+ return new BleepBuilder();
+ }
+
+ /**
+ * @return Seconds of bleep added before the detected span.
+ */
+ public Float getStartPadding() {
+ return startPadding;
+ }
+
+ /**
+ * @return Seconds of bleep added after the detected span.
+ */
+ public Float getStopPadding() {
+ return stopPadding;
+ }
+
+ /**
+ * @return Bleep frequency in Hz.
+ */
+ public Integer getFrequency() {
+ return frequency;
+ }
+
+ /**
+ * @return Bleep gain.
+ */
+ public Integer getGain() {
+ return gain;
+ }
+
+ @Override
+ public String toString() {
+ return "Bleep{" +
+ "startPadding=" + startPadding +
+ ", stopPadding=" + stopPadding +
+ ", frequency=" + frequency +
+ ", gain=" + gain +
+ '}';
+ }
+
+ public static final class BleepBuilder {
+ private Float startPadding;
+ private Float stopPadding;
+ private Integer frequency;
+ private Integer gain;
+
+ private BleepBuilder() {
+ }
+
+ /**
+ * @param startPadding Seconds of bleep added before the detected span.
+ * @return this builder
+ */
+ public BleepBuilder startPadding(Float startPadding) {
+ this.startPadding = startPadding;
+ return this;
+ }
+
+ /**
+ * @param stopPadding Seconds of bleep added after the detected span.
+ * @return this builder
+ */
+ public BleepBuilder stopPadding(Float stopPadding) {
+ this.stopPadding = stopPadding;
+ return this;
+ }
+
+ /**
+ * @param frequency Bleep frequency in Hz.
+ * @return this builder
+ */
+ public BleepBuilder frequency(Integer frequency) {
+ this.frequency = frequency;
+ return this;
+ }
+
+ /**
+ * @param gain Bleep gain.
+ * @return this builder
+ */
+ public BleepBuilder gain(Integer gain) {
+ this.gain = gain;
+ return this;
+ }
+
+ public Bleep build() {
+ return new Bleep(this);
+ }
+ }
+}
diff --git a/common/src/main/java/com/skyflow/detect/CheckGuardrailsRequest.java b/common/src/main/java/com/skyflow/detect/CheckGuardrailsRequest.java
new file mode 100644
index 00000000..526ddd9c
--- /dev/null
+++ b/common/src/main/java/com/skyflow/detect/CheckGuardrailsRequest.java
@@ -0,0 +1,95 @@
+package com.skyflow.detect;
+
+import java.util.List;
+
+/**
+ * Request for {@code checkGuardrails}: screens text for toxicity and denied topics.
+ */
+public final class CheckGuardrailsRequest {
+ private final String text;
+ private final Boolean checkToxicity;
+ private final List denyTopics;
+
+ private CheckGuardrailsRequest(CheckGuardrailsRequestBuilder builder) {
+ this.text = builder.text;
+ this.checkToxicity = builder.checkToxicity;
+ this.denyTopics = builder.denyTopics;
+ }
+
+ /**
+ * @return a new builder
+ */
+ public static CheckGuardrailsRequestBuilder builder() {
+ return new CheckGuardrailsRequestBuilder();
+ }
+
+ /**
+ * @return Text to screen. Required.
+ */
+ public String getText() {
+ return text;
+ }
+
+ /**
+ * @return Whether to check the text for toxicity.
+ */
+ public Boolean getCheckToxicity() {
+ return checkToxicity;
+ }
+
+ /**
+ * @return Topics the text must not discuss.
+ */
+ public List getDenyTopics() {
+ return denyTopics;
+ }
+
+ @Override
+ public String toString() {
+ return "CheckGuardrailsRequest{" +
+ "text=" + text +
+ ", checkToxicity=" + checkToxicity +
+ ", denyTopics=" + denyTopics +
+ '}';
+ }
+
+ public static final class CheckGuardrailsRequestBuilder {
+ private String text;
+ private Boolean checkToxicity;
+ private List denyTopics;
+
+ private CheckGuardrailsRequestBuilder() {
+ }
+
+ /**
+ * @param text Text to screen. Required.
+ * @return this builder
+ */
+ public CheckGuardrailsRequestBuilder text(String text) {
+ this.text = text;
+ return this;
+ }
+
+ /**
+ * @param checkToxicity Whether to check the text for toxicity.
+ * @return this builder
+ */
+ public CheckGuardrailsRequestBuilder checkToxicity(Boolean checkToxicity) {
+ this.checkToxicity = checkToxicity;
+ return this;
+ }
+
+ /**
+ * @param denyTopics Topics the text must not discuss.
+ * @return this builder
+ */
+ public CheckGuardrailsRequestBuilder denyTopics(List denyTopics) {
+ this.denyTopics = denyTopics;
+ return this;
+ }
+
+ public CheckGuardrailsRequest build() {
+ return new CheckGuardrailsRequest(this);
+ }
+ }
+}
diff --git a/common/src/main/java/com/skyflow/detect/CheckGuardrailsResponse.java b/common/src/main/java/com/skyflow/detect/CheckGuardrailsResponse.java
new file mode 100644
index 00000000..153e68cf
--- /dev/null
+++ b/common/src/main/java/com/skyflow/detect/CheckGuardrailsResponse.java
@@ -0,0 +1,56 @@
+package com.skyflow.detect;
+
+/**
+ * Response of {@code checkGuardrails}.
+ */
+public final class CheckGuardrailsResponse {
+ private final String text;
+ private final GuardrailsValidation validation;
+ private final Boolean toxic;
+ private final Boolean deniedTopic;
+
+ public CheckGuardrailsResponse(String text, GuardrailsValidation validation, Boolean toxic, Boolean deniedTopic) {
+ this.text = text;
+ this.validation = validation;
+ this.toxic = toxic;
+ this.deniedTopic = deniedTopic;
+ }
+
+ /**
+ * @return The text that was screened.
+ */
+ public String getText() {
+ return text;
+ }
+
+ /**
+ * @return PASSED when no guardrail was triggered, FAILED otherwise.
+ */
+ public GuardrailsValidation getValidation() {
+ return validation;
+ }
+
+ /**
+ * @return Whether the text was judged toxic. Null when toxicity was not checked.
+ */
+ public Boolean getToxic() {
+ return toxic;
+ }
+
+ /**
+ * @return Whether the text touched a denied topic. Null when no topics were supplied.
+ */
+ public Boolean getDeniedTopic() {
+ return deniedTopic;
+ }
+
+ @Override
+ public String toString() {
+ return "CheckGuardrailsResponse{" +
+ "text=" + text +
+ ", validation=" + validation +
+ ", toxic=" + toxic +
+ ", deniedTopic=" + deniedTopic +
+ '}';
+ }
+}
diff --git a/common/src/main/java/com/skyflow/detect/CustomType.java b/common/src/main/java/com/skyflow/detect/CustomType.java
new file mode 100644
index 00000000..1eee269a
--- /dev/null
+++ b/common/src/main/java/com/skyflow/detect/CustomType.java
@@ -0,0 +1,75 @@
+package com.skyflow.detect;
+
+import java.util.List;
+
+/**
+ * A custom, regex-defined entity type.
+ */
+public final class CustomType {
+ private final String label;
+ private final List match;
+
+ private CustomType(CustomTypeBuilder builder) {
+ this.label = builder.label;
+ this.match = builder.match;
+ }
+
+ /**
+ * @return a new builder
+ */
+ public static CustomTypeBuilder builder() {
+ return new CustomTypeBuilder();
+ }
+
+ /**
+ * @return Label reported as the entityType of matches.
+ */
+ public String getLabel() {
+ return label;
+ }
+
+ /**
+ * @return Regular expressions that identify the custom entity.
+ */
+ public List getMatch() {
+ return match;
+ }
+
+ @Override
+ public String toString() {
+ return "CustomType{" +
+ "label=" + label +
+ ", match=" + match +
+ '}';
+ }
+
+ public static final class CustomTypeBuilder {
+ private String label;
+ private List match;
+
+ private CustomTypeBuilder() {
+ }
+
+ /**
+ * @param label Label reported as the entityType of matches.
+ * @return this builder
+ */
+ public CustomTypeBuilder label(String label) {
+ this.label = label;
+ return this;
+ }
+
+ /**
+ * @param match Regular expressions that identify the custom entity.
+ * @return this builder
+ */
+ public CustomTypeBuilder match(List match) {
+ this.match = match;
+ return this;
+ }
+
+ public CustomType build() {
+ return new CustomType(this);
+ }
+ }
+}
diff --git a/common/src/main/java/com/skyflow/detect/DeidentificationType.java b/common/src/main/java/com/skyflow/detect/DeidentificationType.java
new file mode 100644
index 00000000..067d533f
--- /dev/null
+++ b/common/src/main/java/com/skyflow/detect/DeidentificationType.java
@@ -0,0 +1,12 @@
+package com.skyflow.detect;
+
+/**
+ * How a detected entity is replaced in the processed output.
+ */
+public enum DeidentificationType {
+ UNKNOWN,
+ ENTITY_UNIQUE_COUNTER,
+ ENTITY_ONLY,
+ VAULT_TOKEN,
+ MASK;
+}
diff --git a/common/src/main/java/com/skyflow/detect/DeidentifyFileRequest.java b/common/src/main/java/com/skyflow/detect/DeidentifyFileRequest.java
new file mode 100644
index 00000000..914989dc
--- /dev/null
+++ b/common/src/main/java/com/skyflow/detect/DeidentifyFileRequest.java
@@ -0,0 +1,227 @@
+package com.skyflow.detect;
+
+import java.io.File;
+
+/**
+ * Request for {@code deidentifyFile}. Supply the file through exactly one of {@code filePath}, {@code file}
+ * or {@code value} (with a {@code dataSource}); more than one, or none, is rejected before any call. A local
+ * file given as {@code file} or {@code filePath} is read when the request is sent, sent as {@code BASE64}, and
+ * its {@code dataFormat} is inferred from the extension unless set explicitly.
+ *
+ *
Without {@code pollOptions} the call submits the run and returns its id. With {@code pollOptions} the
+ * SDK polls the run and, on success for a file-based request, writes the outputs to disk.
+ *
+ *
{@code configurationId} and {@code configuration} are both optional and are sent exactly as supplied.
+ * With neither set, the SDK sends a configuration that carries only the vault id, so the server applies
+ * the vault's defaults.
+ */
+public final class DeidentifyFileRequest {
+ private final DeidentifyFileSource dataSource;
+ private final String value;
+ private final File file;
+ private final String filePath;
+ private final FileDataFormat dataFormat;
+ private final String configurationId;
+ private final DetectConfiguration configuration;
+ private final PollOptions pollOptions;
+ private final String outputDirectory;
+
+ private DeidentifyFileRequest(DeidentifyFileRequestBuilder builder) {
+ this.dataSource = builder.dataSource;
+ this.value = builder.value;
+ this.file = builder.file;
+ this.filePath = builder.filePath;
+ this.dataFormat = builder.dataFormat;
+ this.configurationId = builder.configurationId;
+ this.configuration = builder.configuration;
+ this.pollOptions = builder.pollOptions;
+ this.outputDirectory = builder.outputDirectory;
+ }
+
+ /**
+ * @return a new builder
+ */
+ public static DeidentifyFileRequestBuilder builder() {
+ return new DeidentifyFileRequestBuilder();
+ }
+
+ /**
+ * @return How {@code value} supplies the file: this SDK's {@code DeidentifySourceType} (skyvault: BASE64, SKYFLOW_ID,
+ * PRESIGNED_URL; flowvault: BASE64, PRESIGNED_URL). Required with {@code value}.
+ */
+ public DeidentifyFileSource getDataSource() {
+ return dataSource;
+ }
+
+ /**
+ * @return The file as {@code dataSource} describes it: base64 content, a presigned URL or, on skyvault, a skyflow id.
+ */
+ public String getValue() {
+ return value;
+ }
+
+ /**
+ * @return Local file to de-identify, when {@code file} was used.
+ */
+ public File getFile() {
+ return file;
+ }
+
+ /**
+ * @return Path of the local file to de-identify, when {@code filePath} was used.
+ */
+ public String getFilePath() {
+ return filePath;
+ }
+
+ /**
+ * @return Format of the file. Optional; inferred from the file extension or by the server when omitted.
+ */
+ public FileDataFormat getDataFormat() {
+ return dataFormat;
+ }
+
+ /**
+ * @return Id of a stored Detect configuration.
+ */
+ public String getConfigurationId() {
+ return configurationId;
+ }
+
+ /**
+ * @return Inline Detect configuration.
+ */
+ public DetectConfiguration getConfiguration() {
+ return configuration;
+ }
+
+ /**
+ * @return Polling settings, or null to submit only.
+ */
+ public PollOptions getPollOptions() {
+ return pollOptions;
+ }
+
+ /**
+ * @return Directory the outputs are written to on success. Only with {@code pollOptions} and a file-based request.
+ */
+ public String getOutputDirectory() {
+ return outputDirectory;
+ }
+
+ @Override
+ public String toString() {
+ return "DeidentifyFileRequest{" +
+ "dataSource=" + dataSource +
+ ", value=" + (value == null ? null : "<" + value.length() + " chars>") +
+ ", file=" + file +
+ ", filePath=" + filePath +
+ ", dataFormat=" + dataFormat +
+ ", configurationId=" + configurationId +
+ ", configuration=" + configuration +
+ ", pollOptions=" + pollOptions +
+ ", outputDirectory=" + outputDirectory +
+ '}';
+ }
+
+ public static final class DeidentifyFileRequestBuilder {
+ private DeidentifyFileSource dataSource;
+ private String value;
+ private File file;
+ private String filePath;
+ private FileDataFormat dataFormat;
+ private String configurationId;
+ private DetectConfiguration configuration;
+ private PollOptions pollOptions;
+ private String outputDirectory;
+
+ private DeidentifyFileRequestBuilder() {
+ }
+
+ /**
+ * @param dataSource How {@code value} supplies the file: this SDK's {@code DeidentifySourceType}
+ * (skyvault: BASE64, SKYFLOW_ID, PRESIGNED_URL; flowvault: BASE64, PRESIGNED_URL).
+ * @return this builder
+ */
+ public DeidentifyFileRequestBuilder dataSource(DeidentifyFileSource dataSource) {
+ this.dataSource = dataSource;
+ return this;
+ }
+
+ /**
+ * @param value The file as {@code dataSource} describes it: base64 content, a presigned URL or, on skyvault, a skyflow id.
+ * @return this builder
+ */
+ public DeidentifyFileRequestBuilder value(String value) {
+ this.value = value;
+ return this;
+ }
+
+ /**
+ * @param file Local file to de-identify. Sent as BASE64; the content is encoded when sent.
+ * @return this builder
+ */
+ public DeidentifyFileRequestBuilder file(File file) {
+ this.file = file;
+ return this;
+ }
+
+ /**
+ * @param filePath Path of a local file to de-identify. Sent as BASE64; the content is encoded when sent.
+ * @return this builder
+ */
+ public DeidentifyFileRequestBuilder filePath(String filePath) {
+ this.filePath = filePath;
+ return this;
+ }
+
+ /**
+ * @param dataFormat Format of the file. Optional.
+ * @return this builder
+ */
+ public DeidentifyFileRequestBuilder dataFormat(FileDataFormat dataFormat) {
+ this.dataFormat = dataFormat;
+ return this;
+ }
+
+ /**
+ * @param configurationId Id of a stored Detect configuration.
+ * @return this builder
+ */
+ public DeidentifyFileRequestBuilder configurationId(String configurationId) {
+ this.configurationId = configurationId;
+ return this;
+ }
+
+ /**
+ * @param configuration Inline Detect configuration.
+ * @return this builder
+ */
+ public DeidentifyFileRequestBuilder configuration(DetectConfiguration configuration) {
+ this.configuration = configuration;
+ return this;
+ }
+
+ /**
+ * @param pollOptions Poll the run after submitting. Null to submit only.
+ * @return this builder
+ */
+ public DeidentifyFileRequestBuilder pollOptions(PollOptions pollOptions) {
+ this.pollOptions = pollOptions;
+ return this;
+ }
+
+ /**
+ * @param outputDirectory Where to write outputs on success. Requires {@code pollOptions} and a file-based request.
+ * @return this builder
+ */
+ public DeidentifyFileRequestBuilder outputDirectory(String outputDirectory) {
+ this.outputDirectory = outputDirectory;
+ return this;
+ }
+
+ public DeidentifyFileRequest build() {
+ return new DeidentifyFileRequest(this);
+ }
+ }
+}
diff --git a/common/src/main/java/com/skyflow/detect/DeidentifyFileResponse.java b/common/src/main/java/com/skyflow/detect/DeidentifyFileResponse.java
new file mode 100644
index 00000000..730177cc
--- /dev/null
+++ b/common/src/main/java/com/skyflow/detect/DeidentifyFileResponse.java
@@ -0,0 +1,83 @@
+package com.skyflow.detect;
+
+import java.util.List;
+
+/**
+ * Response of {@code deidentifyFile}. {@code runId} is always present. {@code status} is null when the
+ * request did not poll; retrieve the run later with {@code getRun}. When polled, the remaining fields
+ * mirror {@link GetRunResponse}: output, outputType and metrics are populated only on SUCCESS, and
+ * message carries the failure detail on FAILED.
+ */
+public final class DeidentifyFileResponse {
+ private final String runId;
+ private final DetectRunStatus status;
+ private final DeidentifyFileSource outputType;
+ private final List output;
+ private final Metrics metrics;
+ private final String message;
+
+ public DeidentifyFileResponse(String runId, DetectRunStatus status, DeidentifyFileSource outputType,
+ List output, Metrics metrics, String message) {
+ this.runId = runId;
+ this.status = status;
+ this.outputType = outputType;
+ this.output = output;
+ this.metrics = metrics;
+ this.message = message;
+ }
+
+ /**
+ * @return Run id returned by the submit call. Use it with {@code getRun} to retrieve or resume.
+ */
+ public String getRunId() {
+ return runId;
+ }
+
+ /**
+ * @return Run status after polling. Null when the request did not poll. IN_PROGRESS or QUEUED when the
+ * polling budget ran out before the run finished.
+ */
+ public DetectRunStatus getStatus() {
+ return status;
+ }
+
+ /**
+ * @return How output files are delivered. Null unless polled to SUCCESS. A constant of this SDK's {@code DeidentifySourceType}: {@code BASE64} or {@code PRESIGNED_URL}.
+ */
+ public DeidentifyFileSource getOutputType() {
+ return outputType;
+ }
+
+ /**
+ * @return Output artifacts. Empty unless polled to SUCCESS, never null.
+ */
+ public List getOutput() {
+ return output;
+ }
+
+ /**
+ * @return Processing metrics. Null unless polled to SUCCESS.
+ */
+ public Metrics getMetrics() {
+ return metrics;
+ }
+
+ /**
+ * @return Failure detail when status is FAILED.
+ */
+ public String getMessage() {
+ return message;
+ }
+
+ @Override
+ public String toString() {
+ return "DeidentifyFileResponse{" +
+ "runId=" + runId +
+ ", status=" + status +
+ ", outputType=" + outputType +
+ ", output=" + output +
+ ", metrics=" + metrics +
+ ", message=" + message +
+ '}';
+ }
+}
diff --git a/common/src/main/java/com/skyflow/detect/DeidentifyFileSource.java b/common/src/main/java/com/skyflow/detect/DeidentifyFileSource.java
new file mode 100644
index 00000000..f60439ac
--- /dev/null
+++ b/common/src/main/java/com/skyflow/detect/DeidentifyFileSource.java
@@ -0,0 +1,15 @@
+package com.skyflow.detect;
+
+/**
+ * How the file of {@code deidentifyFile} is supplied, and how a run reports its outputs. Each SDK ships its own
+ * {@code com.skyflow.detect.DeidentifySourceType} enum implementing this interface with the sources its vault
+ * type accepts: skyvault {@code BASE64}, {@code SKYFLOW_ID}, {@code PRESIGNED_URL}; flowvault {@code BASE64},
+ * {@code PRESIGNED_URL}. {@code getOutputType()} on {@code DeidentifyFileResponse} and {@code GetRunResponse}
+ * returns a constant of that same enum. The constant name is the wire value.
+ */
+public interface DeidentifyFileSource {
+ /**
+ * @return the wire value, which is the constant name
+ */
+ String name();
+}
diff --git a/common/src/main/java/com/skyflow/detect/DeidentifyStringRequest.java b/common/src/main/java/com/skyflow/detect/DeidentifyStringRequest.java
new file mode 100644
index 00000000..f5bb22c4
--- /dev/null
+++ b/common/src/main/java/com/skyflow/detect/DeidentifyStringRequest.java
@@ -0,0 +1,95 @@
+package com.skyflow.detect;
+
+/**
+ * Request for {@code deidentifyString}. configurationId and configuration are both optional and are sent
+ * exactly as supplied; the server applies its own rules for their combination. With neither set, the SDK
+ * sends a configuration that carries only the vault id, so the server applies the vault's defaults.
+ */
+public final class DeidentifyStringRequest {
+ private final String text;
+ private final String configurationId;
+ private final DetectConfiguration configuration;
+
+ private DeidentifyStringRequest(DeidentifyStringRequestBuilder builder) {
+ this.text = builder.text;
+ this.configurationId = builder.configurationId;
+ this.configuration = builder.configuration;
+ }
+
+ /**
+ * @return a new builder
+ */
+ public static DeidentifyStringRequestBuilder builder() {
+ return new DeidentifyStringRequestBuilder();
+ }
+
+ /**
+ * @return Text to de-identify. Required.
+ */
+ public String getText() {
+ return text;
+ }
+
+ /**
+ * @return Id of a stored Detect configuration.
+ */
+ public String getConfigurationId() {
+ return configurationId;
+ }
+
+ /**
+ * @return Inline Detect configuration.
+ */
+ public DetectConfiguration getConfiguration() {
+ return configuration;
+ }
+
+ @Override
+ public String toString() {
+ return "DeidentifyStringRequest{" +
+ "text=" + text +
+ ", configurationId=" + configurationId +
+ ", configuration=" + configuration +
+ '}';
+ }
+
+ public static final class DeidentifyStringRequestBuilder {
+ private String text;
+ private String configurationId;
+ private DetectConfiguration configuration;
+
+ private DeidentifyStringRequestBuilder() {
+ }
+
+ /**
+ * @param text Text to de-identify. Required.
+ * @return this builder
+ */
+ public DeidentifyStringRequestBuilder text(String text) {
+ this.text = text;
+ return this;
+ }
+
+ /**
+ * @param configurationId Id of a stored Detect configuration.
+ * @return this builder
+ */
+ public DeidentifyStringRequestBuilder configurationId(String configurationId) {
+ this.configurationId = configurationId;
+ return this;
+ }
+
+ /**
+ * @param configuration Inline Detect configuration.
+ * @return this builder
+ */
+ public DeidentifyStringRequestBuilder configuration(DetectConfiguration configuration) {
+ this.configuration = configuration;
+ return this;
+ }
+
+ public DeidentifyStringRequest build() {
+ return new DeidentifyStringRequest(this);
+ }
+ }
+}
diff --git a/common/src/main/java/com/skyflow/detect/DeidentifyStringResponse.java b/common/src/main/java/com/skyflow/detect/DeidentifyStringResponse.java
new file mode 100644
index 00000000..7ea68dcf
--- /dev/null
+++ b/common/src/main/java/com/skyflow/detect/DeidentifyStringResponse.java
@@ -0,0 +1,48 @@
+package com.skyflow.detect;
+
+import java.util.List;
+
+/**
+ * Response of {@code deidentifyString}.
+ */
+public final class DeidentifyStringResponse {
+ private final String processedText;
+ private final List entities;
+ private final Metrics metrics;
+
+ public DeidentifyStringResponse(String processedText, List entities, Metrics metrics) {
+ this.processedText = processedText;
+ this.entities = entities;
+ this.metrics = metrics;
+ }
+
+ /**
+ * @return De-identified text.
+ */
+ public String getProcessedText() {
+ return processedText;
+ }
+
+ /**
+ * @return Detected entities. Never null.
+ */
+ public List getEntities() {
+ return entities;
+ }
+
+ /**
+ * @return Processing metrics.
+ */
+ public Metrics getMetrics() {
+ return metrics;
+ }
+
+ @Override
+ public String toString() {
+ return "DeidentifyStringResponse{" +
+ "processedText=" + processedText +
+ ", entities=" + entities +
+ ", metrics=" + metrics +
+ '}';
+ }
+}
diff --git a/common/src/main/java/com/skyflow/detect/Detect.java b/common/src/main/java/com/skyflow/detect/Detect.java
new file mode 100644
index 00000000..dc998e57
--- /dev/null
+++ b/common/src/main/java/com/skyflow/detect/Detect.java
@@ -0,0 +1,155 @@
+package com.skyflow.detect;
+
+import java.util.List;
+
+/**
+ * Detection policy: which entities to look for and how to replace them.
+ */
+public final class Detect {
+ private final List entities;
+ private final List objectEntities;
+ private final List restrict;
+ private final List skip;
+ private final List customTypes;
+ private final ReturnEntitiesType returnEntities;
+
+ private Detect(DetectBuilder builder) {
+ this.entities = builder.entities;
+ this.objectEntities = builder.objectEntities;
+ this.restrict = builder.restrict;
+ this.skip = builder.skip;
+ this.customTypes = builder.customTypes;
+ this.returnEntities = builder.returnEntities;
+ }
+
+ /**
+ * @return a new builder
+ */
+ public static DetectBuilder builder() {
+ return new DetectBuilder();
+ }
+
+ /**
+ * @return Per-entity rules.
+ */
+ public List getEntities() {
+ return entities;
+ }
+
+ /**
+ * @return Per-object rules. File inputs only.
+ */
+ public List getObjectEntities() {
+ return objectEntities;
+ }
+
+ /**
+ * @return Regular expressions that are always treated as sensitive.
+ */
+ public List getRestrict() {
+ return restrict;
+ }
+
+ /**
+ * @return Regular expressions that are never treated as sensitive.
+ */
+ public List getSkip() {
+ return skip;
+ }
+
+ /**
+ * @return Custom regex-defined entity types.
+ */
+ public List getCustomTypes() {
+ return customTypes;
+ }
+
+ /**
+ * @return Which entities to return. Defaults to EXCLUDE_SENSITIVE_DATA on the server.
+ */
+ public ReturnEntitiesType getReturnEntities() {
+ return returnEntities;
+ }
+
+ @Override
+ public String toString() {
+ return "Detect{" +
+ "entities=" + entities +
+ ", objectEntities=" + objectEntities +
+ ", restrict=" + restrict +
+ ", skip=" + skip +
+ ", customTypes=" + customTypes +
+ ", returnEntities=" + returnEntities +
+ '}';
+ }
+
+ public static final class DetectBuilder {
+ private List entities;
+ private List objectEntities;
+ private List restrict;
+ private List skip;
+ private List customTypes;
+ private ReturnEntitiesType returnEntities;
+
+ private DetectBuilder() {
+ }
+
+ /**
+ * @param entities Per-entity rules.
+ * @return this builder
+ */
+ public DetectBuilder entities(List entities) {
+ this.entities = entities;
+ return this;
+ }
+
+ /**
+ * @param objectEntities Per-object rules. File inputs only.
+ * @return this builder
+ */
+ public DetectBuilder objectEntities(List objectEntities) {
+ this.objectEntities = objectEntities;
+ return this;
+ }
+
+ /**
+ * @param restrict Regular expressions that are always treated as sensitive.
+ * @return this builder
+ */
+ public DetectBuilder restrict(List restrict) {
+ this.restrict = restrict;
+ return this;
+ }
+
+ /**
+ * @param skip Regular expressions that are never treated as sensitive.
+ * @return this builder
+ */
+ public DetectBuilder skip(List skip) {
+ this.skip = skip;
+ return this;
+ }
+
+ /**
+ * @param customTypes Custom regex-defined entity types.
+ * @return this builder
+ */
+ public DetectBuilder customTypes(List customTypes) {
+ this.customTypes = customTypes;
+ return this;
+ }
+
+ /**
+ * @param returnEntities Which entities to return. Defaults to EXCLUDE_SENSITIVE_DATA on the server.
+ * @return this builder
+ */
+ public DetectBuilder returnEntities(ReturnEntitiesType returnEntities) {
+ this.returnEntities = returnEntities;
+ return this;
+ }
+
+ public Detect build() {
+ return new Detect(this);
+ }
+ }
+}
diff --git a/common/src/main/java/com/skyflow/detect/DetectConfiguration.java b/common/src/main/java/com/skyflow/detect/DetectConfiguration.java
new file mode 100644
index 00000000..e9209528
--- /dev/null
+++ b/common/src/main/java/com/skyflow/detect/DetectConfiguration.java
@@ -0,0 +1,135 @@
+package com.skyflow.detect;
+
+import java.util.List;
+
+/**
+ * An inline Detect configuration, used instead of a stored configuration id.
+ */
+public final class DetectConfiguration {
+ private final String name;
+ private final String description;
+ private final Detect detect;
+ private final List fileMapping;
+ private final Media media;
+
+ private DetectConfiguration(DetectConfigurationBuilder builder) {
+ this.name = builder.name;
+ this.description = builder.description;
+ this.detect = builder.detect;
+ this.fileMapping = builder.fileMapping;
+ this.media = builder.media;
+ }
+
+ /**
+ * @return a new builder
+ */
+ public static DetectConfigurationBuilder builder() {
+ return new DetectConfigurationBuilder();
+ }
+
+ /**
+ * @return Configuration name.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * @return Configuration description.
+ */
+ public String getDescription() {
+ return description;
+ }
+
+ /**
+ * @return Detection policy.
+ */
+ public Detect getDetect() {
+ return detect;
+ }
+
+ /**
+ * @return File mappings. File inputs only.
+ */
+ public List getFileMapping() {
+ return fileMapping;
+ }
+
+ /**
+ * @return Media options. File inputs only.
+ */
+ public Media getMedia() {
+ return media;
+ }
+
+ @Override
+ public String toString() {
+ return "DetectConfiguration{" +
+ "name=" + name +
+ ", description=" + description +
+ ", detect=" + detect +
+ ", fileMapping=" + fileMapping +
+ ", media=" + media +
+ '}';
+ }
+
+ public static final class DetectConfigurationBuilder {
+ private String name;
+ private String description;
+ private Detect detect;
+ private List fileMapping;
+ private Media media;
+
+ private DetectConfigurationBuilder() {
+ }
+
+ /**
+ * @param name Configuration name.
+ * @return this builder
+ */
+ public DetectConfigurationBuilder name(String name) {
+ this.name = name;
+ return this;
+ }
+
+ /**
+ * @param description Configuration description.
+ * @return this builder
+ */
+ public DetectConfigurationBuilder description(String description) {
+ this.description = description;
+ return this;
+ }
+
+ /**
+ * @param detect Detection policy.
+ * @return this builder
+ */
+ public DetectConfigurationBuilder detect(Detect detect) {
+ this.detect = detect;
+ return this;
+ }
+
+ /**
+ * @param fileMapping File mappings. File inputs only.
+ * @return this builder
+ */
+ public DetectConfigurationBuilder fileMapping(List fileMapping) {
+ this.fileMapping = fileMapping;
+ return this;
+ }
+
+ /**
+ * @param media Media options. File inputs only.
+ * @return this builder
+ */
+ public DetectConfigurationBuilder media(Media media) {
+ this.media = media;
+ return this;
+ }
+
+ public DetectConfiguration build() {
+ return new DetectConfiguration(this);
+ }
+ }
+}
diff --git a/common/src/main/java/com/skyflow/detect/DetectRunStatus.java b/common/src/main/java/com/skyflow/detect/DetectRunStatus.java
new file mode 100644
index 00000000..3bb05886
--- /dev/null
+++ b/common/src/main/java/com/skyflow/detect/DetectRunStatus.java
@@ -0,0 +1,12 @@
+package com.skyflow.detect;
+
+/**
+ * Lifecycle status of an asynchronous Detect file run.
+ */
+public enum DetectRunStatus {
+ UNKNOWN,
+ QUEUED,
+ IN_PROGRESS,
+ SUCCESS,
+ FAILED;
+}
diff --git a/common/src/main/java/com/skyflow/detect/DetectedEntity.java b/common/src/main/java/com/skyflow/detect/DetectedEntity.java
new file mode 100644
index 00000000..6a443d1c
--- /dev/null
+++ b/common/src/main/java/com/skyflow/detect/DetectedEntity.java
@@ -0,0 +1,68 @@
+package com.skyflow.detect;
+
+import java.util.Map;
+
+/**
+ * An entity detected in the input text.
+ */
+public final class DetectedEntity {
+ private final String token;
+ private final String value;
+ private final EntityLocation location;
+ private final String entityType;
+ private final Map entityScores;
+
+ public DetectedEntity(String token, String value, EntityLocation location, String entityType, Map entityScores) {
+ this.token = token;
+ this.value = value;
+ this.location = location;
+ this.entityType = entityType;
+ this.entityScores = entityScores;
+ }
+
+ /**
+ * @return Replacement token, for example NAME_1.
+ */
+ public String getToken() {
+ return token;
+ }
+
+ /**
+ * @return Original value. Empty unless returnEntities is ALL.
+ */
+ public String getValue() {
+ return value;
+ }
+
+ /**
+ * @return Where the entity was found.
+ */
+ public EntityLocation getLocation() {
+ return location;
+ }
+
+ /**
+ * @return Entity type. Carries custom-type labels as well as built-in types.
+ */
+ public String getEntityType() {
+ return entityType;
+ }
+
+ /**
+ * @return Confidence scores by entity type, 0.0 to 1.0.
+ */
+ public Map getEntityScores() {
+ return entityScores;
+ }
+
+ @Override
+ public String toString() {
+ return "DetectedEntity{" +
+ "token=" + token +
+ ", value=" + value +
+ ", location=" + location +
+ ", entityType=" + entityType +
+ ", entityScores=" + entityScores +
+ '}';
+ }
+}
diff --git a/common/src/main/java/com/skyflow/detect/Document.java b/common/src/main/java/com/skyflow/detect/Document.java
new file mode 100644
index 00000000..2d461196
--- /dev/null
+++ b/common/src/main/java/com/skyflow/detect/Document.java
@@ -0,0 +1,53 @@
+package com.skyflow.detect;
+
+/**
+ * Document processing options.
+ */
+public final class Document {
+ private final Pdf pdf;
+
+ private Document(DocumentBuilder builder) {
+ this.pdf = builder.pdf;
+ }
+
+ /**
+ * @return a new builder
+ */
+ public static DocumentBuilder builder() {
+ return new DocumentBuilder();
+ }
+
+ /**
+ * @return PDF options.
+ */
+ public Pdf getPdf() {
+ return pdf;
+ }
+
+ @Override
+ public String toString() {
+ return "Document{" +
+ "pdf=" + pdf +
+ '}';
+ }
+
+ public static final class DocumentBuilder {
+ private Pdf pdf;
+
+ private DocumentBuilder() {
+ }
+
+ /**
+ * @param pdf PDF options.
+ * @return this builder
+ */
+ public DocumentBuilder pdf(Pdf pdf) {
+ this.pdf = pdf;
+ return this;
+ }
+
+ public Document build() {
+ return new Document(this);
+ }
+ }
+}
diff --git a/common/src/main/java/com/skyflow/detect/Entity.java b/common/src/main/java/com/skyflow/detect/Entity.java
new file mode 100644
index 00000000..992acafd
--- /dev/null
+++ b/common/src/main/java/com/skyflow/detect/Entity.java
@@ -0,0 +1,113 @@
+package com.skyflow.detect;
+
+/**
+ * Configures how a single entity type is detected and de-identified.
+ */
+public final class Entity {
+ private final EntityType entityType;
+ private final DeidentificationType deidentificationType;
+ private final String destination;
+ private final Transformation transformation;
+
+ private Entity(EntityBuilder builder) {
+ this.entityType = builder.entityType;
+ this.deidentificationType = builder.deidentificationType;
+ this.destination = builder.destination;
+ this.transformation = builder.transformation;
+ }
+
+ /**
+ * @return a new builder
+ */
+ public static EntityBuilder builder() {
+ return new EntityBuilder();
+ }
+
+ /**
+ * @return Entity type this rule applies to. Defaults to ALL on the server.
+ */
+ public EntityType getEntityType() {
+ return entityType;
+ }
+
+ /**
+ * @return Replacement strategy. Defaults to ENTITY_UNIQUE_COUNTER on the server.
+ */
+ public DeidentificationType getDeidentificationType() {
+ return deidentificationType;
+ }
+
+ /**
+ * @return Where vault tokens are stored: a table.column (skyvault) or token-group name (flowvault). Only used with VAULT_TOKEN.
+ */
+ public String getDestination() {
+ return destination;
+ }
+
+ /**
+ * @return Optional transformation applied to the detected value.
+ */
+ public Transformation getTransformation() {
+ return transformation;
+ }
+
+ @Override
+ public String toString() {
+ return "Entity{" +
+ "entityType=" + entityType +
+ ", deidentificationType=" + deidentificationType +
+ ", destination=" + destination +
+ ", transformation=" + transformation +
+ '}';
+ }
+
+ public static final class EntityBuilder {
+ private EntityType entityType;
+ private DeidentificationType deidentificationType;
+ private String destination;
+ private Transformation transformation;
+
+ private EntityBuilder() {
+ }
+
+ /**
+ * @param entityType Entity type this rule applies to. Defaults to ALL on the server.
+ * @return this builder
+ */
+ public EntityBuilder entityType(EntityType entityType) {
+ this.entityType = entityType;
+ return this;
+ }
+
+ /**
+ * @param deidentificationType Replacement strategy. Defaults to ENTITY_UNIQUE_COUNTER on the server.
+ * @return this builder
+ */
+ public EntityBuilder deidentificationType(DeidentificationType deidentificationType) {
+ this.deidentificationType = deidentificationType;
+ return this;
+ }
+
+ /**
+ * @param destination Where vault tokens are stored: a table.column (skyvault) or token-group name (flowvault). Only used with VAULT_TOKEN.
+ * @return this builder
+ */
+ public EntityBuilder destination(String destination) {
+ this.destination = destination;
+ return this;
+ }
+
+ /**
+ * @param transformation Optional transformation applied to the detected value.
+ * @return this builder
+ */
+ public EntityBuilder transformation(Transformation transformation) {
+ this.transformation = transformation;
+ return this;
+ }
+
+ public Entity build() {
+ return new Entity(this);
+ }
+ }
+}
diff --git a/common/src/main/java/com/skyflow/detect/EntityLocation.java b/common/src/main/java/com/skyflow/detect/EntityLocation.java
new file mode 100644
index 00000000..88b45048
--- /dev/null
+++ b/common/src/main/java/com/skyflow/detect/EntityLocation.java
@@ -0,0 +1,56 @@
+package com.skyflow.detect;
+
+/**
+ * Position of a detected entity in the original and processed text.
+ */
+public final class EntityLocation {
+ private final Integer startIndex;
+ private final Integer endIndex;
+ private final Integer startIndexProcessed;
+ private final Integer endIndexProcessed;
+
+ public EntityLocation(Integer startIndex, Integer endIndex, Integer startIndexProcessed, Integer endIndexProcessed) {
+ this.startIndex = startIndex;
+ this.endIndex = endIndex;
+ this.startIndexProcessed = startIndexProcessed;
+ this.endIndexProcessed = endIndexProcessed;
+ }
+
+ /**
+ * @return Start index in the original text.
+ */
+ public Integer getStartIndex() {
+ return startIndex;
+ }
+
+ /**
+ * @return End index in the original text.
+ */
+ public Integer getEndIndex() {
+ return endIndex;
+ }
+
+ /**
+ * @return Start index in the processed text.
+ */
+ public Integer getStartIndexProcessed() {
+ return startIndexProcessed;
+ }
+
+ /**
+ * @return End index in the processed text.
+ */
+ public Integer getEndIndexProcessed() {
+ return endIndexProcessed;
+ }
+
+ @Override
+ public String toString() {
+ return "EntityLocation{" +
+ "startIndex=" + startIndex +
+ ", endIndex=" + endIndex +
+ ", startIndexProcessed=" + startIndexProcessed +
+ ", endIndexProcessed=" + endIndexProcessed +
+ '}';
+ }
+}
diff --git a/common/src/main/java/com/skyflow/detect/EntityType.java b/common/src/main/java/com/skyflow/detect/EntityType.java
new file mode 100644
index 00000000..82cae959
--- /dev/null
+++ b/common/src/main/java/com/skyflow/detect/EntityType.java
@@ -0,0 +1,78 @@
+package com.skyflow.detect;
+
+/**
+ * Entity types Skyflow Detect can identify. Also used to target entities in {@code RedactionLevel}.
+ */
+public enum EntityType {
+ NONE,
+ ACCOUNT_NUMBER,
+ AGE,
+ ALL,
+ BANK_ACCOUNT,
+ BLOOD_TYPE,
+ CONDITION,
+ CORPORATE_ACTION,
+ CREDIT_CARD,
+ CREDIT_CARD_EXPIRATION,
+ CVV,
+ DATE,
+ DATE_INTERVAL,
+ DAY,
+ DOB,
+ DOSE,
+ DRIVER_LICENSE,
+ DRUG,
+ DURATION,
+ EFFECT,
+ EMAIL_ADDRESS,
+ EVENT,
+ FILENAME,
+ FINANCIAL_METRIC,
+ GENDER,
+ HEALTHCARE_NUMBER,
+ INJURY,
+ IP_ADDRESS,
+ LANGUAGE,
+ LOCATION,
+ LOCATION_ADDRESS,
+ LOCATION_ADDRESS_STREET,
+ LOCATION_CITY,
+ LOCATION_COORDINATE,
+ LOCATION_COUNTRY,
+ LOCATION_STATE,
+ LOCATION_ZIP,
+ MARITAL_STATUS,
+ MEDICAL_CODE,
+ MEDICAL_PROCESS,
+ MONEY,
+ MONTH,
+ NAME,
+ NAME_FAMILY,
+ NAME_GIVEN,
+ NAME_MEDICAL_PROFESSIONAL,
+ NUMERICAL_PII,
+ OCCUPATION,
+ ORGANIZATION,
+ ORGANIZATION_ID,
+ ORGANIZATION_MEDICAL_FACILITY,
+ ORIGIN,
+ PASSPORT_NUMBER,
+ PASSWORD,
+ PHONE_NUMBER,
+ PHYSICAL_ATTRIBUTE,
+ POLITICAL_AFFILIATION,
+ PRODUCT,
+ PROJECT,
+ RELIGION,
+ ROUTING_NUMBER,
+ SEXUALITY,
+ SSN,
+ STATISTICS,
+ TIME,
+ TREND,
+ URL,
+ USERNAME,
+ VEHICLE_ID,
+ YEAR,
+ ZODIAC_SIGN;
+}
diff --git a/common/src/main/java/com/skyflow/detect/FileDataFormat.java b/common/src/main/java/com/skyflow/detect/FileDataFormat.java
new file mode 100644
index 00000000..047cb54b
--- /dev/null
+++ b/common/src/main/java/com/skyflow/detect/FileDataFormat.java
@@ -0,0 +1,30 @@
+package com.skyflow.detect;
+
+/**
+ * File formats understood by Detect file operations. The wire value is the lower-case extension.
+ */
+public enum FileDataFormat {
+ BMP,
+ CSV,
+ DCM,
+ DOC,
+ DOCX,
+ GIF,
+ JPEG,
+ JPG,
+ JSON,
+ JSONL,
+ MP3,
+ PDF,
+ PNG,
+ PPT,
+ PPTX,
+ TIF,
+ TIFF,
+ TXT,
+ WAV,
+ XLS,
+ XLSX,
+ XML,
+ ZIP;
+}
diff --git a/common/src/main/java/com/skyflow/detect/FileMapping.java b/common/src/main/java/com/skyflow/detect/FileMapping.java
new file mode 100644
index 00000000..da0663b0
--- /dev/null
+++ b/common/src/main/java/com/skyflow/detect/FileMapping.java
@@ -0,0 +1,133 @@
+package com.skyflow.detect;
+
+/**
+ * Maps an input file location to output locations. File inputs only.
+ */
+public final class FileMapping {
+ private final String source;
+ private final String destination;
+ private final String outputFileNameSuffix;
+ private final String entitiesDestination;
+ private final String objectEntitiesDestination;
+
+ private FileMapping(FileMappingBuilder builder) {
+ this.source = builder.source;
+ this.destination = builder.destination;
+ this.outputFileNameSuffix = builder.outputFileNameSuffix;
+ this.entitiesDestination = builder.entitiesDestination;
+ this.objectEntitiesDestination = builder.objectEntitiesDestination;
+ }
+
+ /**
+ * @return a new builder
+ */
+ public static FileMappingBuilder builder() {
+ return new FileMappingBuilder();
+ }
+
+ /**
+ * @return Source location.
+ */
+ public String getSource() {
+ return source;
+ }
+
+ /**
+ * @return Destination for the processed file.
+ */
+ public String getDestination() {
+ return destination;
+ }
+
+ /**
+ * @return Suffix appended to the processed file name.
+ */
+ public String getOutputFileNameSuffix() {
+ return outputFileNameSuffix;
+ }
+
+ /**
+ * @return Destination for the detected entities file.
+ */
+ public String getEntitiesDestination() {
+ return entitiesDestination;
+ }
+
+ /**
+ * @return Destination for the detected object entities file.
+ */
+ public String getObjectEntitiesDestination() {
+ return objectEntitiesDestination;
+ }
+
+ @Override
+ public String toString() {
+ return "FileMapping{" +
+ "source=" + source +
+ ", destination=" + destination +
+ ", outputFileNameSuffix=" + outputFileNameSuffix +
+ ", entitiesDestination=" + entitiesDestination +
+ ", objectEntitiesDestination=" + objectEntitiesDestination +
+ '}';
+ }
+
+ public static final class FileMappingBuilder {
+ private String source;
+ private String destination;
+ private String outputFileNameSuffix;
+ private String entitiesDestination;
+ private String objectEntitiesDestination;
+
+ private FileMappingBuilder() {
+ }
+
+ /**
+ * @param source Source location.
+ * @return this builder
+ */
+ public FileMappingBuilder source(String source) {
+ this.source = source;
+ return this;
+ }
+
+ /**
+ * @param destination Destination for the processed file.
+ * @return this builder
+ */
+ public FileMappingBuilder destination(String destination) {
+ this.destination = destination;
+ return this;
+ }
+
+ /**
+ * @param outputFileNameSuffix Suffix appended to the processed file name.
+ * @return this builder
+ */
+ public FileMappingBuilder outputFileNameSuffix(String outputFileNameSuffix) {
+ this.outputFileNameSuffix = outputFileNameSuffix;
+ return this;
+ }
+
+ /**
+ * @param entitiesDestination Destination for the detected entities file.
+ * @return this builder
+ */
+ public FileMappingBuilder entitiesDestination(String entitiesDestination) {
+ this.entitiesDestination = entitiesDestination;
+ return this;
+ }
+
+ /**
+ * @param objectEntitiesDestination Destination for the detected object entities file.
+ * @return this builder
+ */
+ public FileMappingBuilder objectEntitiesDestination(String objectEntitiesDestination) {
+ this.objectEntitiesDestination = objectEntitiesDestination;
+ return this;
+ }
+
+ public FileMapping build() {
+ return new FileMapping(this);
+ }
+ }
+}
diff --git a/common/src/main/java/com/skyflow/detect/FileOutput.java b/common/src/main/java/com/skyflow/detect/FileOutput.java
new file mode 100644
index 00000000..a33cafca
--- /dev/null
+++ b/common/src/main/java/com/skyflow/detect/FileOutput.java
@@ -0,0 +1,46 @@
+package com.skyflow.detect;
+
+/**
+ * One output artifact of a Detect file run.
+ */
+public final class FileOutput {
+ private final String processedFile;
+ private final String processedFileType;
+ private final FileDataFormat processedFileExtension;
+
+ public FileOutput(String processedFile, String processedFileType, FileDataFormat processedFileExtension) {
+ this.processedFile = processedFile;
+ this.processedFileType = processedFileType;
+ this.processedFileExtension = processedFileExtension;
+ }
+
+ /**
+ * @return Base64 content or presigned URL, according to the run's outputType.
+ */
+ public String getProcessedFile() {
+ return processedFile;
+ }
+
+ /**
+ * @return Kind of output, for example REDACTED_FILE or ENTITIES. Reported as a string because the API does not enumerate it.
+ */
+ public String getProcessedFileType() {
+ return processedFileType;
+ }
+
+ /**
+ * @return Format of the output, or null when not reported.
+ */
+ public FileDataFormat getProcessedFileExtension() {
+ return processedFileExtension;
+ }
+
+ @Override
+ public String toString() {
+ return "FileOutput{" +
+ "processedFile=" + processedFile +
+ ", processedFileType=" + processedFileType +
+ ", processedFileExtension=" + processedFileExtension +
+ '}';
+ }
+}
diff --git a/common/src/main/java/com/skyflow/detect/GetRunRequest.java b/common/src/main/java/com/skyflow/detect/GetRunRequest.java
new file mode 100644
index 00000000..21a02689
--- /dev/null
+++ b/common/src/main/java/com/skyflow/detect/GetRunRequest.java
@@ -0,0 +1,53 @@
+package com.skyflow.detect;
+
+/**
+ * Request for {@code getRun}: retrieves the status and outputs of a Detect file run.
+ */
+public final class GetRunRequest {
+ private final String runId;
+
+ private GetRunRequest(GetRunRequestBuilder builder) {
+ this.runId = builder.runId;
+ }
+
+ /**
+ * @return a new builder
+ */
+ public static GetRunRequestBuilder builder() {
+ return new GetRunRequestBuilder();
+ }
+
+ /**
+ * @return Run id returned by {@code deidentifyFile}. Required.
+ */
+ public String getRunId() {
+ return runId;
+ }
+
+ @Override
+ public String toString() {
+ return "GetRunRequest{" +
+ "runId=" + runId +
+ '}';
+ }
+
+ public static final class GetRunRequestBuilder {
+ private String runId;
+
+ private GetRunRequestBuilder() {
+ }
+
+ /**
+ * @param runId Run id returned by {@code deidentifyFile}. Required.
+ * @return this builder
+ */
+ public GetRunRequestBuilder runId(String runId) {
+ this.runId = runId;
+ return this;
+ }
+
+ public GetRunRequest build() {
+ return new GetRunRequest(this);
+ }
+ }
+}
diff --git a/common/src/main/java/com/skyflow/detect/GetRunResponse.java b/common/src/main/java/com/skyflow/detect/GetRunResponse.java
new file mode 100644
index 00000000..c892355e
--- /dev/null
+++ b/common/src/main/java/com/skyflow/detect/GetRunResponse.java
@@ -0,0 +1,78 @@
+package com.skyflow.detect;
+
+import java.util.List;
+
+/**
+ * Response of {@code getRun}. Output, outputType and metrics are populated only once the run has succeeded.
+ */
+public final class GetRunResponse {
+ private final String runId;
+ private final DetectRunStatus status;
+ private final DeidentifyFileSource outputType;
+ private final List output;
+ private final Metrics metrics;
+ private final String message;
+
+ public GetRunResponse(String runId, DetectRunStatus status, DeidentifyFileSource outputType, List output, Metrics metrics, String message) {
+ this.runId = runId;
+ this.status = status;
+ this.outputType = outputType;
+ this.output = output;
+ this.metrics = metrics;
+ this.message = message;
+ }
+
+ /**
+ * @return Run id that was queried.
+ */
+ public String getRunId() {
+ return runId;
+ }
+
+ /**
+ * @return Run status. UNKNOWN when the API did not report one.
+ */
+ public DetectRunStatus getStatus() {
+ return status;
+ }
+
+ /**
+ * @return How output files are delivered. Null while the run is pending. A constant of this SDK's {@code DeidentifySourceType}: {@code BASE64} or {@code PRESIGNED_URL}.
+ */
+ public DeidentifyFileSource getOutputType() {
+ return outputType;
+ }
+
+ /**
+ * @return Output artifacts. Empty while the run is pending, never null.
+ */
+ public List getOutput() {
+ return output;
+ }
+
+ /**
+ * @return Processing metrics. Null while the run is pending.
+ */
+ public Metrics getMetrics() {
+ return metrics;
+ }
+
+ /**
+ * @return Failure detail when status is FAILED.
+ */
+ public String getMessage() {
+ return message;
+ }
+
+ @Override
+ public String toString() {
+ return "GetRunResponse{" +
+ "runId=" + runId +
+ ", status=" + status +
+ ", outputType=" + outputType +
+ ", output=" + output +
+ ", metrics=" + metrics +
+ ", message=" + message +
+ '}';
+ }
+}
diff --git a/common/src/main/java/com/skyflow/detect/GuardrailsValidation.java b/common/src/main/java/com/skyflow/detect/GuardrailsValidation.java
new file mode 100644
index 00000000..1d6f0f8c
--- /dev/null
+++ b/common/src/main/java/com/skyflow/detect/GuardrailsValidation.java
@@ -0,0 +1,11 @@
+package com.skyflow.detect;
+
+/**
+ * Overall result of a guardrails check.
+ */
+public enum GuardrailsValidation {
+ PASSED,
+ FAILED,
+ /** The API reported a value this SDK version does not know. */
+ UNKNOWN;
+}
diff --git a/common/src/main/java/com/skyflow/detect/Image.java b/common/src/main/java/com/skyflow/detect/Image.java
new file mode 100644
index 00000000..f1e33135
--- /dev/null
+++ b/common/src/main/java/com/skyflow/detect/Image.java
@@ -0,0 +1,93 @@
+package com.skyflow.detect;
+
+/**
+ * Image processing options.
+ */
+public final class Image {
+ private final Boolean outputProcessedImage;
+ private final Boolean outputOcrText;
+ private final MaskingMethod maskingMethod;
+
+ private Image(ImageBuilder builder) {
+ this.outputProcessedImage = builder.outputProcessedImage;
+ this.outputOcrText = builder.outputOcrText;
+ this.maskingMethod = builder.maskingMethod;
+ }
+
+ /**
+ * @return a new builder
+ */
+ public static ImageBuilder builder() {
+ return new ImageBuilder();
+ }
+
+ /**
+ * @return Whether to return the processed image.
+ */
+ public Boolean getOutputProcessedImage() {
+ return outputProcessedImage;
+ }
+
+ /**
+ * @return Whether to return OCR text.
+ */
+ public Boolean getOutputOcrText() {
+ return outputOcrText;
+ }
+
+ /**
+ * @return Masking method for detected regions.
+ */
+ public MaskingMethod getMaskingMethod() {
+ return maskingMethod;
+ }
+
+ @Override
+ public String toString() {
+ return "Image{" +
+ "outputProcessedImage=" + outputProcessedImage +
+ ", outputOcrText=" + outputOcrText +
+ ", maskingMethod=" + maskingMethod +
+ '}';
+ }
+
+ public static final class ImageBuilder {
+ private Boolean outputProcessedImage;
+ private Boolean outputOcrText;
+ private MaskingMethod maskingMethod;
+
+ private ImageBuilder() {
+ }
+
+ /**
+ * @param outputProcessedImage Whether to return the processed image.
+ * @return this builder
+ */
+ public ImageBuilder outputProcessedImage(Boolean outputProcessedImage) {
+ this.outputProcessedImage = outputProcessedImage;
+ return this;
+ }
+
+ /**
+ * @param outputOcrText Whether to return OCR text.
+ * @return this builder
+ */
+ public ImageBuilder outputOcrText(Boolean outputOcrText) {
+ this.outputOcrText = outputOcrText;
+ return this;
+ }
+
+ /**
+ * @param maskingMethod Masking method for detected regions.
+ * @return this builder
+ */
+ public ImageBuilder maskingMethod(MaskingMethod maskingMethod) {
+ this.maskingMethod = maskingMethod;
+ return this;
+ }
+
+ public Image build() {
+ return new Image(this);
+ }
+ }
+}
diff --git a/common/src/main/java/com/skyflow/detect/MaskingMethod.java b/common/src/main/java/com/skyflow/detect/MaskingMethod.java
new file mode 100644
index 00000000..38402c52
--- /dev/null
+++ b/common/src/main/java/com/skyflow/detect/MaskingMethod.java
@@ -0,0 +1,10 @@
+package com.skyflow.detect;
+
+/**
+ * Masking method applied to detected regions in images.
+ */
+public enum MaskingMethod {
+ NONE,
+ BLUR,
+ BLACKBOX;
+}
diff --git a/common/src/main/java/com/skyflow/detect/Media.java b/common/src/main/java/com/skyflow/detect/Media.java
new file mode 100644
index 00000000..af6f24ac
--- /dev/null
+++ b/common/src/main/java/com/skyflow/detect/Media.java
@@ -0,0 +1,93 @@
+package com.skyflow.detect;
+
+/**
+ * Media-type specific processing options. File inputs only.
+ */
+public final class Media {
+ private final Audio audio;
+ private final Document document;
+ private final Image image;
+
+ private Media(MediaBuilder builder) {
+ this.audio = builder.audio;
+ this.document = builder.document;
+ this.image = builder.image;
+ }
+
+ /**
+ * @return a new builder
+ */
+ public static MediaBuilder builder() {
+ return new MediaBuilder();
+ }
+
+ /**
+ * @return Audio options.
+ */
+ public Audio getAudio() {
+ return audio;
+ }
+
+ /**
+ * @return Document options.
+ */
+ public Document getDocument() {
+ return document;
+ }
+
+ /**
+ * @return Image options.
+ */
+ public Image getImage() {
+ return image;
+ }
+
+ @Override
+ public String toString() {
+ return "Media{" +
+ "audio=" + audio +
+ ", document=" + document +
+ ", image=" + image +
+ '}';
+ }
+
+ public static final class MediaBuilder {
+ private Audio audio;
+ private Document document;
+ private Image image;
+
+ private MediaBuilder() {
+ }
+
+ /**
+ * @param audio Audio options.
+ * @return this builder
+ */
+ public MediaBuilder audio(Audio audio) {
+ this.audio = audio;
+ return this;
+ }
+
+ /**
+ * @param document Document options.
+ * @return this builder
+ */
+ public MediaBuilder document(Document document) {
+ this.document = document;
+ return this;
+ }
+
+ /**
+ * @param image Image options.
+ * @return this builder
+ */
+ public MediaBuilder image(Image image) {
+ this.image = image;
+ return this;
+ }
+
+ public Media build() {
+ return new Media(this);
+ }
+ }
+}
diff --git a/common/src/main/java/com/skyflow/detect/Metrics.java b/common/src/main/java/com/skyflow/detect/Metrics.java
new file mode 100644
index 00000000..46becb12
--- /dev/null
+++ b/common/src/main/java/com/skyflow/detect/Metrics.java
@@ -0,0 +1,76 @@
+package com.skyflow.detect;
+
+/**
+ * Processing metrics returned by Detect operations.
+ */
+public final class Metrics {
+ private final Double size;
+ private final Integer wordCount;
+ private final Integer characterCount;
+ private final Integer slides;
+ private final Integer pages;
+ private final Double duration;
+
+ public Metrics(Double size, Integer wordCount, Integer characterCount, Integer slides, Integer pages, Double duration) {
+ this.size = size;
+ this.wordCount = wordCount;
+ this.characterCount = characterCount;
+ this.slides = slides;
+ this.pages = pages;
+ this.duration = duration;
+ }
+
+ /**
+ * @return Input size in kilobytes.
+ */
+ public Double getSize() {
+ return size;
+ }
+
+ /**
+ * @return Number of words.
+ */
+ public Integer getWordCount() {
+ return wordCount;
+ }
+
+ /**
+ * @return Number of characters.
+ */
+ public Integer getCharacterCount() {
+ return characterCount;
+ }
+
+ /**
+ * @return Number of slides.
+ */
+ public Integer getSlides() {
+ return slides;
+ }
+
+ /**
+ * @return Number of pages.
+ */
+ public Integer getPages() {
+ return pages;
+ }
+
+ /**
+ * @return Media duration in seconds.
+ */
+ public Double getDuration() {
+ return duration;
+ }
+
+ @Override
+ public String toString() {
+ return "Metrics{" +
+ "size=" + size +
+ ", wordCount=" + wordCount +
+ ", characterCount=" + characterCount +
+ ", slides=" + slides +
+ ", pages=" + pages +
+ ", duration=" + duration +
+ '}';
+ }
+}
diff --git a/common/src/main/java/com/skyflow/detect/ObjectDeidentificationType.java b/common/src/main/java/com/skyflow/detect/ObjectDeidentificationType.java
new file mode 100644
index 00000000..13f3fd6e
--- /dev/null
+++ b/common/src/main/java/com/skyflow/detect/ObjectDeidentificationType.java
@@ -0,0 +1,10 @@
+package com.skyflow.detect;
+
+/**
+ * How a detected visual object is handled.
+ */
+public enum ObjectDeidentificationType {
+ UNKNOWN,
+ REDACT,
+ UNREDACT;
+}
diff --git a/common/src/main/java/com/skyflow/detect/ObjectEntity.java b/common/src/main/java/com/skyflow/detect/ObjectEntity.java
new file mode 100644
index 00000000..1f62853b
--- /dev/null
+++ b/common/src/main/java/com/skyflow/detect/ObjectEntity.java
@@ -0,0 +1,73 @@
+package com.skyflow.detect;
+
+/**
+ * Configures detection of a visual object type in images or video.
+ */
+public final class ObjectEntity {
+ private final ObjectEntityType entityType;
+ private final ObjectDeidentificationType deidentificationType;
+
+ private ObjectEntity(ObjectEntityBuilder builder) {
+ this.entityType = builder.entityType;
+ this.deidentificationType = builder.deidentificationType;
+ }
+
+ /**
+ * @return a new builder
+ */
+ public static ObjectEntityBuilder builder() {
+ return new ObjectEntityBuilder();
+ }
+
+ /**
+ * @return Object type this rule applies to.
+ */
+ public ObjectEntityType getEntityType() {
+ return entityType;
+ }
+
+ /**
+ * @return How matches are handled.
+ */
+ public ObjectDeidentificationType getDeidentificationType() {
+ return deidentificationType;
+ }
+
+ @Override
+ public String toString() {
+ return "ObjectEntity{" +
+ "entityType=" + entityType +
+ ", deidentificationType=" + deidentificationType +
+ '}';
+ }
+
+ public static final class ObjectEntityBuilder {
+ private ObjectEntityType entityType;
+ private ObjectDeidentificationType deidentificationType;
+
+ private ObjectEntityBuilder() {
+ }
+
+ /**
+ * @param entityType Object type this rule applies to.
+ * @return this builder
+ */
+ public ObjectEntityBuilder entityType(ObjectEntityType entityType) {
+ this.entityType = entityType;
+ return this;
+ }
+
+ /**
+ * @param deidentificationType How matches are handled.
+ * @return this builder
+ */
+ public ObjectEntityBuilder deidentificationType(ObjectDeidentificationType deidentificationType) {
+ this.deidentificationType = deidentificationType;
+ return this;
+ }
+
+ public ObjectEntity build() {
+ return new ObjectEntity(this);
+ }
+ }
+}
diff --git a/common/src/main/java/com/skyflow/detect/ObjectEntityType.java b/common/src/main/java/com/skyflow/detect/ObjectEntityType.java
new file mode 100644
index 00000000..679917c7
--- /dev/null
+++ b/common/src/main/java/com/skyflow/detect/ObjectEntityType.java
@@ -0,0 +1,13 @@
+package com.skyflow.detect;
+
+/**
+ * Visual objects Skyflow Detect can identify in images and video.
+ */
+public enum ObjectEntityType {
+ NONE,
+ FACE,
+ LICENSE_PLATE,
+ LOGO,
+ SIGNATURE,
+ ALL;
+}
diff --git a/common/src/main/java/com/skyflow/detect/OutputTranscriptionType.java b/common/src/main/java/com/skyflow/detect/OutputTranscriptionType.java
new file mode 100644
index 00000000..ed2638ed
--- /dev/null
+++ b/common/src/main/java/com/skyflow/detect/OutputTranscriptionType.java
@@ -0,0 +1,12 @@
+package com.skyflow.detect;
+
+/**
+ * Transcription output produced for audio inputs.
+ */
+public enum OutputTranscriptionType {
+ NONE,
+ TRANSCRIPTION,
+ MEDICAL_TRANSCRIPTION,
+ DIARIZED_TRANSCRIPTION,
+ MEDICAL_DIARIZED_TRANSCRIPTION;
+}
diff --git a/common/src/main/java/com/skyflow/detect/Pdf.java b/common/src/main/java/com/skyflow/detect/Pdf.java
new file mode 100644
index 00000000..d147d632
--- /dev/null
+++ b/common/src/main/java/com/skyflow/detect/Pdf.java
@@ -0,0 +1,93 @@
+package com.skyflow.detect;
+
+/**
+ * PDF processing options.
+ */
+public final class Pdf {
+ private final PdfProcessingMode processingMode;
+ private final Integer density;
+ private final Integer maxResolution;
+
+ private Pdf(PdfBuilder builder) {
+ this.processingMode = builder.processingMode;
+ this.density = builder.density;
+ this.maxResolution = builder.maxResolution;
+ }
+
+ /**
+ * @return a new builder
+ */
+ public static PdfBuilder builder() {
+ return new PdfBuilder();
+ }
+
+ /**
+ * @return Processing mode.
+ */
+ public PdfProcessingMode getProcessingMode() {
+ return processingMode;
+ }
+
+ /**
+ * @return Rendering density (DPI).
+ */
+ public Integer getDensity() {
+ return density;
+ }
+
+ /**
+ * @return Maximum rendering resolution.
+ */
+ public Integer getMaxResolution() {
+ return maxResolution;
+ }
+
+ @Override
+ public String toString() {
+ return "Pdf{" +
+ "processingMode=" + processingMode +
+ ", density=" + density +
+ ", maxResolution=" + maxResolution +
+ '}';
+ }
+
+ public static final class PdfBuilder {
+ private PdfProcessingMode processingMode;
+ private Integer density;
+ private Integer maxResolution;
+
+ private PdfBuilder() {
+ }
+
+ /**
+ * @param processingMode Processing mode.
+ * @return this builder
+ */
+ public PdfBuilder processingMode(PdfProcessingMode processingMode) {
+ this.processingMode = processingMode;
+ return this;
+ }
+
+ /**
+ * @param density Rendering density (DPI).
+ * @return this builder
+ */
+ public PdfBuilder density(Integer density) {
+ this.density = density;
+ return this;
+ }
+
+ /**
+ * @param maxResolution Maximum rendering resolution.
+ * @return this builder
+ */
+ public PdfBuilder maxResolution(Integer maxResolution) {
+ this.maxResolution = maxResolution;
+ return this;
+ }
+
+ public Pdf build() {
+ return new Pdf(this);
+ }
+ }
+}
diff --git a/common/src/main/java/com/skyflow/detect/PdfProcessingMode.java b/common/src/main/java/com/skyflow/detect/PdfProcessingMode.java
new file mode 100644
index 00000000..f32399ba
--- /dev/null
+++ b/common/src/main/java/com/skyflow/detect/PdfProcessingMode.java
@@ -0,0 +1,10 @@
+package com.skyflow.detect;
+
+/**
+ * How PDF documents are processed.
+ */
+public enum PdfProcessingMode {
+ NONE,
+ OCR,
+ TEXT_LAYER;
+}
diff --git a/common/src/main/java/com/skyflow/detect/PollOptions.java b/common/src/main/java/com/skyflow/detect/PollOptions.java
new file mode 100644
index 00000000..c1aa656a
--- /dev/null
+++ b/common/src/main/java/com/skyflow/detect/PollOptions.java
@@ -0,0 +1,91 @@
+package com.skyflow.detect;
+
+/**
+ * Opts {@code deidentifyFile} into submit-and-poll mode. When present, the SDK polls the run with
+ * exponential backoff (1, 2, 4, 8, 16, then 32 seconds) until it reaches a terminal status, the
+ * wait time is used up, or the attempt limit is hit. An empty {@code PollOptions.builder().build()}
+ * uses the defaults.
+ */
+public final class PollOptions {
+ public static final int DEFAULT_WAIT_TIME_SECONDS = 60;
+ public static final int MAX_WAIT_TIME_SECONDS = 300;
+ public static final int DEFAULT_MAX_ATTEMPTS = 23;
+ public static final int MAX_MAX_ATTEMPTS = 23;
+
+ private final Integer waitTime;
+ private final Integer maxAttempts;
+
+ private PollOptions(PollOptionsBuilder builder) {
+ this.waitTime = builder.waitTime;
+ this.maxAttempts = builder.maxAttempts;
+ }
+
+ /**
+ * @return a new builder
+ */
+ public static PollOptionsBuilder builder() {
+ return new PollOptionsBuilder();
+ }
+
+ /**
+ * @return Maximum total seconds to keep polling, or null for the default of 60. At most 300.
+ */
+ public Integer getWaitTime() {
+ return waitTime;
+ }
+
+ /**
+ * @return Maximum number of run lookups, or null for the default of 23. At most 23.
+ */
+ public Integer getMaxAttempts() {
+ return maxAttempts;
+ }
+
+ /** @return the wait time with the default applied */
+ public int effectiveWaitTime() {
+ return waitTime == null ? DEFAULT_WAIT_TIME_SECONDS : waitTime;
+ }
+
+ /** @return the attempt limit with the default applied */
+ public int effectiveMaxAttempts() {
+ return maxAttempts == null ? DEFAULT_MAX_ATTEMPTS : maxAttempts;
+ }
+
+ @Override
+ public String toString() {
+ return "PollOptions{" +
+ "waitTime=" + waitTime +
+ ", maxAttempts=" + maxAttempts +
+ '}';
+ }
+
+ public static final class PollOptionsBuilder {
+ private Integer waitTime;
+ private Integer maxAttempts;
+
+ private PollOptionsBuilder() {
+ }
+
+ /**
+ * @param waitTime Maximum total seconds to keep polling. 1 to 300; default 60.
+ * @return this builder
+ */
+ public PollOptionsBuilder waitTime(Integer waitTime) {
+ this.waitTime = waitTime;
+ return this;
+ }
+
+ /**
+ * @param maxAttempts Maximum number of run lookups. 1 to 23; default 23.
+ * @return this builder
+ */
+ public PollOptionsBuilder maxAttempts(Integer maxAttempts) {
+ this.maxAttempts = maxAttempts;
+ return this;
+ }
+
+ public PollOptions build() {
+ return new PollOptions(this);
+ }
+ }
+}
diff --git a/common/src/main/java/com/skyflow/detect/RedactionRule.java b/common/src/main/java/com/skyflow/detect/RedactionRule.java
new file mode 100644
index 00000000..19d20716
--- /dev/null
+++ b/common/src/main/java/com/skyflow/detect/RedactionRule.java
@@ -0,0 +1,26 @@
+package com.skyflow.detect;
+
+/**
+ * One re-identification rendering rule, the element of {@code redactionLevel} on {@code ReidentifyStringRequest}
+ * and {@code ReidentifyFileRequest}. Each SDK ships its own {@code com.skyflow.detect.RedactionLevel} with the
+ * pair of fields its vault type uses: skyvault names an {@code entityName} and a {@code redactionType}; flowvault
+ * names a {@code tokenGroupName} and a {@code redactionPattern}. Only those classes can extend this type.
+ */
+public abstract class RedactionRule {
+
+ RedactionRule() {
+ // subclasses live in this package, one per SDK
+ }
+
+ /** @return the wire {@code entityName}, or null when this SDK's rule does not carry one */
+ abstract String apiEntityName();
+
+ /** @return the wire {@code redactionType}, or null when this SDK's rule does not carry one */
+ abstract String apiRedactionType();
+
+ /** @return the wire {@code tokenGroupName}, or null when this SDK's rule does not carry one */
+ abstract String apiTokenGroupName();
+
+ /** @return the wire {@code redactionPattern}, or null when this SDK's rule does not carry one */
+ abstract String apiRedactionPattern();
+}
diff --git a/common/src/main/java/com/skyflow/detect/RedactionRules.java b/common/src/main/java/com/skyflow/detect/RedactionRules.java
new file mode 100644
index 00000000..9a9817d6
--- /dev/null
+++ b/common/src/main/java/com/skyflow/detect/RedactionRules.java
@@ -0,0 +1,36 @@
+package com.skyflow.detect;
+
+import com.skyflow.generated.common.rest.types.RedactionLevel;
+import com.skyflow.generated.common.rest.types.RedactionLevelEntityName;
+import com.skyflow.generated.common.rest.types.RedactionLevelRedactionType;
+
+/**
+ * Internal: turns an SDK {@link RedactionRule} into the API's {@code RedactionLevel}, which carries all four
+ * fields for every vault type. Not part of the public contract.
+ */
+public final class RedactionRules {
+
+ private RedactionRules() {
+ }
+
+ /**
+ * @param rule a rule built with this SDK's {@code RedactionLevel}
+ * @return the wire representation with only the fields the rule carries
+ */
+ public static RedactionLevel toApi(RedactionRule rule) {
+ RedactionLevel.Builder builder = RedactionLevel.builder();
+ if (rule.apiEntityName() != null) {
+ builder.entityName(RedactionLevelEntityName.valueOf(rule.apiEntityName()));
+ }
+ if (rule.apiRedactionType() != null) {
+ builder.redactionType(RedactionLevelRedactionType.valueOf(rule.apiRedactionType()));
+ }
+ if (rule.apiTokenGroupName() != null) {
+ builder.tokenGroupName(rule.apiTokenGroupName());
+ }
+ if (rule.apiRedactionPattern() != null) {
+ builder.redactionPattern(rule.apiRedactionPattern());
+ }
+ return builder.build();
+ }
+}
diff --git a/common/src/main/java/com/skyflow/detect/ReidentifyFileRequest.java b/common/src/main/java/com/skyflow/detect/ReidentifyFileRequest.java
new file mode 100644
index 00000000..82b1aff4
--- /dev/null
+++ b/common/src/main/java/com/skyflow/detect/ReidentifyFileRequest.java
@@ -0,0 +1,120 @@
+package com.skyflow.detect;
+
+import java.util.List;
+
+/**
+ * Request for {@code reidentifyFile}. Supply the file through this SDK's {@code ReidentifySourceType}
+ * ({@code BASE64} or {@code PRESIGNED_URL}; re-identification does not accept a skyflow id) and the matching
+ * {@code value}.
+ */
+public final class ReidentifyFileRequest {
+ private final ReidentifyFileSource dataSource;
+ private final String value;
+ private final FileDataFormat dataFormat;
+ private final List extends RedactionRule> redactionLevel;
+
+ private ReidentifyFileRequest(ReidentifyFileRequestBuilder builder) {
+ this.dataSource = builder.dataSource;
+ this.value = builder.value;
+ this.dataFormat = builder.dataFormat;
+ this.redactionLevel = builder.redactionLevel;
+ }
+
+ /**
+ * @return a new builder
+ */
+ public static ReidentifyFileRequestBuilder builder() {
+ return new ReidentifyFileRequestBuilder();
+ }
+
+ /**
+ * @return How {@code value} supplies the file: this SDK's {@code ReidentifySourceType} (skyvault and flowvault:
+ * BASE64, PRESIGNED_URL; a skyflow id is not offered for re-identification). Required.
+ */
+ public ReidentifyFileSource getDataSource() {
+ return dataSource;
+ }
+
+ /**
+ * @return Base64 content or presigned URL of the file, according to {@code dataSource}. Required.
+ */
+ public String getValue() {
+ return value;
+ }
+
+ /**
+ * @return Format of the file. Optional; the API infers it when omitted. Re-identification supports text formats
+ * such as TXT, CSV, JSON, JSONL, XML, DOCX, XLSX and PPTX.
+ */
+ public FileDataFormat getDataFormat() {
+ return dataFormat;
+ }
+
+ /**
+ * @return Optional per-group rendering rules. Built with this SDK's {@code RedactionLevel}.
+ */
+ public List extends RedactionRule> getRedactionLevel() {
+ return redactionLevel;
+ }
+
+ @Override
+ public String toString() {
+ return "ReidentifyFileRequest{" +
+ "dataSource=" + dataSource +
+ ", value=" + value +
+ ", dataFormat=" + dataFormat +
+ ", redactionLevel=" + redactionLevel +
+ '}';
+ }
+
+ public static final class ReidentifyFileRequestBuilder {
+ private ReidentifyFileSource dataSource;
+ private String value;
+ private FileDataFormat dataFormat;
+ private List extends RedactionRule> redactionLevel;
+
+ private ReidentifyFileRequestBuilder() {
+ }
+
+ /**
+ * @param dataSource How {@code value} supplies the file: this SDK's {@code ReidentifySourceType} (skyvault and
+ * flowvault: BASE64, PRESIGNED_URL; a skyflow id is not offered for re-identification). Required.
+ * @return this builder
+ */
+ public ReidentifyFileRequestBuilder dataSource(ReidentifyFileSource dataSource) {
+ this.dataSource = dataSource;
+ return this;
+ }
+
+ /**
+ * @param value Base64 content or presigned URL of the file, according to {@code dataSource}. Required.
+ * @return this builder
+ */
+ public ReidentifyFileRequestBuilder value(String value) {
+ this.value = value;
+ return this;
+ }
+
+ /**
+ * @param dataFormat Format of the file. Optional.
+ * @return this builder
+ */
+ public ReidentifyFileRequestBuilder dataFormat(FileDataFormat dataFormat) {
+ this.dataFormat = dataFormat;
+ return this;
+ }
+
+ /**
+ * @param redactionLevel Optional rendering rules, built with this SDK's {@code RedactionLevel}.
+ * @return this builder
+ */
+ public ReidentifyFileRequestBuilder redactionLevel(List extends RedactionRule> redactionLevel) {
+ this.redactionLevel = redactionLevel;
+ return this;
+ }
+
+ public ReidentifyFileRequest build() {
+ return new ReidentifyFileRequest(this);
+ }
+ }
+}
diff --git a/common/src/main/java/com/skyflow/detect/ReidentifyFileResponse.java b/common/src/main/java/com/skyflow/detect/ReidentifyFileResponse.java
new file mode 100644
index 00000000..50938fbb
--- /dev/null
+++ b/common/src/main/java/com/skyflow/detect/ReidentifyFileResponse.java
@@ -0,0 +1,59 @@
+package com.skyflow.detect;
+
+import java.util.List;
+
+/**
+ * Response of {@code reidentifyFile}. File re-identification is synchronous, so a {@code SUCCESS}
+ * status carries the output in the same response.
+ */
+public final class ReidentifyFileResponse {
+ private final DetectRunStatus status;
+ private final ReidentifyFileSource outputType;
+ private final List output;
+ private final Metrics metrics;
+
+ public ReidentifyFileResponse(DetectRunStatus status, ReidentifyFileSource outputType, List output, Metrics metrics) {
+ this.status = status;
+ this.outputType = outputType;
+ this.output = output;
+ this.metrics = metrics;
+ }
+
+ /**
+ * @return Processing status. UNKNOWN when the API did not report one.
+ */
+ public DetectRunStatus getStatus() {
+ return status;
+ }
+
+ /**
+ * @return How output files are delivered, or null when not reported. A constant of this SDK's {@code ReidentifySourceType}: {@code BASE64} or {@code PRESIGNED_URL}.
+ */
+ public ReidentifyFileSource getOutputType() {
+ return outputType;
+ }
+
+ /**
+ * @return Output artifacts. Empty when none were returned, never null.
+ */
+ public List getOutput() {
+ return output;
+ }
+
+ /**
+ * @return Processing metrics, or null when not reported.
+ */
+ public Metrics getMetrics() {
+ return metrics;
+ }
+
+ @Override
+ public String toString() {
+ return "ReidentifyFileResponse{" +
+ "status=" + status +
+ ", outputType=" + outputType +
+ ", output=" + output +
+ ", metrics=" + metrics +
+ '}';
+ }
+}
diff --git a/common/src/main/java/com/skyflow/detect/ReidentifyFileSource.java b/common/src/main/java/com/skyflow/detect/ReidentifyFileSource.java
new file mode 100644
index 00000000..d0f54ab3
--- /dev/null
+++ b/common/src/main/java/com/skyflow/detect/ReidentifyFileSource.java
@@ -0,0 +1,14 @@
+package com.skyflow.detect;
+
+/**
+ * How the file of {@code reidentifyFile} is supplied, and how its response reports the output. Each SDK ships
+ * its own {@code com.skyflow.detect.ReidentifySourceType} enum implementing this interface, with {@code BASE64}
+ * and {@code PRESIGNED_URL} in both SDKs. {@code getOutputType()} on {@code ReidentifyFileResponse} returns a
+ * constant of that same enum. The constant name is the wire value.
+ */
+public interface ReidentifyFileSource {
+ /**
+ * @return the wire value, which is the constant name
+ */
+ String name();
+}
diff --git a/common/src/main/java/com/skyflow/detect/ReidentifyStringRequest.java b/common/src/main/java/com/skyflow/detect/ReidentifyStringRequest.java
new file mode 100644
index 00000000..acabf2bb
--- /dev/null
+++ b/common/src/main/java/com/skyflow/detect/ReidentifyStringRequest.java
@@ -0,0 +1,75 @@
+package com.skyflow.detect;
+
+import java.util.List;
+
+/**
+ * Request for {@code reidentifyString}.
+ */
+public final class ReidentifyStringRequest {
+ private final String text;
+ private final List extends RedactionRule> redactionLevel;
+
+ private ReidentifyStringRequest(ReidentifyStringRequestBuilder builder) {
+ this.text = builder.text;
+ this.redactionLevel = builder.redactionLevel;
+ }
+
+ /**
+ * @return a new builder
+ */
+ public static ReidentifyStringRequestBuilder builder() {
+ return new ReidentifyStringRequestBuilder();
+ }
+
+ /**
+ * @return Text containing tokens to re-identify. Required.
+ */
+ public String getText() {
+ return text;
+ }
+
+ /**
+ * @return Optional per-group rendering rules. Built with this SDK's {@code RedactionLevel}.
+ */
+ public List extends RedactionRule> getRedactionLevel() {
+ return redactionLevel;
+ }
+
+ @Override
+ public String toString() {
+ return "ReidentifyStringRequest{" +
+ "text=" + text +
+ ", redactionLevel=" + redactionLevel +
+ '}';
+ }
+
+ public static final class ReidentifyStringRequestBuilder {
+ private String text;
+ private List extends RedactionRule> redactionLevel;
+
+ private ReidentifyStringRequestBuilder() {
+ }
+
+ /**
+ * @param text Text containing tokens to re-identify. Required.
+ * @return this builder
+ */
+ public ReidentifyStringRequestBuilder text(String text) {
+ this.text = text;
+ return this;
+ }
+
+ /**
+ * @param redactionLevel Optional rendering rules, built with this SDK's {@code RedactionLevel}.
+ * @return this builder
+ */
+ public ReidentifyStringRequestBuilder redactionLevel(List extends RedactionRule> redactionLevel) {
+ this.redactionLevel = redactionLevel;
+ return this;
+ }
+
+ public ReidentifyStringRequest build() {
+ return new ReidentifyStringRequest(this);
+ }
+ }
+}
diff --git a/common/src/main/java/com/skyflow/detect/ReidentifyStringResponse.java b/common/src/main/java/com/skyflow/detect/ReidentifyStringResponse.java
new file mode 100644
index 00000000..e1825bf2
--- /dev/null
+++ b/common/src/main/java/com/skyflow/detect/ReidentifyStringResponse.java
@@ -0,0 +1,36 @@
+package com.skyflow.detect;
+
+/**
+ * Response of {@code reidentifyString}.
+ */
+public final class ReidentifyStringResponse {
+ private final String processedText;
+ private final Metrics metrics;
+
+ public ReidentifyStringResponse(String processedText, Metrics metrics) {
+ this.processedText = processedText;
+ this.metrics = metrics;
+ }
+
+ /**
+ * @return Re-identified text.
+ */
+ public String getProcessedText() {
+ return processedText;
+ }
+
+ /**
+ * @return Processing metrics.
+ */
+ public Metrics getMetrics() {
+ return metrics;
+ }
+
+ @Override
+ public String toString() {
+ return "ReidentifyStringResponse{" +
+ "processedText=" + processedText +
+ ", metrics=" + metrics +
+ '}';
+ }
+}
diff --git a/common/src/main/java/com/skyflow/detect/ReturnEntitiesType.java b/common/src/main/java/com/skyflow/detect/ReturnEntitiesType.java
new file mode 100644
index 00000000..3ba4fa79
--- /dev/null
+++ b/common/src/main/java/com/skyflow/detect/ReturnEntitiesType.java
@@ -0,0 +1,10 @@
+package com.skyflow.detect;
+
+/**
+ * Controls which detected entities are returned in the response.
+ */
+public enum ReturnEntitiesType {
+ EXCLUDE_SENSITIVE_DATA,
+ ALL,
+ NONE;
+}
diff --git a/common/src/main/java/com/skyflow/detect/ShiftDates.java b/common/src/main/java/com/skyflow/detect/ShiftDates.java
new file mode 100644
index 00000000..fd4adc24
--- /dev/null
+++ b/common/src/main/java/com/skyflow/detect/ShiftDates.java
@@ -0,0 +1,73 @@
+package com.skyflow.detect;
+
+/**
+ * Shifts detected dates by a random number of days within the given range.
+ */
+public final class ShiftDates {
+ private final Integer minDays;
+ private final Integer maxDays;
+
+ private ShiftDates(ShiftDatesBuilder builder) {
+ this.minDays = builder.minDays;
+ this.maxDays = builder.maxDays;
+ }
+
+ /**
+ * @return a new builder
+ */
+ public static ShiftDatesBuilder builder() {
+ return new ShiftDatesBuilder();
+ }
+
+ /**
+ * @return Minimum number of days to shift.
+ */
+ public Integer getMinDays() {
+ return minDays;
+ }
+
+ /**
+ * @return Maximum number of days to shift.
+ */
+ public Integer getMaxDays() {
+ return maxDays;
+ }
+
+ @Override
+ public String toString() {
+ return "ShiftDates{" +
+ "minDays=" + minDays +
+ ", maxDays=" + maxDays +
+ '}';
+ }
+
+ public static final class ShiftDatesBuilder {
+ private Integer minDays;
+ private Integer maxDays;
+
+ private ShiftDatesBuilder() {
+ }
+
+ /**
+ * @param minDays Minimum number of days to shift.
+ * @return this builder
+ */
+ public ShiftDatesBuilder minDays(Integer minDays) {
+ this.minDays = minDays;
+ return this;
+ }
+
+ /**
+ * @param maxDays Maximum number of days to shift.
+ * @return this builder
+ */
+ public ShiftDatesBuilder maxDays(Integer maxDays) {
+ this.maxDays = maxDays;
+ return this;
+ }
+
+ public ShiftDates build() {
+ return new ShiftDates(this);
+ }
+ }
+}
diff --git a/common/src/main/java/com/skyflow/detect/Transformation.java b/common/src/main/java/com/skyflow/detect/Transformation.java
new file mode 100644
index 00000000..5fb9cb69
--- /dev/null
+++ b/common/src/main/java/com/skyflow/detect/Transformation.java
@@ -0,0 +1,53 @@
+package com.skyflow.detect;
+
+/**
+ * Transformations applied to detected entities before they are written to the output.
+ */
+public final class Transformation {
+ private final ShiftDates shiftDates;
+
+ private Transformation(TransformationBuilder builder) {
+ this.shiftDates = builder.shiftDates;
+ }
+
+ /**
+ * @return a new builder
+ */
+ public static TransformationBuilder builder() {
+ return new TransformationBuilder();
+ }
+
+ /**
+ * @return Date shifting configuration.
+ */
+ public ShiftDates getShiftDates() {
+ return shiftDates;
+ }
+
+ @Override
+ public String toString() {
+ return "Transformation{" +
+ "shiftDates=" + shiftDates +
+ '}';
+ }
+
+ public static final class TransformationBuilder {
+ private ShiftDates shiftDates;
+
+ private TransformationBuilder() {
+ }
+
+ /**
+ * @param shiftDates Date shifting configuration.
+ * @return this builder
+ */
+ public TransformationBuilder shiftDates(ShiftDates shiftDates) {
+ this.shiftDates = shiftDates;
+ return this;
+ }
+
+ public Transformation build() {
+ return new Transformation(this);
+ }
+ }
+}
diff --git a/common/src/main/java/com/skyflow/detect/internal/DeidentifyFileFlow.java b/common/src/main/java/com/skyflow/detect/internal/DeidentifyFileFlow.java
new file mode 100644
index 00000000..da64c9b2
--- /dev/null
+++ b/common/src/main/java/com/skyflow/detect/internal/DeidentifyFileFlow.java
@@ -0,0 +1,43 @@
+package com.skyflow.detect.internal;
+
+import java.io.File;
+import com.skyflow.detect.DeidentifyFileRequest;
+import com.skyflow.detect.DeidentifyFileResponse;
+import com.skyflow.detect.DetectRunStatus;
+import com.skyflow.detect.GetRunResponse;
+import com.skyflow.detect.polling.RunPoller;
+import com.skyflow.errors.SkyflowException;
+import com.skyflow.logs.InfoLogs;
+import com.skyflow.utils.BaseUtils;
+import com.skyflow.utils.logger.LogUtil;
+
+/**
+ * Everything {@code deidentifyFile} does after the submit call, shared by every SDK: decide whether to
+ * poll, poll, merge the run into the response, and write outputs for file-based requests. Each
+ * controller performs the submit itself and hands the run id here.
+ */
+public final class DeidentifyFileFlow {
+ private DeidentifyFileFlow() {
+ }
+
+ public static DeidentifyFileResponse complete(DeidentifyFileRequest request, String runId, RunPoller.RunFetcher fetcher)
+ throws SkyflowException {
+ return complete(request, runId, fetcher, Thread::sleep);
+ }
+
+ static DeidentifyFileResponse complete(DeidentifyFileRequest request, String runId, RunPoller.RunFetcher fetcher,
+ RunPoller.Sleeper sleeper) throws SkyflowException {
+ if (request.getPollOptions() == null || runId == null) {
+ LogUtil.printInfoLog(BaseUtils.parameterizedString(InfoLogs.DEIDENTIFY_FILE_RUN_SUBMITTED.getLog(), String.valueOf(runId)));
+ return DetectResponseMapper.submittedDeidentifyFileResponse(runId);
+ }
+ GetRunResponse run = RunPoller.poll(runId, request.getPollOptions(), fetcher, sleeper);
+ DeidentifyFileResponse response = DetectResponseMapper.toDeidentifyFileResponse(runId, run);
+ File localFile = DetectRequestMapper.localFile(request);
+ if (response.getStatus() == DetectRunStatus.SUCCESS && localFile != null) {
+ FileOutputWriter.write(response.getOutput(), response.getOutputType(), localFile.getName(),
+ request.getOutputDirectory());
+ }
+ return response;
+ }
+}
diff --git a/common/src/main/java/com/skyflow/detect/internal/DetectRequestMapper.java b/common/src/main/java/com/skyflow/detect/internal/DetectRequestMapper.java
new file mode 100644
index 00000000..9e2b42cf
--- /dev/null
+++ b/common/src/main/java/com/skyflow/detect/internal/DetectRequestMapper.java
@@ -0,0 +1,422 @@
+package com.skyflow.detect.internal;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.Base64;
+import java.util.List;
+
+import com.skyflow.detect.Audio;
+import com.skyflow.detect.Bleep;
+import com.skyflow.detect.CheckGuardrailsRequest;
+import com.skyflow.detect.CustomType;
+import com.skyflow.detect.DeidentifyFileRequest;
+import com.skyflow.detect.DeidentifyStringRequest;
+import com.skyflow.detect.FileDataFormat;
+import com.skyflow.detect.Detect;
+import com.skyflow.detect.DetectConfiguration;
+import com.skyflow.detect.Document;
+import com.skyflow.detect.Entity;
+import com.skyflow.detect.FileMapping;
+import com.skyflow.detect.Image;
+import com.skyflow.detect.Media;
+import com.skyflow.detect.ObjectEntity;
+import com.skyflow.detect.Pdf;
+import com.skyflow.detect.RedactionRule;
+import com.skyflow.detect.RedactionRules;
+import com.skyflow.detect.ReidentifyStringRequest;
+import com.skyflow.detect.ShiftDates;
+import com.skyflow.detect.Transformation;
+import com.skyflow.errors.BaseErrorMessage;
+import com.skyflow.errors.ErrorCode;
+import com.skyflow.errors.SkyflowException;
+import com.skyflow.generated.common.rest.resources.filesv2.requests.DeidentifyFileRequestV2;
+import com.skyflow.generated.common.rest.resources.filesv2.types.DeidentifyFileRequestV2DataFormat;
+import com.skyflow.generated.common.rest.resources.filesv2.types.DeidentifyFileRequestV2DataSource;
+import com.skyflow.generated.common.rest.resources.guardrailsv2.requests.DetectGuardrailsRequestV2;
+import com.skyflow.logs.ErrorLogs;
+import com.skyflow.utils.BaseUtils;
+import com.skyflow.utils.logger.LogUtil;
+import com.skyflow.generated.common.rest.resources.stringsv2.requests.DeidentifyStringRequestV2;
+import com.skyflow.generated.common.rest.resources.stringsv2.requests.ReidentifyStringRequestV2;
+import com.skyflow.generated.common.rest.types.AudioV2;
+import com.skyflow.generated.common.rest.types.AudioV2Bleep;
+import com.skyflow.generated.common.rest.types.AudioV2OutputTranscription;
+import com.skyflow.generated.common.rest.types.DetectConfigV2;
+import com.skyflow.generated.common.rest.types.DetectCustomTypes;
+import com.skyflow.generated.common.rest.types.DetectEntity;
+import com.skyflow.generated.common.rest.types.DetectEntityDeidentificationType;
+import com.skyflow.generated.common.rest.types.DetectEntityEntityType;
+import com.skyflow.generated.common.rest.types.DetectObjectEntity;
+import com.skyflow.generated.common.rest.types.DetectObjectEntityDeidentificationType;
+import com.skyflow.generated.common.rest.types.DetectObjectEntityEntityType;
+import com.skyflow.generated.common.rest.types.DetectReturnEntities;
+import com.skyflow.generated.common.rest.types.DocumentV2;
+import com.skyflow.generated.common.rest.types.DocumentV2Pdf;
+import com.skyflow.generated.common.rest.types.DocumentV2PdfProcessingMode;
+import com.skyflow.generated.common.rest.types.EntityTransformation;
+import com.skyflow.generated.common.rest.types.ImageV2;
+import com.skyflow.generated.common.rest.types.ImageV2MaskingMethod;
+import com.skyflow.generated.common.rest.types.TransformationShiftDates;
+
+/**
+ * Converts public SDK request models into generated V2 API requests. Internal to the SDK.
+ */
+public final class DetectRequestMapper {
+ private DetectRequestMapper() {
+ }
+
+ public static DeidentifyStringRequestV2 toDeidentifyStringRequest(DeidentifyStringRequest request, String vaultId) {
+ DeidentifyStringRequestV2._FinalStage builder = DeidentifyStringRequestV2.builder().text(request.getText());
+ if (request.getConfigurationId() != null) {
+ builder.configurationId(request.getConfigurationId());
+ }
+ if (sendsConfiguration(request.getConfigurationId(), request.getConfiguration())) {
+ builder.configuration(toDetectConfig(request.getConfiguration(), vaultId));
+ }
+ return builder.build();
+ }
+
+ /**
+ * The API needs either a configuration id or a configuration, and the vault id travels inside the
+ * configuration. An inline configuration is always sent; with neither field set the SDK still sends a
+ * configuration holding only the vault id, so the server applies the vault's defaults instead of
+ * rejecting the request. When only an id is set nothing else is sent.
+ */
+ static boolean sendsConfiguration(String configurationId, DetectConfiguration configuration) {
+ return configuration != null || configurationId == null;
+ }
+
+ /**
+ * Builds the submit request. For file-based requests this reads and base64-encodes the file and infers
+ * the format from its extension when none was given.
+ */
+ /**
+ * The local file a deidentifyFile request points at, from {@code file} or {@code filePath}, or null for a
+ * {@code value}-based request.
+ */
+ public static File localFile(DeidentifyFileRequest request) {
+ if (request.getFile() != null) {
+ return request.getFile();
+ }
+ String path = request.getFilePath();
+ return path == null || path.trim().isEmpty() ? null : new File(path);
+ }
+
+ public static DeidentifyFileRequestV2 toDeidentifyFileRequest(DeidentifyFileRequest request, String vaultId)
+ throws SkyflowException {
+ String value = request.getValue();
+ FileDataFormat format = request.getDataFormat();
+ File file = localFile(request);
+ if (file != null) {
+ value = encodeFile(file);
+ if (format == null) {
+ format = inferFormat(file.getName());
+ }
+ }
+ // A local file is always sent as BASE64, whatever dataSource the builder was left with.
+ DeidentifyFileRequestV2DataSource dataSource = file != null
+ ? DeidentifyFileRequestV2DataSource.BASE64
+ : DeidentifyFileRequestV2DataSource.valueOf(request.getDataSource().name());
+ DeidentifyFileRequestV2._FinalStage builder = DeidentifyFileRequestV2.builder()
+ .dataSource(dataSource)
+ .value(value);
+ if (format != null) {
+ // The wire value for a file format is the lower-case extension.
+ builder.dataFormat(DeidentifyFileRequestV2DataFormat.valueOf(format.name().toLowerCase()));
+ }
+ if (request.getConfigurationId() != null) {
+ builder.configurationId(request.getConfigurationId());
+ }
+ if (sendsConfiguration(request.getConfigurationId(), request.getConfiguration())) {
+ builder.configuration(toDetectConfig(request.getConfiguration(), vaultId));
+ }
+ return builder.build();
+ }
+
+ static String encodeFile(File file) throws SkyflowException {
+ try {
+ return Base64.getEncoder().encodeToString(Files.readAllBytes(file.toPath()));
+ } catch (IOException | OutOfMemoryError e) {
+ LogUtil.printErrorLog(BaseUtils.parameterizedString(ErrorLogs.FAILED_TO_ENCODE_FILE_IN_DEIDENTIFY_FILE.getLog(), "detect"));
+ throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), BaseErrorMessage.FailedToEncodeFile.getMessage());
+ }
+ }
+
+ /** @return the format matching the file extension, or null when unknown so the server infers it */
+ static FileDataFormat inferFormat(String fileName) {
+ int dot = fileName == null ? -1 : fileName.lastIndexOf('.');
+ if (dot < 0 || dot == fileName.length() - 1) {
+ return null;
+ }
+ try {
+ return FileDataFormat.valueOf(fileName.substring(dot + 1).toUpperCase());
+ } catch (IllegalArgumentException unknown) {
+ return null;
+ }
+ }
+
+ public static ReidentifyStringRequestV2 toReidentifyStringRequest(ReidentifyStringRequest request, String vaultId) {
+ ReidentifyStringRequestV2._FinalStage builder = ReidentifyStringRequestV2.builder()
+ .vaultId(vaultId)
+ .text(request.getText());
+ if (request.getRedactionLevel() != null) {
+ builder.redactionLevel(toRedactionLevels(request.getRedactionLevel()));
+ }
+ return builder.build();
+ }
+
+ public static DetectGuardrailsRequestV2 toCheckGuardrailsRequest(CheckGuardrailsRequest request, String vaultId) {
+ DetectGuardrailsRequestV2._FinalStage builder = DetectGuardrailsRequestV2.builder()
+ .text(request.getText())
+ .vaultId(vaultId);
+ if (request.getCheckToxicity() != null) {
+ builder.checkToxicity(request.getCheckToxicity());
+ }
+ if (request.getDenyTopics() != null) {
+ builder.denyTopics(request.getDenyTopics());
+ }
+ return builder.build();
+ }
+
+ /**
+ * @param configuration the inline configuration, or {@code null} to send a configuration that carries
+ * only the vault id
+ */
+ public static DetectConfigV2 toDetectConfig(DetectConfiguration configuration, String vaultId) {
+ DetectConfigV2._FinalStage builder = DetectConfigV2.builder().vaultId(vaultId);
+ if (configuration == null) {
+ return builder.build();
+ }
+ if (configuration.getName() != null) {
+ builder.name(configuration.getName());
+ }
+ if (configuration.getDescription() != null) {
+ builder.description(configuration.getDescription());
+ }
+ if (configuration.getDetect() != null) {
+ builder.detect(toDetect(configuration.getDetect()));
+ }
+ if (configuration.getFileMapping() != null) {
+ builder.fileMapping(toFileMappings(configuration.getFileMapping()));
+ }
+ if (configuration.getMedia() != null) {
+ builder.media(toMedia(configuration.getMedia()));
+ }
+ return builder.build();
+ }
+
+ static com.skyflow.generated.common.rest.types.Detect toDetect(Detect detect) {
+ com.skyflow.generated.common.rest.types.Detect.Builder builder =
+ com.skyflow.generated.common.rest.types.Detect.builder();
+ if (detect.getEntities() != null) {
+ List entities = new ArrayList<>();
+ for (Entity entity : detect.getEntities()) {
+ if (entity != null) {
+ entities.add(toEntity(entity));
+ }
+ }
+ builder.entities(entities);
+ }
+ if (detect.getObjectEntities() != null) {
+ List objectEntities = new ArrayList<>();
+ for (ObjectEntity objectEntity : detect.getObjectEntities()) {
+ if (objectEntity != null) {
+ objectEntities.add(toObjectEntity(objectEntity));
+ }
+ }
+ builder.objectEntities(objectEntities);
+ }
+ if (detect.getRestrict() != null) {
+ builder.restrict(detect.getRestrict());
+ }
+ if (detect.getSkip() != null) {
+ builder.skip(detect.getSkip());
+ }
+ if (detect.getCustomTypes() != null) {
+ List customTypes = new ArrayList<>();
+ for (CustomType customType : detect.getCustomTypes()) {
+ if (customType != null) {
+ customTypes.add(toCustomType(customType));
+ }
+ }
+ builder.customTypes(customTypes);
+ }
+ if (detect.getReturnEntities() != null) {
+ builder.returnEntities(DetectReturnEntities.valueOf(detect.getReturnEntities().name()));
+ }
+ return builder.build();
+ }
+
+ static DetectEntity toEntity(Entity entity) {
+ DetectEntity.Builder builder = DetectEntity.builder();
+ if (entity.getEntityType() != null) {
+ builder.entityType(DetectEntityEntityType.valueOf(entity.getEntityType().name()));
+ }
+ if (entity.getDeidentificationType() != null) {
+ builder.deidentificationType(DetectEntityDeidentificationType.valueOf(entity.getDeidentificationType().name()));
+ }
+ if (entity.getDestination() != null) {
+ builder.destination(entity.getDestination());
+ }
+ if (entity.getTransformation() != null) {
+ builder.transformation(toTransformation(entity.getTransformation()));
+ }
+ return builder.build();
+ }
+
+ static EntityTransformation toTransformation(Transformation transformation) {
+ EntityTransformation.Builder builder = EntityTransformation.builder();
+ ShiftDates shiftDates = transformation.getShiftDates();
+ if (shiftDates != null) {
+ TransformationShiftDates.Builder shift = TransformationShiftDates.builder();
+ if (shiftDates.getMinDays() != null) {
+ shift.minDays(shiftDates.getMinDays());
+ }
+ if (shiftDates.getMaxDays() != null) {
+ shift.maxDays(shiftDates.getMaxDays());
+ }
+ builder.shiftDates(shift.build());
+ }
+ return builder.build();
+ }
+
+ static DetectCustomTypes toCustomType(CustomType customType) {
+ DetectCustomTypes.Builder builder = DetectCustomTypes.builder();
+ if (customType.getLabel() != null) {
+ builder.label(customType.getLabel());
+ }
+ if (customType.getMatch() != null) {
+ builder.match(customType.getMatch());
+ }
+ return builder.build();
+ }
+
+ static DetectObjectEntity toObjectEntity(ObjectEntity objectEntity) {
+ DetectObjectEntity.Builder builder = DetectObjectEntity.builder();
+ if (objectEntity.getEntityType() != null) {
+ builder.entityType(DetectObjectEntityEntityType.valueOf(objectEntity.getEntityType().name()));
+ }
+ if (objectEntity.getDeidentificationType() != null) {
+ builder.deidentificationType(
+ DetectObjectEntityDeidentificationType.valueOf(objectEntity.getDeidentificationType().name()));
+ }
+ return builder.build();
+ }
+
+ static List toFileMappings(List fileMappings) {
+ List result = new ArrayList<>();
+ for (FileMapping mapping : fileMappings) {
+ if (mapping == null) {
+ continue;
+ }
+ com.skyflow.generated.common.rest.types.FileMapping.Builder builder =
+ com.skyflow.generated.common.rest.types.FileMapping.builder();
+ if (mapping.getSource() != null) {
+ builder.source(mapping.getSource());
+ }
+ if (mapping.getDestination() != null) {
+ builder.destination(mapping.getDestination());
+ }
+ if (mapping.getOutputFileNameSuffix() != null) {
+ builder.outputFileNameSuffix(mapping.getOutputFileNameSuffix());
+ }
+ if (mapping.getEntitiesDestination() != null) {
+ builder.entitiesDestination(mapping.getEntitiesDestination());
+ }
+ if (mapping.getObjectEntitiesDestination() != null) {
+ builder.objectEntitiesDestination(mapping.getObjectEntitiesDestination());
+ }
+ result.add(builder.build());
+ }
+ return result;
+ }
+
+ static com.skyflow.generated.common.rest.types.Media toMedia(Media media) {
+ com.skyflow.generated.common.rest.types.Media.Builder builder =
+ com.skyflow.generated.common.rest.types.Media.builder();
+ if (media.getAudio() != null) {
+ builder.audio(toAudio(media.getAudio()));
+ }
+ if (media.getDocument() != null) {
+ builder.document(toDocument(media.getDocument()));
+ }
+ if (media.getImage() != null) {
+ builder.image(toImage(media.getImage()));
+ }
+ return builder.build();
+ }
+
+ static AudioV2 toAudio(Audio audio) {
+ AudioV2.Builder builder = AudioV2.builder();
+ if (audio.getOutputProcessedAudio() != null) {
+ builder.outputProcessedAudio(audio.getOutputProcessedAudio());
+ }
+ if (audio.getOutputTranscription() != null) {
+ builder.outputTranscription(AudioV2OutputTranscription.valueOf(audio.getOutputTranscription().name()));
+ }
+ Bleep bleep = audio.getBleep();
+ if (bleep != null) {
+ AudioV2Bleep.Builder bleepBuilder = AudioV2Bleep.builder();
+ if (bleep.getStartPadding() != null) {
+ bleepBuilder.startPadding(bleep.getStartPadding());
+ }
+ if (bleep.getStopPadding() != null) {
+ bleepBuilder.stopPadding(bleep.getStopPadding());
+ }
+ if (bleep.getFrequency() != null) {
+ bleepBuilder.frequency(bleep.getFrequency());
+ }
+ if (bleep.getGain() != null) {
+ bleepBuilder.gain(bleep.getGain());
+ }
+ builder.bleep(bleepBuilder.build());
+ }
+ return builder.build();
+ }
+
+ static DocumentV2 toDocument(Document document) {
+ DocumentV2.Builder builder = DocumentV2.builder();
+ Pdf pdf = document.getPdf();
+ if (pdf != null) {
+ DocumentV2Pdf.Builder pdfBuilder = DocumentV2Pdf.builder();
+ if (pdf.getProcessingMode() != null) {
+ pdfBuilder.processingMode(DocumentV2PdfProcessingMode.valueOf(pdf.getProcessingMode().name()));
+ }
+ if (pdf.getDensity() != null) {
+ pdfBuilder.density(pdf.getDensity());
+ }
+ if (pdf.getMaxResolution() != null) {
+ pdfBuilder.maxResolution(pdf.getMaxResolution());
+ }
+ builder.pdf(pdfBuilder.build());
+ }
+ return builder.build();
+ }
+
+ static ImageV2 toImage(Image image) {
+ ImageV2.Builder builder = ImageV2.builder();
+ if (image.getOutputProcessedImage() != null) {
+ builder.outputProcessedImage(image.getOutputProcessedImage());
+ }
+ if (image.getOutputOcrText() != null) {
+ builder.outputOcrText(image.getOutputOcrText());
+ }
+ if (image.getMaskingMethod() != null) {
+ builder.maskingMethod(ImageV2MaskingMethod.valueOf(image.getMaskingMethod().name()));
+ }
+ return builder.build();
+ }
+
+ public static List toRedactionLevels(List extends RedactionRule> levels) {
+ List result = new ArrayList<>();
+ for (RedactionRule level : levels) {
+ if (level == null) {
+ continue;
+ }
+ result.add(RedactionRules.toApi(level));
+ }
+ return result;
+ }
+}
diff --git a/common/src/main/java/com/skyflow/detect/internal/DetectResponseMapper.java b/common/src/main/java/com/skyflow/detect/internal/DetectResponseMapper.java
new file mode 100644
index 00000000..44a9dba6
--- /dev/null
+++ b/common/src/main/java/com/skyflow/detect/internal/DetectResponseMapper.java
@@ -0,0 +1,151 @@
+package com.skyflow.detect.internal;
+
+import com.skyflow.detect.CheckGuardrailsResponse;
+import com.skyflow.detect.DeidentifyFileSource;
+import com.skyflow.detect.DeidentifyFileResponse;
+import com.skyflow.detect.DeidentifyStringResponse;
+import com.skyflow.detect.DetectRunStatus;
+import com.skyflow.detect.FileDataFormat;
+import com.skyflow.detect.FileOutput;
+import com.skyflow.detect.GetRunResponse;
+import com.skyflow.detect.GuardrailsValidation;
+import com.skyflow.detect.DetectedEntity;
+import com.skyflow.detect.EntityLocation;
+import com.skyflow.detect.Metrics;
+import com.skyflow.detect.ReidentifyStringResponse;
+import com.skyflow.generated.common.rest.types.DeidentifyStringResponseV2;
+import com.skyflow.generated.common.rest.types.DeidentifyStringResponseV2DetectedEntity;
+import com.skyflow.generated.common.rest.types.DeidentifyStringResponseV2EntityLocation;
+import com.skyflow.generated.common.rest.types.DetectGuardrailsResponseV2;
+import com.skyflow.generated.common.rest.types.DetectRunsResponseV2;
+import com.skyflow.generated.common.rest.types.ReidentifyStringResponseV2;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.function.Function;
+import java.util.Map;
+
+/**
+ * Converts generated V2 API responses into public SDK response models. Internal to the SDK.
+ */
+public final class DetectResponseMapper {
+ private DetectResponseMapper() {
+ }
+
+ public static DeidentifyStringResponse toDeidentifyStringResponse(DeidentifyStringResponseV2 response) {
+ List entities = new ArrayList<>();
+ List apiEntities = response.getEntities().orElse(null);
+ if (apiEntities != null) {
+ for (DeidentifyStringResponseV2DetectedEntity apiEntity : apiEntities) {
+ if (apiEntity != null) {
+ entities.add(toDetectedEntity(apiEntity));
+ }
+ }
+ }
+ return new DeidentifyStringResponse(
+ response.getProcessedText().orElse(null),
+ Collections.unmodifiableList(entities),
+ response.getMetrics().map(DetectResponseMapper::toMetrics).orElse(null));
+ }
+
+ public static ReidentifyStringResponse toReidentifyStringResponse(ReidentifyStringResponseV2 response) {
+ return new ReidentifyStringResponse(
+ response.getProcessedText().orElse(null),
+ response.getMetrics().map(DetectResponseMapper::toMetrics).orElse(null));
+ }
+
+ static DetectedEntity toDetectedEntity(DeidentifyStringResponseV2DetectedEntity apiEntity) {
+ Map scores = apiEntity.getEntityScores().orElse(null);
+ return new DetectedEntity(
+ apiEntity.getToken().orElse(null),
+ apiEntity.getValue().orElse(null),
+ apiEntity.getLocation().map(DetectResponseMapper::toEntityLocation).orElse(null),
+ apiEntity.getEntityType().orElse(null),
+ scores == null ? Collections.emptyMap() : Collections.unmodifiableMap(scores));
+ }
+
+ static EntityLocation toEntityLocation(DeidentifyStringResponseV2EntityLocation location) {
+ return new EntityLocation(
+ location.getStartIndex().orElse(null),
+ location.getEndIndex().orElse(null),
+ location.getStartIndexProcessed().orElse(null),
+ location.getEndIndexProcessed().orElse(null));
+ }
+
+ public static CheckGuardrailsResponse toCheckGuardrailsResponse(DetectGuardrailsResponseV2 response) {
+ return new CheckGuardrailsResponse(
+ response.getText(),
+ enumOrDefault(GuardrailsValidation.class,
+ response.getValidation() == null ? null : response.getValidation().toString(), GuardrailsValidation.UNKNOWN),
+ response.getToxic().orElse(null),
+ response.getDeniedTopic().orElse(null));
+ }
+
+ /**
+ * @param sourceResolver maps the wire outputType onto this SDK's {@code DeidentifySourceType}; returns null for an
+ * unknown value
+ */
+ public static GetRunResponse toGetRunResponse(String runId, DetectRunsResponseV2 response,
+ Function sourceResolver) {
+ List outputs = new ArrayList<>();
+ List apiOutputs = response.getOutput().orElse(null);
+ if (apiOutputs != null) {
+ for (com.skyflow.generated.common.rest.types.FileOutput apiOutput : apiOutputs) {
+ if (apiOutput != null) {
+ outputs.add(toFileOutput(apiOutput));
+ }
+ }
+ }
+ return new GetRunResponse(
+ runId,
+ response.getStatus().map(s -> enumOrDefault(DetectRunStatus.class, s.toString(), DetectRunStatus.UNKNOWN))
+ .orElse(DetectRunStatus.UNKNOWN),
+ response.getOutputType().map(t -> sourceResolver.apply(t.toString())).orElse(null),
+ Collections.unmodifiableList(outputs),
+ response.getMetrics().map(DetectResponseMapper::toMetrics).orElse(null),
+ response.getMessage().orElse(null));
+ }
+
+ /** Response for a submit-only call: run id and nothing else. */
+ public static DeidentifyFileResponse submittedDeidentifyFileResponse(String runId) {
+ return new DeidentifyFileResponse(runId, null, null, Collections.emptyList(), null, null);
+ }
+
+ /** Merges the submit's run id with the polled run. */
+ public static DeidentifyFileResponse toDeidentifyFileResponse(String runId, GetRunResponse run) {
+ return new DeidentifyFileResponse(runId, run.getStatus(), run.getOutputType(), run.getOutput(),
+ run.getMetrics(), run.getMessage());
+ }
+
+ public static FileOutput toFileOutput(com.skyflow.generated.common.rest.types.FileOutput apiOutput) {
+ return new FileOutput(
+ apiOutput.getProcessedFile().orElse(null),
+ apiOutput.getProcessedFileType().map(Object::toString).orElse(null),
+ apiOutput.getProcessedFileExtension()
+ .map(e -> enumOrDefault(FileDataFormat.class, e.toString().toUpperCase(), null))
+ .orElse(null));
+ }
+
+ /** Maps a wire value onto a public enum, tolerating values this SDK version does not know. */
+ static > E enumOrDefault(Class type, String value, E fallback) {
+ if (value == null) {
+ return fallback;
+ }
+ try {
+ return Enum.valueOf(type, value);
+ } catch (IllegalArgumentException unknown) {
+ return fallback;
+ }
+ }
+
+ public static Metrics toMetrics(com.skyflow.generated.common.rest.types.Metrics metrics) {
+ return new Metrics(
+ metrics.getSize().orElse(null),
+ metrics.getWordCount().orElse(null),
+ metrics.getCharacterCount().orElse(null),
+ metrics.getSlides().orElse(null),
+ metrics.getPages().orElse(null),
+ metrics.getDuration().orElse(null));
+ }
+}
diff --git a/common/src/main/java/com/skyflow/detect/internal/DetectValidations.java b/common/src/main/java/com/skyflow/detect/internal/DetectValidations.java
new file mode 100644
index 00000000..db3345fb
--- /dev/null
+++ b/common/src/main/java/com/skyflow/detect/internal/DetectValidations.java
@@ -0,0 +1,125 @@
+package com.skyflow.detect.internal;
+
+import com.skyflow.detect.CheckGuardrailsRequest;
+import com.skyflow.detect.DeidentifyFileRequest;
+import com.skyflow.detect.DeidentifyStringRequest;
+import com.skyflow.detect.PollOptions;
+import com.skyflow.detect.GetRunRequest;
+import com.skyflow.detect.ReidentifyStringRequest;
+import com.skyflow.errors.BaseErrorMessage;
+import com.skyflow.errors.ErrorCode;
+import com.skyflow.errors.SkyflowException;
+import com.skyflow.logs.ErrorLogs;
+import com.skyflow.utils.BaseUtils;
+import com.skyflow.utils.logger.LogUtil;
+
+import java.io.File;
+
+
+/**
+ * Client-side validation for Detect V2 requests. Internal to the SDK.
+ */
+public final class DetectValidations {
+ static final String INTERFACE_NAME = "detect";
+
+ private DetectValidations() {
+ }
+
+ public static void validateDeidentifyStringRequest(DeidentifyStringRequest request) throws SkyflowException {
+ if (request == null) {
+ throw invalid(ErrorLogs.DEIDENTIFY_STRING_REQUEST_NULL, BaseErrorMessage.DeidentifyStringRequestNull);
+ }
+ if (isBlank(request.getText())) {
+ throw invalid(ErrorLogs.INVALID_TEXT_IN_DEIDENTIFY_STRING, BaseErrorMessage.InvalidTextInDeidentifyString);
+ }
+ // configurationId and configuration are both optional on the API and are passed through as given;
+ // with neither set the mapper sends a configuration carrying only the vault id.
+ }
+
+ public static void validateDeidentifyFileRequest(DeidentifyFileRequest request) throws SkyflowException {
+ if (request == null) {
+ throw invalid(ErrorLogs.DEIDENTIFY_FILE_REQUEST_NULL, BaseErrorMessage.DeidentifyFileRequestNull);
+ }
+ // The file comes from exactly one of filePath, file or value; dataSource belongs to value only.
+ int sources = (request.getFilePath() != null ? 1 : 0) + (request.getFile() != null ? 1 : 0)
+ + (request.getValue() != null ? 1 : 0);
+ if (sources == 0) {
+ throw invalid(ErrorLogs.MISSING_FILE_SOURCE_IN_DEIDENTIFY_FILE, BaseErrorMessage.MissingFileSourceInDeidentifyFile);
+ }
+ if (sources > 1) {
+ throw invalid(ErrorLogs.MULTIPLE_FILE_SOURCES_IN_DEIDENTIFY_FILE, BaseErrorMessage.MultipleFileSourcesInDeidentifyFile);
+ }
+ if (request.getValue() != null) {
+ if (request.getDataSource() == null) {
+ throw invalid(ErrorLogs.INVALID_DATA_SOURCE_IN_DEIDENTIFY_FILE, BaseErrorMessage.InvalidDataSourceInDeidentifyFile);
+ }
+ if (isBlank(request.getValue())) {
+ throw invalid(ErrorLogs.INVALID_VALUE_IN_DEIDENTIFY_FILE, BaseErrorMessage.InvalidValueInDeidentifyFile);
+ }
+ } else {
+ File file = DetectRequestMapper.localFile(request);
+ if (file == null || !file.isFile()) {
+ throw invalid(ErrorLogs.FILE_NOT_FOUND_IN_DEIDENTIFY_FILE, BaseErrorMessage.FileNotFoundToDeidentify);
+ }
+ }
+ // configurationId and configuration are both optional on the API and are passed through as given;
+ // with neither set the mapper sends a configuration carrying only the vault id.
+ validatePollOptions(request.getPollOptions());
+ if (request.getPollOptions() == null && !isBlank(request.getOutputDirectory())) {
+ throw invalid(ErrorLogs.OUTPUT_DIRECTORY_WITHOUT_POLL_OPTIONS, BaseErrorMessage.OutputDirectoryWithoutPollOptions);
+ }
+ }
+
+ static void validatePollOptions(PollOptions options) throws SkyflowException {
+ if (options == null) {
+ return;
+ }
+ Integer waitTime = options.getWaitTime();
+ if (waitTime != null && (waitTime < 1 || waitTime > PollOptions.MAX_WAIT_TIME_SECONDS)) {
+ throw invalid(ErrorLogs.INVALID_WAIT_TIME_IN_POLL_OPTIONS, BaseErrorMessage.InvalidWaitTimeInPollOptions);
+ }
+ Integer maxAttempts = options.getMaxAttempts();
+ if (maxAttempts != null && (maxAttempts < 1 || maxAttempts > PollOptions.MAX_MAX_ATTEMPTS)) {
+ throw invalid(ErrorLogs.INVALID_MAX_ATTEMPTS_IN_POLL_OPTIONS, BaseErrorMessage.InvalidMaxAttemptsInPollOptions);
+ }
+ }
+
+ public static void validateReidentifyStringRequest(ReidentifyStringRequest request) throws SkyflowException {
+ if (request == null) {
+ throw invalid(ErrorLogs.REIDENTIFY_STRING_REQUEST_NULL, BaseErrorMessage.ReidentifyStringRequestNull);
+ }
+ if (isBlank(request.getText())) {
+ throw invalid(ErrorLogs.INVALID_TEXT_IN_REIDENTIFY_STRING, BaseErrorMessage.InvalidTextInReidentifyString);
+ }
+ // redactionLevel entries are optional on the API and are passed through as given.
+ }
+
+ public static void validateGetRunRequest(GetRunRequest request) throws SkyflowException {
+ if (request == null) {
+ throw invalid(ErrorLogs.GET_RUN_REQUEST_NULL, BaseErrorMessage.GetRunRequestNull);
+ }
+ if (isBlank(request.getRunId())) {
+ throw invalid(ErrorLogs.INVALID_RUN_ID_IN_GET_RUN, BaseErrorMessage.InvalidRunIdInGetRun);
+ }
+ }
+
+ public static void validateCheckGuardrailsRequest(CheckGuardrailsRequest request) throws SkyflowException {
+ if (request == null) {
+ throw invalid(ErrorLogs.CHECK_GUARDRAILS_REQUEST_NULL, BaseErrorMessage.CheckGuardrailsRequestNull);
+ }
+ if (isBlank(request.getText())) {
+ throw invalid(ErrorLogs.INVALID_TEXT_IN_CHECK_GUARDRAILS, BaseErrorMessage.InvalidTextInCheckGuardrails);
+ }
+ // checkToxicity and denyTopics are optional on the API and are passed through as given.
+ }
+
+
+ static boolean isBlank(String value) {
+ return value == null || value.trim().isEmpty();
+ }
+
+ private static SkyflowException invalid(ErrorLogs log, BaseErrorMessage message) {
+ LogUtil.printErrorLog(BaseUtils.parameterizedString(log.getLog(), INTERFACE_NAME));
+ return new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), message.getMessage());
+ }
+}
diff --git a/common/src/main/java/com/skyflow/detect/internal/FileOutputWriter.java b/common/src/main/java/com/skyflow/detect/internal/FileOutputWriter.java
new file mode 100644
index 00000000..73261728
--- /dev/null
+++ b/common/src/main/java/com/skyflow/detect/internal/FileOutputWriter.java
@@ -0,0 +1,118 @@
+package com.skyflow.detect.internal;
+
+import com.skyflow.detect.DeidentifyFileSource;
+import com.skyflow.detect.FileOutput;
+import com.skyflow.errors.BaseErrorMessage;
+import com.skyflow.errors.SkyflowException;
+import com.skyflow.logs.ErrorLogs;
+import com.skyflow.logs.InfoLogs;
+import com.skyflow.utils.BaseConstants;
+import com.skyflow.utils.BaseUtils;
+import com.skyflow.utils.logger.LogUtil;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.Base64;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Writes the base64 outputs of a successful file run next to, or into a chosen directory for, the
+ * local file that was submitted. Internal to the SDK.
+ *
+ *
Each output becomes {@code processed-.}. Entity outputs carry their
+ * type in the name so they never collide with a processed file of the same extension: ENTITIES
+ * becomes {@code processed-entities-.json} and OBJECT_ENTITIES becomes
+ * {@code processed-object-entities-.json}. If two outputs would still share a name
+ * the file type is added before the extension. Presigned-URL outputs are not fetched and nothing
+ * is written for them.
+ */
+public final class FileOutputWriter {
+ private static final String ENTITIES_TYPE = "ENTITIES";
+
+ private FileOutputWriter() {
+ }
+
+ /**
+ * @return the files written, in output order; empty when the output type is not BASE64
+ * @throws SkyflowException if the directory cannot be created or a file cannot be decoded or written
+ */
+ public static List write(List outputs, DeidentifyFileSource outputType, String inputFileName,
+ String outputDirectory) throws SkyflowException {
+ List written = new ArrayList<>();
+ if (outputs == null || outputs.isEmpty()) {
+ return written;
+ }
+ if (outputType == null || !"BASE64".equals(outputType.name())) {
+ LogUtil.printInfoLog(BaseUtils.parameterizedString(InfoLogs.OUTPUT_NOT_WRITTEN_FOR_OUTPUT_TYPE.getLog(),
+ String.valueOf(outputType)));
+ return written;
+ }
+ File directory = outputDirectory == null || outputDirectory.trim().isEmpty() ? null : new File(outputDirectory);
+ if (directory != null && !directory.isDirectory() && !directory.mkdirs()) {
+ throw writeFailure(ErrorLogs.OUTPUT_DIRECTORY_NOT_CREATED, directory.getPath(), null);
+ }
+ String base = stripExtension(inputFileName);
+ Set used = new HashSet<>();
+ for (FileOutput output : outputs) {
+ if (output == null || output.getProcessedFile() == null) {
+ continue;
+ }
+ String name = fileName(base, output, used);
+ File target = directory == null ? new File(name) : new File(directory, name);
+ try {
+ byte[] bytes = Base64.getDecoder().decode(output.getProcessedFile());
+ Files.write(target.toPath(), bytes);
+ } catch (IllegalArgumentException | IOException e) {
+ throw writeFailure(ErrorLogs.OUTPUT_FILE_NOT_WRITTEN, target.getPath(), e);
+ }
+ LogUtil.printInfoLog(BaseUtils.parameterizedString(InfoLogs.OUTPUT_FILE_WRITTEN.getLog(), target.getPath()));
+ written.add(target);
+ }
+ return written;
+ }
+
+ /**
+ * @param base the input file name without its extension
+ * @return {@code processed-.}, or {@code processed--.json} for entity outputs
+ */
+ static String fileName(String base, FileOutput output, Set used) {
+ String type = output.getProcessedFileType() == null ? "" : output.getProcessedFileType();
+ boolean entities = type.toUpperCase().contains(ENTITIES_TYPE);
+ String extension;
+ if (output.getProcessedFileExtension() != null) {
+ extension = output.getProcessedFileExtension().name().toLowerCase();
+ } else if (entities) {
+ extension = "json";
+ } else {
+ extension = "bin";
+ }
+ // ENTITIES -> processed-entities-, OBJECT_ENTITIES -> processed-object-entities-
+ String stem = entities
+ ? BaseConstants.PROCESSED_FILE_NAME_PREFIX + type.toLowerCase().replace('_', '-') + "-" + base
+ : BaseConstants.PROCESSED_FILE_NAME_PREFIX + base;
+ String name = stem + "." + extension;
+ if (!used.add(name)) {
+ name = stem + "." + (type.isEmpty() ? String.valueOf(used.size()) : type.toLowerCase()) + "." + extension;
+ used.add(name);
+ }
+ return name;
+ }
+
+ static String stripExtension(String fileName) {
+ if (fileName == null || fileName.isEmpty()) {
+ return "output";
+ }
+ int dot = fileName.lastIndexOf('.');
+ return dot > 0 ? fileName.substring(0, dot) : fileName;
+ }
+
+ private static SkyflowException writeFailure(ErrorLogs log, String path, Exception cause) {
+ LogUtil.printErrorLog(BaseUtils.parameterizedString(log.getLog(), path));
+ String message = BaseUtils.parameterizedString(BaseErrorMessage.FailedToWriteOutputFile.getMessage(), path);
+ return cause == null ? new SkyflowException(message) : new SkyflowException(message, cause);
+ }
+}
diff --git a/common/src/main/java/com/skyflow/detect/internal/ReidentifyFileMapper.java b/common/src/main/java/com/skyflow/detect/internal/ReidentifyFileMapper.java
new file mode 100644
index 00000000..73448a3a
--- /dev/null
+++ b/common/src/main/java/com/skyflow/detect/internal/ReidentifyFileMapper.java
@@ -0,0 +1,75 @@
+package com.skyflow.detect.internal;
+
+import com.skyflow.detect.ReidentifyFileSource;
+import com.skyflow.detect.DetectRunStatus;
+import com.skyflow.detect.FileOutput;
+import com.skyflow.detect.ReidentifyFileRequest;
+import com.skyflow.detect.ReidentifyFileResponse;
+import com.skyflow.generated.common.rest.resources.filesv2.requests.ReidentifyFileRequestV2;
+import com.skyflow.generated.common.rest.resources.filesv2.types.ReidentifyFileRequestV2DataFormat;
+import com.skyflow.generated.common.rest.resources.filesv2.types.ReidentifyFileRequestV2DataSource;
+import com.skyflow.generated.common.rest.types.ReidentifyFileResponseV2;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.function.Function;
+
+/**
+ * Converts the flowvault {@code reidentifyFile} models to and from the generated V2 API types.
+ * Internal to the SDK.
+ */
+public final class ReidentifyFileMapper {
+ private ReidentifyFileMapper() {
+ }
+
+ public static ReidentifyFileRequestV2 toApiRequest(ReidentifyFileRequest request, String vaultId) {
+ ReidentifyFileRequestV2._FinalStage builder = ReidentifyFileRequestV2.builder()
+ .dataSource(ReidentifyFileRequestV2DataSource.valueOf(request.getDataSource().name()))
+ .value(request.getValue())
+ .vaultId(vaultId);
+ if (request.getDataFormat() != null) {
+ // The wire value for a file format is the lower-case extension.
+ builder.dataFormat(ReidentifyFileRequestV2DataFormat.valueOf(request.getDataFormat().name().toLowerCase()));
+ }
+ if (request.getRedactionLevel() != null) {
+ builder.redactionLevel(DetectRequestMapper.toRedactionLevels(request.getRedactionLevel()));
+ }
+ return builder.build();
+ }
+
+ /**
+ * @param sourceResolver maps the wire outputType onto this SDK's {@code ReidentifySourceType}; returns null for an
+ * unknown value
+ */
+ public static ReidentifyFileResponse toResponse(ReidentifyFileResponseV2 response,
+ Function sourceResolver) {
+ List outputs = new ArrayList<>();
+ List apiOutputs = response.getOutput().orElse(null);
+ if (apiOutputs != null) {
+ for (com.skyflow.generated.common.rest.types.FileOutput apiOutput : apiOutputs) {
+ if (apiOutput != null) {
+ outputs.add(DetectResponseMapper.toFileOutput(apiOutput));
+ }
+ }
+ }
+ return new ReidentifyFileResponse(
+ response.getStatus().map(s -> enumOrDefault(DetectRunStatus.class, s.toString(), DetectRunStatus.UNKNOWN))
+ .orElse(DetectRunStatus.UNKNOWN),
+ response.getOutputType().map(t -> sourceResolver.apply(t.toString())).orElse(null),
+ Collections.unmodifiableList(outputs),
+ response.getMetrics().map(DetectResponseMapper::toMetrics).orElse(null));
+ }
+
+ /** Maps a wire value onto a public enum, tolerating values this SDK version does not know. */
+ private static > E enumOrDefault(Class type, String value, E fallback) {
+ if (value == null) {
+ return fallback;
+ }
+ try {
+ return Enum.valueOf(type, value);
+ } catch (IllegalArgumentException unknown) {
+ return fallback;
+ }
+ }
+}
diff --git a/common/src/main/java/com/skyflow/detect/internal/ReidentifyFileValidations.java b/common/src/main/java/com/skyflow/detect/internal/ReidentifyFileValidations.java
new file mode 100644
index 00000000..46106c96
--- /dev/null
+++ b/common/src/main/java/com/skyflow/detect/internal/ReidentifyFileValidations.java
@@ -0,0 +1,43 @@
+package com.skyflow.detect.internal;
+
+import com.skyflow.detect.ReidentifyFileRequest;
+import com.skyflow.errors.BaseErrorMessage;
+import com.skyflow.errors.ErrorCode;
+import com.skyflow.errors.SkyflowException;
+import com.skyflow.logs.ErrorLogs;
+import com.skyflow.utils.BaseUtils;
+import com.skyflow.utils.logger.LogUtil;
+
+
+/**
+ * Client-side validation for the flowvault {@code reidentifyFile} request. Internal to the SDK.
+ */
+public final class ReidentifyFileValidations {
+ private static final String INTERFACE_NAME = "detect";
+
+ private ReidentifyFileValidations() {
+ }
+
+ public static void validateReidentifyFileRequest(ReidentifyFileRequest request) throws SkyflowException {
+ if (request == null) {
+ throw invalid(ErrorLogs.REIDENTIFY_FILE_REQUEST_NULL, BaseErrorMessage.ReidentifyFileRequestNull);
+ }
+ if (request.getDataSource() == null) {
+ throw invalid(ErrorLogs.INVALID_DATA_SOURCE_IN_REIDENTIFY_FILE, BaseErrorMessage.InvalidDataSourceInReidentifyFile);
+ }
+ if (isBlank(request.getValue())) {
+ throw invalid(ErrorLogs.INVALID_VALUE_IN_REIDENTIFY_FILE, BaseErrorMessage.InvalidValueInReidentifyFile);
+ }
+ // redactionLevel entries are optional on the API and are passed through as given.
+ }
+
+
+ private static boolean isBlank(String value) {
+ return value == null || value.trim().isEmpty();
+ }
+
+ private static SkyflowException invalid(ErrorLogs log, BaseErrorMessage message) {
+ LogUtil.printErrorLog(BaseUtils.parameterizedString(log.getLog(), INTERFACE_NAME));
+ return new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), message.getMessage());
+ }
+}
diff --git a/common/src/main/java/com/skyflow/detect/polling/RunPoller.java b/common/src/main/java/com/skyflow/detect/polling/RunPoller.java
new file mode 100644
index 00000000..4aff5a31
--- /dev/null
+++ b/common/src/main/java/com/skyflow/detect/polling/RunPoller.java
@@ -0,0 +1,99 @@
+package com.skyflow.detect.polling;
+
+import com.skyflow.detect.DetectRunStatus;
+import com.skyflow.detect.FileOutput;
+import com.skyflow.detect.GetRunResponse;
+import com.skyflow.detect.PollOptions;
+import com.skyflow.errors.SkyflowException;
+import com.skyflow.logs.InfoLogs;
+import com.skyflow.utils.BaseUtils;
+import com.skyflow.utils.logger.LogUtil;
+
+import java.util.Collections;
+
+/**
+ * Polls a Detect file run until it reaches a terminal status or the {@link PollOptions} budget is used
+ * up. Shared by every SDK: the caller supplies how a run is fetched, so each controller plugs in its
+ * own {@code getRun}.
+ *
+ *
Backoff is exponential, 1, 2, 4, 8, 16 then 32 seconds between lookups, with the last sleep
+ * trimmed so the total never exceeds {@code waitTime}. The first lookup happens immediately after the
+ * submit. SUCCESS, FAILED and UNKNOWN are terminal; every other status keeps polling.
+ */
+public final class RunPoller {
+ /** Longest single pause between two lookups, in seconds. */
+ public static final long MAX_DELAY_SECONDS = 32L;
+
+ /** Fetches the current state of a run. */
+ public interface RunFetcher {
+ GetRunResponse fetch(String runId) throws SkyflowException;
+ }
+
+ /** Pauses the calling thread. Replaceable in tests. */
+ public interface Sleeper {
+ void sleep(long millis) throws InterruptedException;
+ }
+
+ private RunPoller() {
+ }
+
+ /**
+ * Polls on the calling thread.
+ *
+ * @param runId run to poll
+ * @param options wait time and attempt limit, defaults applied
+ * @param fetcher how to look the run up
+ * @return the terminal run, or the last non-terminal run seen when the budget ran out or the thread was interrupted
+ * @throws SkyflowException if a lookup fails
+ */
+ public static GetRunResponse poll(String runId, PollOptions options, RunFetcher fetcher) throws SkyflowException {
+ return poll(runId, options, fetcher, Thread::sleep);
+ }
+
+ public static GetRunResponse poll(String runId, PollOptions options, RunFetcher fetcher, Sleeper sleeper)
+ throws SkyflowException {
+ int waitTime = options.effectiveWaitTime();
+ int maxAttempts = options.effectiveMaxAttempts();
+ LogUtil.printInfoLog(BaseUtils.parameterizedString(InfoLogs.POLL_RUN_STARTED.getLog(), runId,
+ String.valueOf(waitTime), String.valueOf(maxAttempts)));
+
+ long elapsedSeconds = 0;
+ long delaySeconds = 1;
+ int attempts = 0;
+ while (true) {
+ GetRunResponse run = fetcher.fetch(runId);
+ attempts++;
+ if (run == null || run.getStatus() == null) {
+ // A fetcher that reports nothing is treated as an unknown, terminal state.
+ run = new GetRunResponse(runId, DetectRunStatus.UNKNOWN, null, Collections.emptyList(), null, null);
+ }
+ switch (run.getStatus()) {
+ case SUCCESS:
+ case FAILED:
+ case UNKNOWN:
+ LogUtil.printInfoLog(BaseUtils.parameterizedString(InfoLogs.POLL_RUN_TERMINAL.getLog(), runId,
+ run.getStatus().name(), String.valueOf(attempts)));
+ return run;
+ default:
+ // QUEUED, IN_PROGRESS: keep polling while the budget allows.
+ break;
+ }
+ if (attempts >= maxAttempts || elapsedSeconds >= waitTime) {
+ LogUtil.printInfoLog(BaseUtils.parameterizedString(InfoLogs.POLL_RUN_BUDGET_EXHAUSTED.getLog(), runId,
+ run.getStatus().name(), String.valueOf(attempts), String.valueOf(elapsedSeconds)));
+ return run;
+ }
+ long sleepSeconds = Math.min(delaySeconds, waitTime - elapsedSeconds);
+ try {
+ sleeper.sleep(sleepSeconds * 1000L);
+ } catch (InterruptedException interrupted) {
+ Thread.currentThread().interrupt();
+ LogUtil.printInfoLog(BaseUtils.parameterizedString(InfoLogs.POLL_RUN_INTERRUPTED.getLog(), runId,
+ run.getStatus().name()));
+ return run;
+ }
+ elapsedSeconds += sleepSeconds;
+ delaySeconds = Math.min(delaySeconds * 2, MAX_DELAY_SECONDS);
+ }
+ }
+}
diff --git a/common/src/main/java/com/skyflow/enums/RedactionType.java b/common/src/main/java/com/skyflow/enums/RedactionType.java
new file mode 100644
index 00000000..c6feaa68
--- /dev/null
+++ b/common/src/main/java/com/skyflow/enums/RedactionType.java
@@ -0,0 +1,21 @@
+package com.skyflow.enums;
+
+/**
+ * How a stored value is rendered when it is read back. Shared by the skyvault vault operations
+ * ({@code get} and {@code detokenize}) and by Detect re-identification, where a
+ * {@code RedactionLevel} applies it to one entity type.
+ */
+public enum RedactionType {
+ PLAIN_TEXT,
+ MASKED,
+ DEFAULT,
+ REDACTED;
+
+ /**
+ * @return the wire value, which is the constant name
+ */
+ @Override
+ public String toString() {
+ return name();
+ }
+}
diff --git a/common/src/main/java/com/skyflow/errors/ErrorMessage.java b/common/src/main/java/com/skyflow/errors/BaseErrorMessage.java
similarity index 72%
rename from common/src/main/java/com/skyflow/errors/ErrorMessage.java
rename to common/src/main/java/com/skyflow/errors/BaseErrorMessage.java
index 1e408cca..b3eb34c7 100644
--- a/common/src/main/java/com/skyflow/errors/ErrorMessage.java
+++ b/common/src/main/java/com/skyflow/errors/BaseErrorMessage.java
@@ -2,7 +2,12 @@
import com.skyflow.utils.SdkVersion;
-public enum ErrorMessage {
+/**
+ * Validation and client-side error messages shared by every SDK. Named {@code BaseErrorMessage}
+ * rather than {@code ErrorMessage} so it can never be shadowed by a module's own
+ * {@code com.skyflow.errors.ErrorMessage}: code in common must reference this enum.
+ */
+public enum BaseErrorMessage {
// Client initialization
VaultIdAlreadyInConfigList("%s0 Validation error. VaultId is present in an existing config. Specify a new vaultId in config."),
VaultIdNotInConfigList("%s0 Validation error. VaultId is missing from the config. Specify the vaultIds from configs."),
@@ -12,18 +17,11 @@ public enum ErrorMessage {
ConnectionIdNotInConfigList("%s0 Validation error. ConnectionId is missing from the config. Specify the connectionIds from configs."),
EmptyCredentials("%s0 Validation error. Invalid credentials. Credentials must not be empty."),
NullCredentials("%s0 Validation error. Credentials object is null. Specify a valid Credentials object."),
- TableSpecifiedInRequestAndRecordObject("%s0 Validation error. Table name cannot be specified at both the request and record levels. Please specify the table name in only one place."),
- UpsertTableRequestAtRecordLevel("%s0 Validation error. Table name should be present at each record level when upsert is present at record level."),
- UpsertTableRequestAtRequestLevel("%s0 Validation error. Upsert should be present at each record level when table name is present at record level."),
- TableNotSpecifiedInRequestAndRecordObject("%s0 Validation error. Table name is missing. Table name should be specified at one place either at the request level or record level. Please specify the table name at one place."),
// Vault config
InvalidVaultId("%s0 Initialization failed. Invalid vault ID. Specify a valid vault ID."),
EmptyVaultId("%s0 Initialization failed. Invalid vault ID. Vault ID must not be empty."),
InvalidClusterId("%s0 Initialization failed. Invalid cluster ID. Specify cluster ID."),
EmptyClusterId("%s0 Initialization failed. Invalid cluster ID. Specify a valid cluster ID."),
- EmptyVaultUrl("%s0 Initialization failed. Vault URL is empty. Specify a valid vault URL."),
- InvalidVaultUrlFormat("%s0 Initialization failed. Vault URL must start with 'https://'."),
- EitherVaultUrlOrClusterIdRequired("%s0 Initialization failed. Specify either 'clusterId' or 'vaultURL'."),
// Connection config
InvalidConnectionId("%s0 Initialization failed. Invalid connection ID. Specify a valid connection ID."),
@@ -69,20 +67,11 @@ public enum ErrorMessage {
TableKeyError("%s0 Validation error. 'table' key is missing from the payload. Specify a 'table' key."),
EmptyTable("%s0 Validation error. 'table' can't be empty. Specify a table."),
ValuesKeyError("%s0 Validation error. 'values' key is missing from the payload. Specify a 'values' key."),
- EmptyRecords("%s0 Validation error. 'records' can't be empty. Specify records."),
- EmptyKeyInRecords("%s0 Validation error. Invalid key in data in records. Specify a valid key."),
- EmptyValueInRecords("%s0 Validation error. Invalid value in records. Specify a valid value."),
- RecordsKeyError("%s0 Validation error. 'records' key is missing from the payload. Specify a 'records' key."),
- EmptyValues("%s0 Validation error. 'values' can't be empty. Specify values."),
EmptyKeyInValues("%s0 Validation error. Invalid key in values. Specify a valid key."),
- EmptyValueInValues("%s0 Validation error. Invalid value in values. Specify a valid value."),
TokensKeyError("%s0 Validation error. 'tokens' key is missing from the payload. Specify a 'tokens' key."),
EmptyTokens("%s0 Validation error. The 'tokens' field is empty. Specify tokens for one or more fields."),
EmptyKeyInTokens("%s0 Validation error. Invalid key tokens. Specify a valid key."),
- EmptyValueInTokens("%s0 Validation error. Invalid value in tokens. Specify a valid value."),
EmptyUpsert("%s0 Validation error. 'upsert' key can't be empty. Specify an upsert column."),
- InvalidUpsertUpdateType("%s0 Validation error. Invalid upsert updateType. Specify either 'UPDATE' or 'REPLACE'."),
- EmptyUpsertValues("%s0 Validation error. Upsert column values can't be empty. Specify at least one upsert column."),
HomogenousNotSupportedWithUpsert("%s0 Validation error. 'homogenous' is not supported with 'upsert'. Specify either 'homogenous' or 'upsert'."),
TokensPassedForTokenModeDisable("%s0 Validation error. 'tokenMode' wasn't specified. Set 'tokenMode' to 'ENABLE' to insert tokens."),
NoTokensWithTokenMode("%s0 Validation error. Tokens weren't specified for records while 'tokenMode' was %s1. Specify tokens."),
@@ -90,22 +79,15 @@ public enum ErrorMessage {
InsufficientTokensPassedForTokenModeEnableStrict("%s0 Validation error. 'tokenMode' is set to 'ENABLE_STRICT', but some fields are missing tokens. Specify tokens for all fields."),
BatchInsertPartialSuccess("%s0 Insert operation completed with partial success."),
BatchInsertFailure("%s0 Insert operation failed."),
- RecordSizeExceedError("%s0 Maximum number of records exceeded. The limit is 100000."),
// Detokenize
InvalidDetokenizeData("%s0 Validation error. Invalid detokenize data. Specify valid detokenize data."),
EmptyDetokenizeData("%s0 Validation error. Invalid data tokens. Specify at least one data token."),
EmptyTokenInDetokenizeData("%s0 Validation error. Invalid data tokens. Specify a valid data token."),
- TokensSizeExceedError("%s0 Maximum number of tokens exceeded. The limit is 100000."),
// Delete
DeleteRequestNull("%s0 Validation error. DeleteRequest object is null. Specify a valid DeleteRequest object."),
- // Delete Tokens
- DeleteTokensRequestNull("%s0 Validation error. DeleteTokensRequest object is null. Specify a valid DeleteTokensRequest object."),
- EmptyDeleteTokensData("%s0 Validation error. Tokens list is empty. Specify at least one token to delete."),
- EmptyTokenInDeleteTokensData("%s0 Validation error. Invalid token in delete tokens request. Specify a valid token."),
- DeleteTokensSizeExceedError("%s0 Maximum number of tokens exceeded. The limit is 100000."),
// Get
GetRequestNull("%s0 Validation error. GetRequest object is null. Specify a valid GetRequest object."),
@@ -126,15 +108,6 @@ public enum ErrorMessage {
ColumnValuesKeyErrorGet("%s0 Validation error. 'columnValues' aren't specified whereas 'columnName' is specified. Either add 'columnValues' or remove 'columnName'."),
EmptyColumnValues("%s0 Validation error. 'columnValues' can't be empty. Specify at least one column value"),
EmptyValueInColumnValues("%s0 Validation error. Invalid value in column values. Specify a valid column value."),
- IdsOrUniqueValuesKeyError("%s0 Validation error. 'ids' or 'uniqueValues' key is missing from the payload. Specify ids or uniqueValues in payload."),
- BothIdsAndUniqueValuesSpecified("%s0 Validation error. Both Skyflow IDs and unique values can't be specified. Either specify Skyflow IDs or unique values."),
- EmptyUniqueValues("%s0 Validation error. 'uniqueValues' can't be empty. Specify at least one unique value."),
- EmptyUniqueValueInUniqueValues("%s0 Validation error. Invalid unique value in 'uniqueValues'. Specify a valid unique value."),
- NullColumnRedactions("%s0 Validation error. Column redaction object can not be null. Specify a valid column redaction object."),
- NullColumnNameInColumnRedaction("%s0 Validation error. Column name can not be null or empty in column redaction. Specify a valid column name."),
- NullRedactionInColumnRedaction("%s0 Validation error. Redaction can not be null or empty in column redaction. Specify a valid redaction."),
- BothSingleTableFieldsAndRecordsSpecified("%s0 Validation error. Both single-table lookup fields ('table', 'ids', 'fields', 'uniqueValues', 'columnRedactions') and 'records' can't be specified. Either specify single-table fields or 'records'."),
- NullGetRecordRequest("%s0 Validation error. Record in 'records' is null. Specify a valid record."),
TokenKeyError("%s0 Validation error. 'token' key is missing from the payload. Specify a 'token' key."),
PartialSuccess("%s0 Validation error. Check 'SkyflowError.data' for details."),
@@ -146,9 +119,6 @@ public enum ErrorMessage {
InvalidSkyflowIdType("%s0 Validation error. Invalid type for 'skyflow_id' in data payload. Specify 'skyflow_id' as a string."),
EmptySkyflowId("%s0 Validation error. 'skyflow_id' can't be empty. Specify a skyflow id."),
UpdateRequestNull("%s0 Validation error. UpdateRequest object is null. Specify a valid UpdateRequest object."),
- UpdateRecordNull("%s0 Validation error. UpdateRequestRecord object in the list is null. Specify a valid UpdateRequestRecord object."),
- RecordSkyflowIdKeyError("%s0 Validation error. 'skyflowId' key is missing from the record. Specify a 'skyflowId' key."),
- EmptySkyflowIdInRecord("%s0 Validation error. 'skyflowId' can't be empty in the record. Specify a valid skyflow ID."),
// Query
QueryRequestNull("%s0 Validation error. QueryRequest object is null. Specify a valid QueryRequest object."),
@@ -159,15 +129,6 @@ public enum ErrorMessage {
ColumnValuesKeyErrorTokenize("%s0 Validation error. 'columnValues' key is missing from the payload. Specify a 'columnValues' key."),
EmptyColumnGroupInColumnValue("%s0 Validation error. Invalid column group in column value. Specify a valid column group."),
TokenizeRequestNull("%s0 Validation error. TokenizeRequest object is null. Specify a valid TokenizeRequest object."),
- EmptyTokenizeData("%s0 Validation error. Tokenize data is empty. Specify at least one tokenize record."),
- TokenizeRecordNull("%s0 Validation error. TokenizeRecord in the list is null. Specify a valid TokenizeRecord object."),
- InvalidBulkTokenizeRecordType("%s0 Validation error. Record in the list must be of type BulkTokenizeRequestRecord. Specify a valid BulkTokenizeRequestRecord object."),
- EmptyValueInTokenizeRecord("%s0 Validation error. Value in TokenizeRecord is null or empty. Specify a valid value."),
- EmptyTokenGroupNamesInTokenizeRecord("%s0 Validation error. TokenGroupNames in TokenizeRecord is null or empty. Specify at least one token group name."),
- EmptyTokenGroupNameInTokenizeRecord("%s0 Validation error. Token group name in TokenizeRecord is null or empty. Specify a valid token group name."),
- TokenizeDataSizeExceedError("%s0 Maximum number of tokenize records exceeded. The limit is 100000."),
- MissingIndexInBulkTokenizeRecord("%s0 Validation error. Index in BulkTokenizeRequestRecord is null. Specify an index for every record."),
- DuplicateIndexInBulkTokenizeRecord("%s0 Validation error. Duplicate index in BulkTokenizeRequestRecord. Specify a unique index for every record."),
// Connection
InvalidRequestHeaders("%s0 Validation error. Request headers aren't valid. Specify valid request headers."),
@@ -215,17 +176,34 @@ public enum ErrorMessage {
DetokenizeRequestNull("%s0 Validation error. DetokenizeRequest object is null. Specify a valid DetokenizeRequest object."),
- NullTokenGroupRedactions("%s0 Validation error. TokenGroupRedaction in the list is null. Specify a valid TokenGroupRedactions object."),
- NullRedactionInTokenGroup("%s0 Validation error. Redaction in TokenGroupRedactions is null or empty. Specify a valid redaction."),
- NullTokenGroupNameInTokenGroup("%s0 Validation error. TokenGroupName in TokenGroupRedactions is null or empty. Specify a valid tokenGroupName."),
- InvalidRecord("%s0 Validation error. InsertRecord object in the list is invalid. Specify a valid InsertRecord object."),
+ // Detect
+ DeidentifyStringRequestNull("%s0 Validation error. DeidentifyString request cannot be null."),
+ InvalidTextInDeidentifyString("%s0 Validation error. Invalid text in deidentify string request. Specify a non-empty text."),
+ ReidentifyStringRequestNull("%s0 Validation error. ReidentifyString request cannot be null."),
+ InvalidTextInReidentifyString("%s0 Validation error. Invalid text in reidentify string request. Specify a non-empty text."),
+ DeidentifyFileRequestNull("%s0 Validation error. DeidentifyFile request cannot be null."),
+ InvalidDataSourceInDeidentifyFile("%s0 Validation error. Invalid dataSource in deidentify file request. Specify a DeidentifySourceType."),
+ InvalidValueInDeidentifyFile("%s0 Validation error. Invalid value in deidentify file request. Specify the non-empty content or reference that dataSource describes."),
+ MultipleFileSourcesInDeidentifyFile("%s0 Validation error. Specify only one of filePath, file or value in deidentify file request."),
+ MissingFileSourceInDeidentifyFile("%s0 Validation error. Specify one of filePath, file or value in deidentify file request."),
+ InvalidWaitTimeInPollOptions("%s0 Validation error. waitTime in pollOptions must be between 1 and 300 seconds."),
+ InvalidMaxAttemptsInPollOptions("%s0 Validation error. maxAttempts in pollOptions must be between 1 and 23."),
+ OutputDirectoryWithoutPollOptions("%s0 Validation error. outputDirectory in deidentify file request requires pollOptions."),
+ FailedToWriteOutputFile("%s0 Failed to write the processed output to %s1."),
+ GetRunRequestNull("%s0 Validation error. GetRun request cannot be null."),
+ ReidentifyFileRequestNull("%s0 Validation error. ReidentifyFile request cannot be null."),
+ InvalidDataSourceInReidentifyFile("%s0 Validation error. Invalid dataSource in reidentify file request. Specify a ReidentifySourceType."),
+ InvalidValueInReidentifyFile("%s0 Validation error. Invalid value in reidentify file request. Specify the non-empty base64 content or presigned URL of the file."),
+ InvalidRunIdInGetRun("%s0 Validation error. Invalid runId in get run request. Specify a non-empty run id."),
+ CheckGuardrailsRequestNull("%s0 Validation error. CheckGuardrails request cannot be null."),
+ InvalidTextInCheckGuardrails("%s0 Validation error. Invalid text in check guardrails request. Specify a non-empty text."),
;
private final String message;
- ErrorMessage(String message) {
+ BaseErrorMessage(String message) {
this.message = message;
}
diff --git a/common/src/main/java/com/skyflow/errors/SkyflowException.java b/common/src/main/java/com/skyflow/errors/SkyflowException.java
index 2b043f92..f8c595ba 100644
--- a/common/src/main/java/com/skyflow/errors/SkyflowException.java
+++ b/common/src/main/java/com/skyflow/errors/SkyflowException.java
@@ -89,7 +89,7 @@ public SkyflowException(int httpCode, Throwable cause, Map>
} catch (Exception e) {
this.httpStatus = HttpStatus.BAD_REQUEST.getHttpStatus();
String fullMessage = responseBody != null ? responseBody :
- (cause.getLocalizedMessage() != null ? cause.getMessage() : ErrorMessage.ErrorOccurred.getMessage());
+ (cause.getLocalizedMessage() != null ? cause.getMessage() : BaseErrorMessage.ErrorOccurred.getMessage());
this.message = fullMessage.split("HTTP response code:")[0].trim();
}
}
diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/ApiClient.java b/common/src/main/java/com/skyflow/generated/auth/rest/ApiClient.java
deleted file mode 100644
index a1dd3aae..00000000
--- a/common/src/main/java/com/skyflow/generated/auth/rest/ApiClient.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/**
- * This file was auto-generated by Fern from our API Definition.
- */
-package com.skyflow.generated.auth.rest;
-
-import com.skyflow.generated.auth.rest.core.ClientOptions;
-import com.skyflow.generated.auth.rest.core.Suppliers;
-import com.skyflow.generated.auth.rest.resources.authentication.AuthenticationClient;
-
-import java.util.function.Supplier;
-
-public class ApiClient {
- protected final ClientOptions clientOptions;
-
- protected final Supplier authenticationClient;
-
- public ApiClient(ClientOptions clientOptions) {
- this.clientOptions = clientOptions;
- this.authenticationClient = Suppliers.memoize(() -> new AuthenticationClient(clientOptions));
- }
-
- public AuthenticationClient authentication() {
- return this.authenticationClient.get();
- }
-
- public static ApiClientBuilder builder() {
- return new ApiClientBuilder();
- }
-}
diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/ApiClientBuilder.java b/common/src/main/java/com/skyflow/generated/auth/rest/ApiClientBuilder.java
deleted file mode 100644
index aed3ed24..00000000
--- a/common/src/main/java/com/skyflow/generated/auth/rest/ApiClientBuilder.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/**
- * This file was auto-generated by Fern from our API Definition.
- */
-package com.skyflow.generated.auth.rest;
-
-import com.skyflow.generated.auth.rest.core.ClientOptions;
-import com.skyflow.generated.auth.rest.core.Environment;
-import okhttp3.OkHttpClient;
-
-public final class ApiClientBuilder {
- private ClientOptions.Builder clientOptionsBuilder = ClientOptions.builder();
-
- private String token = null;
-
- private Environment environment = Environment.PRODUCTION;
-
- /**
- * Sets token
- */
- public ApiClientBuilder token(String token) {
- this.token = token;
- return this;
- }
-
- public ApiClientBuilder environment(Environment environment) {
- this.environment = environment;
- return this;
- }
-
- public ApiClientBuilder url(String url) {
- this.environment = Environment.custom(url);
- return this;
- }
-
- /**
- * Sets the timeout (in seconds) for the client. Defaults to 60 seconds.
- */
- public ApiClientBuilder timeout(int timeout) {
- this.clientOptionsBuilder.timeout(timeout);
- return this;
- }
-
- /**
- * Sets the maximum number of retries for the client. Defaults to 2 retries.
- */
- public ApiClientBuilder maxRetries(int maxRetries) {
- this.clientOptionsBuilder.maxRetries(maxRetries);
- return this;
- }
-
- /**
- * Sets the underlying OkHttp client
- */
- public ApiClientBuilder httpClient(OkHttpClient httpClient) {
- this.clientOptionsBuilder.httpClient(httpClient);
- return this;
- }
-
- public ApiClient build() {
- if (token == null) {
- throw new RuntimeException("Please provide token");
- }
- this.clientOptionsBuilder.addHeader("Authorization", "Bearer " + this.token);
- clientOptionsBuilder.environment(this.environment);
- return new ApiClient(clientOptionsBuilder.build());
- }
-}
diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/AsyncApiClient.java b/common/src/main/java/com/skyflow/generated/auth/rest/AsyncApiClient.java
deleted file mode 100644
index 748eb02e..00000000
--- a/common/src/main/java/com/skyflow/generated/auth/rest/AsyncApiClient.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/**
- * This file was auto-generated by Fern from our API Definition.
- */
-package com.skyflow.generated.auth.rest;
-
-import com.skyflow.generated.auth.rest.core.ClientOptions;
-import com.skyflow.generated.auth.rest.core.Suppliers;
-import com.skyflow.generated.auth.rest.resources.authentication.AsyncAuthenticationClient;
-
-import java.util.function.Supplier;
-
-public class AsyncApiClient {
- protected final ClientOptions clientOptions;
-
- protected final Supplier authenticationClient;
-
- public AsyncApiClient(ClientOptions clientOptions) {
- this.clientOptions = clientOptions;
- this.authenticationClient = Suppliers.memoize(() -> new AsyncAuthenticationClient(clientOptions));
- }
-
- public AsyncAuthenticationClient authentication() {
- return this.authenticationClient.get();
- }
-
- public static AsyncApiClientBuilder builder() {
- return new AsyncApiClientBuilder();
- }
-}
diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/AsyncApiClientBuilder.java b/common/src/main/java/com/skyflow/generated/auth/rest/AsyncApiClientBuilder.java
deleted file mode 100644
index 2e30d45a..00000000
--- a/common/src/main/java/com/skyflow/generated/auth/rest/AsyncApiClientBuilder.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/**
- * This file was auto-generated by Fern from our API Definition.
- */
-package com.skyflow.generated.auth.rest;
-
-import com.skyflow.generated.auth.rest.core.ClientOptions;
-import com.skyflow.generated.auth.rest.core.Environment;
-import okhttp3.OkHttpClient;
-
-public final class AsyncApiClientBuilder {
- private ClientOptions.Builder clientOptionsBuilder = ClientOptions.builder();
-
- private String token = null;
-
- private Environment environment = Environment.PRODUCTION;
-
- /**
- * Sets token
- */
- public AsyncApiClientBuilder token(String token) {
- this.token = token;
- return this;
- }
-
- public AsyncApiClientBuilder environment(Environment environment) {
- this.environment = environment;
- return this;
- }
-
- public AsyncApiClientBuilder url(String url) {
- this.environment = Environment.custom(url);
- return this;
- }
-
- /**
- * Sets the timeout (in seconds) for the client. Defaults to 60 seconds.
- */
- public AsyncApiClientBuilder timeout(int timeout) {
- this.clientOptionsBuilder.timeout(timeout);
- return this;
- }
-
- /**
- * Sets the maximum number of retries for the client. Defaults to 2 retries.
- */
- public AsyncApiClientBuilder maxRetries(int maxRetries) {
- this.clientOptionsBuilder.maxRetries(maxRetries);
- return this;
- }
-
- /**
- * Sets the underlying OkHttp client
- */
- public AsyncApiClientBuilder httpClient(OkHttpClient httpClient) {
- this.clientOptionsBuilder.httpClient(httpClient);
- return this;
- }
-
- public AsyncApiClient build() {
- if (token == null) {
- throw new RuntimeException("Please provide token");
- }
- this.clientOptionsBuilder.addHeader("Authorization", "Bearer " + this.token);
- clientOptionsBuilder.environment(this.environment);
- return new AsyncApiClient(clientOptionsBuilder.build());
- }
-}
diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/core/ClientOptions.java b/common/src/main/java/com/skyflow/generated/auth/rest/core/ClientOptions.java
deleted file mode 100644
index 4eee6b92..00000000
--- a/common/src/main/java/com/skyflow/generated/auth/rest/core/ClientOptions.java
+++ /dev/null
@@ -1,171 +0,0 @@
-/**
- * This file was auto-generated by Fern from our API Definition.
- */
-package com.skyflow.generated.auth.rest.core;
-
-import okhttp3.OkHttpClient;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Optional;
-import java.util.concurrent.TimeUnit;
-import java.util.function.Supplier;
-
-public final class ClientOptions {
- private final Environment environment;
-
- private final Map headers;
-
- private final Map> headerSuppliers;
-
- private final OkHttpClient httpClient;
-
- private final int timeout;
-
- private ClientOptions(
- Environment environment,
- Map headers,
- Map> headerSuppliers,
- OkHttpClient httpClient,
- int timeout) {
- this.environment = environment;
- this.headers = new HashMap<>();
- this.headers.putAll(headers);
- this.headers.putAll(new HashMap() {
- {
- put("X-Fern-Language", "JAVA");
- put("X-Fern-SDK-Name", "com.skyflow.generated.rest.fern:api-sdk");
- put("X-Fern-SDK-Version", "0.0.279");
- }
- });
- this.headerSuppliers = headerSuppliers;
- this.httpClient = httpClient;
- this.timeout = timeout;
- }
-
- public Environment environment() {
- return this.environment;
- }
-
- public Map headers(RequestOptions requestOptions) {
- Map values = new HashMap<>(this.headers);
- headerSuppliers.forEach((key, supplier) -> {
- values.put(key, supplier.get());
- });
- if (requestOptions != null) {
- values.putAll(requestOptions.getHeaders());
- }
- return values;
- }
-
- public int timeout(RequestOptions requestOptions) {
- if (requestOptions == null) {
- return this.timeout;
- }
- return requestOptions.getTimeout().orElse(this.timeout);
- }
-
- public OkHttpClient httpClient() {
- return this.httpClient;
- }
-
- public OkHttpClient httpClientWithTimeout(RequestOptions requestOptions) {
- if (requestOptions == null) {
- return this.httpClient;
- }
- return this.httpClient
- .newBuilder()
- .callTimeout(requestOptions.getTimeout().get(), requestOptions.getTimeoutTimeUnit())
- .connectTimeout(0, TimeUnit.SECONDS)
- .writeTimeout(0, TimeUnit.SECONDS)
- .readTimeout(0, TimeUnit.SECONDS)
- .build();
- }
-
- public static Builder builder() {
- return new Builder();
- }
-
- public static final class Builder {
- private Environment environment;
-
- private final Map headers = new HashMap<>();
-
- private final Map> headerSuppliers = new HashMap<>();
-
- private int maxRetries = 2;
-
- private Optional timeout = Optional.empty();
-
- private OkHttpClient httpClient = null;
-
- public Builder environment(Environment environment) {
- this.environment = environment;
- return this;
- }
-
- public Builder addHeader(String key, String value) {
- this.headers.put(key, value);
- return this;
- }
-
- public Builder addHeader(String key, Supplier value) {
- this.headerSuppliers.put(key, value);
- return this;
- }
-
- /**
- * Override the timeout in seconds. Defaults to 60 seconds.
- */
- public Builder timeout(int timeout) {
- this.timeout = Optional.of(timeout);
- return this;
- }
-
- /**
- * Override the timeout in seconds. Defaults to 60 seconds.
- */
- public Builder timeout(Optional timeout) {
- this.timeout = timeout;
- return this;
- }
-
- /**
- * Override the maximum number of retries. Defaults to 2 retries.
- */
- public Builder maxRetries(int maxRetries) {
- this.maxRetries = maxRetries;
- return this;
- }
-
- public Builder httpClient(OkHttpClient httpClient) {
- this.httpClient = httpClient;
- return this;
- }
-
- public ClientOptions build() {
- OkHttpClient.Builder httpClientBuilder =
- this.httpClient != null ? this.httpClient.newBuilder() : new OkHttpClient.Builder();
-
- if (this.httpClient != null) {
- timeout.ifPresent(timeout -> httpClientBuilder
- .callTimeout(timeout, TimeUnit.SECONDS)
- .connectTimeout(0, TimeUnit.SECONDS)
- .writeTimeout(0, TimeUnit.SECONDS)
- .readTimeout(0, TimeUnit.SECONDS));
- } else {
- httpClientBuilder
- .callTimeout(this.timeout.orElse(60), TimeUnit.SECONDS)
- .connectTimeout(0, TimeUnit.SECONDS)
- .writeTimeout(0, TimeUnit.SECONDS)
- .readTimeout(0, TimeUnit.SECONDS)
- .addInterceptor(new RetryInterceptor(this.maxRetries));
- }
-
- this.httpClient = httpClientBuilder.build();
- this.timeout = Optional.of(httpClient.callTimeoutMillis() / 1000);
-
- return new ClientOptions(environment, headers, headerSuppliers, httpClient, this.timeout.get());
- }
- }
-}
diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/core/RetryInterceptor.java b/common/src/main/java/com/skyflow/generated/auth/rest/core/RetryInterceptor.java
deleted file mode 100644
index 8344b974..00000000
--- a/common/src/main/java/com/skyflow/generated/auth/rest/core/RetryInterceptor.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/**
- * This file was auto-generated by Fern from our API Definition.
- */
-package com.skyflow.generated.auth.rest.core;
-
-import okhttp3.Interceptor;
-import okhttp3.Response;
-
-import java.io.IOException;
-import java.time.Duration;
-import java.util.Optional;
-import java.util.Random;
-
-public class RetryInterceptor implements Interceptor {
-
- private static final Duration ONE_SECOND = Duration.ofSeconds(1);
- private final ExponentialBackoff backoff;
- private final Random random = new Random();
-
- public RetryInterceptor(int maxRetries) {
- this.backoff = new ExponentialBackoff(maxRetries);
- }
-
- @Override
- public Response intercept(Chain chain) throws IOException {
- Response response = chain.proceed(chain.request());
-
- if (shouldRetry(response.code())) {
- return retryChain(response, chain);
- }
-
- return response;
- }
-
- private Response retryChain(Response response, Chain chain) throws IOException {
- Optional nextBackoff = this.backoff.nextBackoff();
- while (nextBackoff.isPresent()) {
- try {
- Thread.sleep(nextBackoff.get().toMillis());
- } catch (InterruptedException e) {
- throw new IOException("Interrupted while trying request", e);
- }
- response.close();
- response = chain.proceed(chain.request());
- if (shouldRetry(response.code())) {
- nextBackoff = this.backoff.nextBackoff();
- } else {
- return response;
- }
- }
-
- return response;
- }
-
- private static boolean shouldRetry(int statusCode) {
- return statusCode == 408 || statusCode == 429 || statusCode >= 500;
- }
-
- private final class ExponentialBackoff {
-
- private final int maxNumRetries;
-
- private int retryNumber = 0;
-
- ExponentialBackoff(int maxNumRetries) {
- this.maxNumRetries = maxNumRetries;
- }
-
- public Optional nextBackoff() {
- retryNumber += 1;
- if (retryNumber > maxNumRetries) {
- return Optional.empty();
- }
-
- int upperBound = (int) Math.pow(2, retryNumber);
- return Optional.of(ONE_SECOND.multipliedBy(random.nextInt(upperBound)));
- }
- }
-}
diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/core/Stream.java b/common/src/main/java/com/skyflow/generated/auth/rest/core/Stream.java
deleted file mode 100644
index 4a984faa..00000000
--- a/common/src/main/java/com/skyflow/generated/auth/rest/core/Stream.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/**
- * This file was auto-generated by Fern from our API Definition.
- */
-package com.skyflow.generated.auth.rest.core;
-
-import java.io.Reader;
-import java.util.Iterator;
-import java.util.NoSuchElementException;
-import java.util.Scanner;
-
-/**
- * The {@code Stream} class implements {@link Iterable} to provide a simple mechanism for reading and parsing
- * objects of a given type from data streamed via a {@link Reader} using a specified delimiter.
- *
- * {@code Stream} assumes that data is being pushed to the provided {@link Reader} asynchronously and utilizes a
- * {@code Scanner} to block during iteration if the next object is not available.
- *
- * @param The type of objects in the stream.
- */
-public final class Stream implements Iterable {
- /**
- * The {@link Class} of the objects in the stream.
- */
- private final Class valueType;
- /**
- * The {@link Scanner} used for reading from the input stream and blocking when needed during iteration.
- */
- private final Scanner scanner;
-
- /**
- * Constructs a new {@code Stream} with the specified value type, reader, and delimiter.
- *
- * @param valueType The class of the objects in the stream.
- * @param reader The reader that provides the streamed data.
- * @param delimiter The delimiter used to separate elements in the stream.
- */
- public Stream(Class valueType, Reader reader, String delimiter) {
- this.scanner = new Scanner(reader).useDelimiter(delimiter);
- this.valueType = valueType;
- }
-
- /**
- * Returns an iterator over the elements in this stream that blocks during iteration when the next object is
- * not yet available.
- *
- * @return An iterator that can be used to traverse the elements in the stream.
- */
- @Override
- public Iterator iterator() {
- return new Iterator() {
- /**
- * Returns {@code true} if there are more elements in the stream.
- *
- * Will block and wait for input if the stream has not ended and the next object is not yet available.
- *
- * @return {@code true} if there are more elements, {@code false} otherwise.
- */
- @Override
- public boolean hasNext() {
- return scanner.hasNext();
- }
-
- /**
- * Returns the next element in the stream.
- *
- * Will block and wait for input if the stream has not ended and the next object is not yet available.
- *
- * @return The next element in the stream.
- * @throws NoSuchElementException If there are no more elements in the stream.
- */
- @Override
- public T next() {
- if (!scanner.hasNext()) {
- throw new NoSuchElementException();
- } else {
- try {
- T parsedResponse = ObjectMappers.JSON_MAPPER.readValue(
- scanner.next().trim(), valueType);
- return parsedResponse;
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
- }
-
- /**
- * Removing elements from {@code Stream} is not supported.
- *
- * @throws UnsupportedOperationException Always, as removal is not supported.
- */
- @Override
- public void remove() {
- throw new UnsupportedOperationException();
- }
- };
- }
-}
diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/errors/HttpStatus.java b/common/src/main/java/com/skyflow/generated/auth/rest/errors/HttpStatus.java
deleted file mode 100644
index 2e1c45d2..00000000
--- a/common/src/main/java/com/skyflow/generated/auth/rest/errors/HttpStatus.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.skyflow.generated.auth.rest.errors;
-
-public enum HttpStatus {
- BAD_REQUEST("Bad Request");
-
- private final String httpStatus;
-
- HttpStatus(String httpStatus) {
- this.httpStatus = httpStatus;
- }
-
- public String getHttpStatus() {
- return httpStatus;
- }
-}
diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/resources/authentication/AsyncAuthenticationClient.java b/common/src/main/java/com/skyflow/generated/auth/rest/resources/authentication/AsyncAuthenticationClient.java
deleted file mode 100644
index c742b239..00000000
--- a/common/src/main/java/com/skyflow/generated/auth/rest/resources/authentication/AsyncAuthenticationClient.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/**
- * This file was auto-generated by Fern from our API Definition.
- */
-package com.skyflow.generated.auth.rest.resources.authentication;
-
-import com.skyflow.generated.auth.rest.core.ClientOptions;
-import com.skyflow.generated.auth.rest.core.RequestOptions;
-import com.skyflow.generated.auth.rest.resources.authentication.requests.V1GetAuthTokenRequest;
-import com.skyflow.generated.auth.rest.types.V1GetAuthTokenResponse;
-
-import java.util.concurrent.CompletableFuture;
-
-public class AsyncAuthenticationClient {
- protected final ClientOptions clientOptions;
-
- private final AsyncRawAuthenticationClient rawClient;
-
- public AsyncAuthenticationClient(ClientOptions clientOptions) {
- this.clientOptions = clientOptions;
- this.rawClient = new AsyncRawAuthenticationClient(clientOptions);
- }
-
- /**
- * Get responses with HTTP metadata like headers
- */
- public AsyncRawAuthenticationClient withRawResponse() {
- return this.rawClient;
- }
-
- /**
- *
<p>Generates a Bearer Token to authenticate with Skyflow. This method doesn't require the <code>Authorization</code> header.</p><p><b>Note:</b> For recommended ways to authenticate, see <a href='/api-authentication/'>API authentication</a>.</p>
<p>Generates a Bearer Token to authenticate with Skyflow. This method doesn't require the <code>Authorization</code> header.</p><p><b>Note:</b> For recommended ways to authenticate, see <a href='/api-authentication/'>API authentication</a>.</p>
- */
- public CompletableFuture authenticationServiceGetAuthToken(
- V1GetAuthTokenRequest request, RequestOptions requestOptions) {
- return this.rawClient
- .authenticationServiceGetAuthToken(request, requestOptions)
- .thenApply(response -> response.body());
- }
-}
diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/resources/authentication/AuthenticationClient.java b/common/src/main/java/com/skyflow/generated/auth/rest/resources/authentication/AuthenticationClient.java
deleted file mode 100644
index a0ba860a..00000000
--- a/common/src/main/java/com/skyflow/generated/auth/rest/resources/authentication/AuthenticationClient.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/**
- * This file was auto-generated by Fern from our API Definition.
- */
-package com.skyflow.generated.auth.rest.resources.authentication;
-
-import com.skyflow.generated.auth.rest.core.ClientOptions;
-import com.skyflow.generated.auth.rest.core.RequestOptions;
-import com.skyflow.generated.auth.rest.resources.authentication.requests.V1GetAuthTokenRequest;
-import com.skyflow.generated.auth.rest.types.V1GetAuthTokenResponse;
-
-public class AuthenticationClient {
- protected final ClientOptions clientOptions;
-
- private final RawAuthenticationClient rawClient;
-
- public AuthenticationClient(ClientOptions clientOptions) {
- this.clientOptions = clientOptions;
- this.rawClient = new RawAuthenticationClient(clientOptions);
- }
-
- /**
- * Get responses with HTTP metadata like headers
- */
- public RawAuthenticationClient withRawResponse() {
- return this.rawClient;
- }
-
- /**
- *
<p>Generates a Bearer Token to authenticate with Skyflow. This method doesn't require the <code>Authorization</code> header.</p><p><b>Note:</b> For recommended ways to authenticate, see <a href='/api-authentication/'>API authentication</a>.</p>
<p>Generates a Bearer Token to authenticate with Skyflow. This method doesn't require the <code>Authorization</code> header.</p><p><b>Note:</b> For recommended ways to authenticate, see <a href='/api-authentication/'>API authentication</a>.</p>
<p>Generates a Bearer Token to authenticate with Skyflow. This method doesn't require the <code>Authorization</code> header.</p><p><b>Note:</b> For recommended ways to authenticate, see <a href='/api-authentication/'>API authentication</a>.</p>
<p>Generates a Bearer Token to authenticate with Skyflow. This method doesn't require the <code>Authorization</code> header.</p><p><b>Note:</b> For recommended ways to authenticate, see <a href='/api-authentication/'>API authentication</a>.</p>