Skip to content

Add util classes for data loader CLI #2616

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 29 commits into from
May 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
be9ee23
Initial commit
inv-jishnu Apr 10, 2025
89b9f05
Spotless applied again
inv-jishnu Apr 11, 2025
49c83b6
Removed unused code
inv-jishnu Apr 11, 2025
b2871fb
Merge branch 'master' into feat/data-loader/import-log-2
ypeckstadt Apr 15, 2025
c5c9c0a
Removed unused classes and references
inv-jishnu Apr 15, 2025
4964e8d
Merge branch 'master' into feat/data-loader/import-log-2
inv-jishnu Apr 15, 2025
ff81f5f
Merge branch 'master' into feat/data-loader/import-log-2
inv-jishnu Apr 15, 2025
3934c2a
Improve Javadocs
ypeckstadt Apr 16, 2025
9958f95
Changes
inv-jishnu Apr 21, 2025
1afbc21
Renamed parameters
inv-jishnu Apr 21, 2025
8c5114d
logging changes
inv-jishnu Apr 21, 2025
ffab395
removed repeated code
inv-jishnu Apr 22, 2025
79df1ed
Merge branch 'master' into feat/data-loader/import-log-2
inv-jishnu Apr 22, 2025
cf31672
Merge branch 'master' into feat/data-loader/import-log-2
brfrn169 Apr 23, 2025
6dd213e
Added excetpion throw
inv-jishnu Apr 23, 2025
6542177
Synchronisation changes
inv-jishnu Apr 25, 2025
603e46e
Added volatile back to fix spotbugs issue
inv-jishnu Apr 25, 2025
eaf9d88
Removed unused variable
inv-jishnu Apr 25, 2025
0a2518a
Changes
inv-jishnu Apr 29, 2025
378effb
Initial commit
inv-jishnu Apr 29, 2025
8a71c75
Revert "Initial commit"
inv-jishnu Apr 29, 2025
df32a6f
Removed unused file
inv-jishnu May 7, 2025
e76e27a
Merged latest changes from master after resolving conflicts
inv-jishnu May 8, 2025
bed04c6
Added back new line
inv-jishnu May 8, 2025
8dc0d8a
Merge branch 'master' into feat/data-loader/cli-utils-2
inv-jishnu May 9, 2025
872412f
Merge branch 'master' into feat/data-loader/cli-utils-2
inv-jishnu May 13, 2025
f78de2d
Changes
inv-jishnu May 13, 2025
0d55aa8
Merge branch 'master' into feat/data-loader/cli-utils-2
inv-jishnu May 13, 2025
8ad50d9
Merge branch 'master' into feat/data-loader/cli-utils-2
ypeckstadt May 14, 2025
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
31 changes: 31 additions & 0 deletions core/src/main/java/com/scalar/db/common/error/CoreError.java
Original file line number Diff line number Diff line change
Expand Up @@ -865,6 +865,37 @@ public enum CoreError implements ScalarDbError {
"The replication feature is not enabled. To use this feature, you must enable it",
"",
""),
DATA_LOADER_IMPORT_TARGET_MISSING(
Category.USER_ERROR,
"0189",
"Missing option: either '--namespace' and'--table' or '--control-file' options must be specified.",
"",
""),
DATA_LOADER_MISSING_IMPORT_FILE(
Category.USER_ERROR,
"0190",
"The file '%s' specified by the argument '%s' does not exist.",
"",
""),
DATA_LOADER_LOG_DIRECTORY_WRITE_ACCESS_DENIED(
Category.USER_ERROR, "0191", "Cannot write to the log directory: %s", "", ""),
DATA_LOADER_LOG_DIRECTORY_CREATION_FAILED(
Category.USER_ERROR, "0192", "Failed to create the log directory: %s", "", ""),
DATA_LOADER_INVALID_CONTROL_FILE(
Category.USER_ERROR, "0193", "Failed to parse the control file: %s", "", ""),
DATA_LOADER_DIRECTORY_WRITE_ACCESS(
Category.USER_ERROR,
"0194",
"No permission to create or write files in the directory: %s",
"",
""),
DATA_LOADER_DIRECTORY_CREATION_FAILED(
Category.USER_ERROR, "0195", "Failed to create the directory: %s", "", ""),
DATA_LOADER_PATH_IS_NOT_A_DIRECTORY(
Category.USER_ERROR, "0196", "Path exists but is not a directory: %s", "", ""),
DATA_LOADER_FILE_PATH_IS_BLANK(
Category.USER_ERROR, "0197", "File path must not be blank.", "", ""),
DATA_LOADER_FILE_NOT_FOUND(Category.USER_ERROR, "0198", "File not found: %s", "", ""),

