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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@
import java.util.Arrays;
import java.util.Base64;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import okhttp3.Call;
import okhttp3.Callback;
Expand All @@ -32,6 +34,10 @@
/** Constructor.io Client */
public class ConstructorIO {

/** Valid file extensions for catalog uploads */
private static final Set<String> VALID_CATALOG_EXTENSIONS =
new LinkedHashSet<>(Arrays.asList(".csv", ".json", ".jsonl"));

/** the HTTP client used by all instances */
private static OkHttpClient client =
new OkHttpClient.Builder()
Expand Down Expand Up @@ -2031,6 +2037,53 @@ protected static String getResponseBody(Response response) throws ConstructorExc
throw new ConstructorException(errorMessage, errorCode);
}

/**
* Validates and extracts the file extension from a File object for catalog uploads.
*
* @param file the File object containing the actual file
* @param fileName the logical file name (items, variations, item_groups)
* @return the validated file extension (including the dot, e.g., ".csv", ".json", or ".jsonl")
* @throws ConstructorException if the file extension is not in VALID_CATALOG_EXTENSIONS
*/
private static String getValidatedFileExtension(File file, String fileName)
throws ConstructorException {
if (file == null) {
throw new ConstructorException(
"Invalid file for '" + fileName + "': file cannot be null.");
}

String actualFileName = file.getName();
if (actualFileName == null || actualFileName.isEmpty()) {
throw new ConstructorException(
"Invalid file for '" + fileName + "': file name cannot be empty.");
}

int lastDotIndex = actualFileName.lastIndexOf('.');
if (lastDotIndex == -1 || lastDotIndex == actualFileName.length() - 1) {
throw new ConstructorException(
"Invalid file for '"
+ fileName
+ "': file must have "
+ VALID_CATALOG_EXTENSIONS
+ " extension. Found: "
+ actualFileName);
}

String extension = actualFileName.substring(lastDotIndex).toLowerCase();

if (!VALID_CATALOG_EXTENSIONS.contains(extension)) {
throw new ConstructorException(
"Invalid file type for '"
+ fileName
+ "': file must have "
+ VALID_CATALOG_EXTENSIONS
+ " extension. Found: "
+ actualFileName);
}

return extension;
}

/**
* Grabs the version number (hard coded ATM)
*
Expand Down Expand Up @@ -2308,9 +2361,12 @@ protected static JSONArray transformItemsAPIV2Response(JSONArray results) {
/**
* Send a full catalog to replace the current one (sync)
*
* @param req the catalog request
* @return a string of JSON
* @throws ConstructorException if the request is invalid.
* <p>Supports CSV, JSON, and JSONL file formats. The file type is automatically detected from
* the file extension (.csv, .json, or .jsonl).
*
* @param req the catalog request containing files with .csv, .json, or .jsonl extensions
* @return a string of JSON containing task information
* @throws ConstructorException if the request is invalid or file extensions are not supported
*/
public String replaceCatalog(CatalogRequest req) throws ConstructorException {
try {
Expand All @@ -2336,10 +2392,11 @@ public String replaceCatalog(CatalogRequest req) throws ConstructorException {
for (Map.Entry<String, File> entry : files.entrySet()) {
String fileName = entry.getKey();
File file = entry.getValue();
String fileExtension = getValidatedFileExtension(file, fileName);

multipartBuilder.addFormDataPart(
fileName,
fileName + ".csv",
fileName + fileExtension,
RequestBody.create(MediaType.parse("application/octet-stream"), file));
}
}
Expand All @@ -2365,9 +2422,12 @@ public String replaceCatalog(CatalogRequest req) throws ConstructorException {
/**
* Send a partial catalog to update specific items (delta)
*
* @param req the catalog request
* @return a string of JSON
* @throws ConstructorException if the request is invalid.
* <p>Supports CSV, JSON, and JSONL file formats. The file type is automatically detected from
* the file extension (.csv, .json, or .jsonl).
*
* @param req the catalog request containing files with .csv, .json, or .jsonl extensions
* @return a string of JSON containing task information
* @throws ConstructorException if the request is invalid or file extensions are not supported
*/
public String updateCatalog(CatalogRequest req) throws ConstructorException {
try {
Expand All @@ -2393,10 +2453,11 @@ public String updateCatalog(CatalogRequest req) throws ConstructorException {
for (Map.Entry<String, File> entry : files.entrySet()) {
String fileName = entry.getKey();
File file = entry.getValue();
String fileExtension = getValidatedFileExtension(file, fileName);

multipartBuilder.addFormDataPart(
fileName,
fileName + ".csv",
fileName + fileExtension,
RequestBody.create(MediaType.parse("application/octet-stream"), file));
}
}
Expand All @@ -2423,9 +2484,12 @@ public String updateCatalog(CatalogRequest req) throws ConstructorException {
/**
* Send a patch delta catalog to update specific items (delta)
*
* @param req the catalog request
* @return a string of JSON
* @throws ConstructorException if the request is invalid.
* <p>Supports CSV, JSON, and JSONL file formats. The file type is automatically detected from
* the file extension (.csv, .json, or .jsonl).
*
* @param req the catalog request containing files with .csv, .json, or .jsonl extensions
* @return a string of JSON containing task information
* @throws ConstructorException if the request is invalid or file extensions are not supported
*/
public String patchCatalog(CatalogRequest req) throws ConstructorException {
try {
Expand Down Expand Up @@ -2456,10 +2520,11 @@ public String patchCatalog(CatalogRequest req) throws ConstructorException {
for (Map.Entry<String, File> entry : files.entrySet()) {
String fileName = entry.getKey();
File file = entry.getValue();
String fileExtension = getValidatedFileExtension(file, fileName);

multipartBuilder.addFormDataPart(
fileName,
fileName + ".csv",
fileName + fileExtension,
RequestBody.create(MediaType.parse("application/octet-stream"), file));
}
}
Expand Down
Loading
Loading