//
// Errors for the concurrency error category
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@ private void validateOutputDirectory(@Nullable String path)
private void validateDirectory(String directoryPath) throws DirectoryValidationException {
// If the directory path is null or empty, use the current working directory
if (directoryPath == null || directoryPath.isEmpty()) {
DirectoryUtils.validateTargetDirectory(DirectoryUtils.getCurrentWorkingDirectory());
DirectoryUtils.validateOrCreateTargetDirectory(DirectoryUtils.getCurrentWorkingDirectory());
} else {
DirectoryUtils.validateTargetDirectory(directoryPath);
DirectoryUtils.validateOrCreateTargetDirectory(directoryPath);
}
}

Expand Down
23 changes: 21 additions & 2 deletions data-loader/cli/src/main/java/com/scalar/db/dataloader/cli/util/DirectoryUtils.java
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,30 @@ private DirectoryUtils() {
// restrict instantiation
}

/**
* Validates the current working directory. Ensures that it is writable.
*
* @throws DirectoryValidationException if the current working directory is not writable
*/
public static void validateWorkingDirectory() throws DirectoryValidationException {
Path workingDirectoryPath = Paths.get(System.getProperty("user.dir"));

// Check if the current working directory is writable
if (!Files.isWritable(workingDirectoryPath)) {
throw new DirectoryValidationException(
CoreError.DATA_LOADER_DIRECTORY_WRITE_ACCESS.buildMessage(
workingDirectoryPath.toAbsolutePath()));
}
}

/**
* Validates the provided directory path. Ensures that the directory exists and is writable. If
* the directory doesn't exist, a creation attempt is made.
*
* @param directoryPath the directory path to validate
* @throws DirectoryValidationException if the directory is not writable or cannot be created
*/
public static void validateTargetDirectory(String directoryPath)
public static void validateOrCreateTargetDirectory(String directoryPath)
throws DirectoryValidationException {
if (StringUtils.isBlank(directoryPath)) {
throw new IllegalArgumentException(
Expand All @@ -32,7 +48,10 @@ public static void validateTargetDirectory(String directoryPath)
Path path = Paths.get(directoryPath);

if (Files.exists(path)) {
// Check if the provided directory is writable
if (!Files.isDirectory(path)) {
throw new DirectoryValidationException(
CoreError.DATA_LOADER_PATH_IS_NOT_A_DIRECTORY.buildMessage(path));
}
if (!Files.isWritable(path)) {
throw new DirectoryValidationException(
CoreError.DATA_LOADER_DIRECTORY_WRITE_ACCESS_NOT_ALLOWED.buildMessage(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.scalar.db.dataloader.cli.util;

import com.scalar.db.common.error.CoreError;
import java.nio.file.Path;
import java.nio.file.Paths;
import org.apache.commons.lang3.StringUtils;

public class FileUtils {

/**
* Validates the provided file path.
*
* @param filePath the file path to validate
* @throws InvalidFilePathException if the file path is invalid
*/
public static void validateFilePath(String filePath) throws InvalidFilePathException {
if (StringUtils.isBlank(filePath)) {
throw new IllegalArgumentException(CoreError.DATA_LOADER_FILE_PATH_IS_BLANK.buildMessage());
}
Path pathToCheck = Paths.get(filePath);

if (!pathToCheck.toFile().exists()) {
throw new InvalidFilePathException(
CoreError.DATA_LOADER_FILE_NOT_FOUND.buildMessage(pathToCheck));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.scalar.db.dataloader.cli.util;

public class InvalidFilePathException extends Exception {

public InvalidFilePathException(String message) {
super(message);
}

public InvalidFilePathException(String message, Throwable cause) {
super(message, cause);
}
}
16 changes: 8 additions & 8 deletions data-loader/cli/src/test/java/com/scalar/db/dataloader/cli/util/DirectoryUtilsTest.java
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -30,26 +30,26 @@ public void cleanup() throws IOException {
@Test
void validateTargetDirectory_ValidDirectory_NoExceptionThrown()
throws DirectoryValidationException {
DirectoryUtils.validateTargetDirectory(tempDir.toString());
DirectoryUtils.validateOrCreateTargetDirectory(tempDir.toString());
}

@Test
void validateTargetDirectory_DirectoryDoesNotExist_CreatesDirectory()
void validateOrCreateTargetDirectory_DirectoryDoesNotExist_CreatesDirectory()
throws DirectoryValidationException {
Path newDirectory = Paths.get(tempDir.toString(), "newDir");
DirectoryUtils.validateTargetDirectory(newDirectory.toString());
DirectoryUtils.validateOrCreateTargetDirectory(newDirectory.toString());
assertTrue(Files.exists(newDirectory));
}

@Test
void validateTargetDirectory_DirectoryNotWritable_ThrowsException() throws IOException {
void validateOrCreateTargetDirectory_DirectoryNotWritable_ThrowsException() throws IOException {
Path readOnlyDirectory = Files.createDirectory(Paths.get(tempDir.toString(), "readOnlyDir"));
readOnlyDirectory.toFile().setWritable(false);

assertThrows(
DirectoryValidationException.class,
() -> {
DirectoryUtils.validateTargetDirectory(readOnlyDirectory.toString());
DirectoryUtils.validateOrCreateTargetDirectory(readOnlyDirectory.toString());
});
}

Expand All @@ -58,16 +58,16 @@ void validateTargetDirectory_NullDirectory_ThrowsException() {
assertThrows(
IllegalArgumentException.class,
() -> {
DirectoryUtils.validateTargetDirectory(null);
DirectoryUtils.validateOrCreateTargetDirectory(null);
});
}

@Test
void validateTargetDirectory_EmptyDirectory_ThrowsException() {
void validateOrCreateTargetDirectory_EmptyDirectory_ThrowsException() {
assertThrows(
IllegalArgumentException.class,
() -> {
DirectoryUtils.validateTargetDirectory("");
DirectoryUtils.validateOrCreateTargetDirectory("");
});
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.scalar.db.dataloader.cli.util;

import static org.assertj.core.api.Assertions.assertThatThrownBy;

import com.scalar.db.common.error.CoreError;
import java.nio.file.Paths;
import org.junit.jupiter.api.Test;

public class FileUtilsTest {

private static final String currentPath = Paths.get("").toAbsolutePath().toString();

@Test
void validateFilePath_withValidFilePath_shouldNotThrowException()
throws InvalidFilePathException {
// Test and confirm no exception is thrown when a valid path is provided
FileUtils.validateFilePath(currentPath);
}

@Test
void validateFilePath_withInvalidFilePath_shouldThrowException() {
assertThatThrownBy(() -> FileUtils.validateFilePath(currentPath + "/demo"))
.isInstanceOf(InvalidFilePathException.class)
.hasMessage(CoreError.DATA_LOADER_FILE_NOT_FOUND.buildMessage(currentPath + "/demo"));
}

@Test
void validateFilePath_withBlankFilePath_shouldThrowException() {
assertThatThrownBy(() -> FileUtils.validateFilePath(""))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage(CoreError.DATA_LOADER_FILE_PATH_IS_BLANK.buildMessage());
}
}