Skip to content

Commit 943258c

Browse files
TharmiganKdaneshk
andauthored
Refactor persist-tools to extract core Java APIs into separate module (#428)
* Refactor persist-tools to extract core Java APIs into separate module Create new `persist-core` gradle subproject containing reusable Java APIs that were previously tightly coupled to the CLI tool. This enables direct usage of core persistence functionality in other Java packages without depending on the CLI. Changes: - Add `persist-core` gradle subproject with Java library configuration - Move core packages from `persist-cli` to `persist-core`: * configuration, introspect, nodegenerator (all subpackages) * inflector, utils, models, components, introspectiondto * BalException.java, PersistToolsConstants.java - Create JPMS module definition for `persist-core` - Extract shared file utilities into FileUtils class - Update `persist-cli` to depend on `persist-core` - Update `persist-cli-tests` to include both modules - Configure GitHub Packages publication for `persist-core` - Preserve all gradle build functionality and test execution This architectural change maintains backward compatibility while providing a cleaner separation of concerns between the CLI interface and core persistence logic. * Apply suggestions from code review Co-authored-by: Danesh Kuruppu <daneshk@users.noreply.github.com> * Refactor file handling in persist tools to utilize FileUtils for output operations --------- Co-authored-by: Danesh Kuruppu <daneshk@users.noreply.github.com>
1 parent d2ddd63 commit 943258c

File tree

76 files changed

+393
-171
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

76 files changed

+393
-171
lines changed

build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ task createProperties() {
169169

170170
task build {
171171
dependsOn createProperties
172+
dependsOn(":persist-core:build")
172173
dependsOn(":persist-cli:build")
173174
dependsOn(":persist-cli-tests:build")
174175
dependsOn(":persist-tool:build")

persist-cli-tests/build.gradle

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ dependencies {
6666
transitive = false
6767
}
6868

69+
testImplementation project(":persist-core")
6970
testImplementation project(":persist-cli")
7071
testImplementation group: 'org.testng', name: 'testng', version: "${testngVersion}"
7172
testImplementation 'org.junit.jupiter:junit-jupiter:5.8.1'
@@ -302,8 +303,9 @@ jacoco {
302303

303304
jacocoTestReport {
304305
dependsOn test
305-
def classFiles = new File("${rootDir}/persist-cli/build/classes/java/main/io/ballerina/persist")
306-
additionalClassDirs(classFiles)
306+
def coreClassFiles = new File("${rootDir}/persist-core/build/classes/java/main/io/ballerina/persist")
307+
def cliClassFiles = new File("${rootDir}/persist-cli/build/classes/java/main/io/ballerina/persist")
308+
additionalClassDirs(coreClassFiles, cliClassFiles)
307309
reports {
308310
xml.required = true
309311
}

persist-cli/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ dependencies {
3636
checkstyle project(':checkstyle')
3737
checkstyle "com.puppycrawl.tools:checkstyle:${checkstylePluginVersion}"
3838

39+
implementation project(':persist-core')
3940
implementation group: 'org.ballerinalang', name: 'ballerina-lang', version: "${ballerinaLangVersion}"
4041
implementation (group: 'org.ballerinalang', name: 'ballerina-cli', version: "${ballerinaLangVersion}") {
4142
exclude group: 'org.ballerinalang', module: 'maven-resolver'

persist-cli/src/main/java/io/ballerina/persist/cmd/Add.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import io.ballerina.persist.PersistToolsConstants;
2424
import io.ballerina.persist.nodegenerator.syntax.utils.TomlSyntaxUtils;
2525
import io.ballerina.persist.utils.BalProjectUtils;
26+
import io.ballerina.persist.utils.FileUtils;
2627
import io.ballerina.projects.util.ProjectUtils;
2728
import io.ballerina.toml.syntax.tree.AbstractNodeFactory;
2829
import io.ballerina.toml.syntax.tree.DocumentMemberDeclarationNode;
@@ -125,7 +126,7 @@ public void execute() {
125126
createDefaultClientId();
126127
String syntaxTree = updateBallerinaToml(Paths.get(this.sourcePath, BALLERINA_TOML),
127128
moduleNameWithPackage, datastore, testDatastore, eagerLoading, id);
128-
Utils.writeOutputString(syntaxTree,
129+
FileUtils.writeToTargetFile(syntaxTree,
129130
Paths.get(sourcePath, BALLERINA_TOML).toAbsolutePath().toString());
130131
createPersistDirectoryIfNotExists();
131132
createDefaultSchemaBalFile();
@@ -232,7 +233,8 @@ private void createPersistDirectoryIfNotExists() throws IOException {
232233

233234
private void createDefaultSchemaBalFile() throws IOException, BalException {
234235
List<String> schemaFiles;
235-
try (Stream<Path> stream = Files.list(Paths.get(sourcePath, PERSIST_DIRECTORY))) {
236+
Path persistPath = Paths.get(sourcePath, PERSIST_DIRECTORY);
237+
try (Stream<Path> stream = Files.list(persistPath)) {
236238
schemaFiles = stream.filter(file -> !Files.isDirectory(file))
237239
.map(Path::getFileName)
238240
.filter(Objects::nonNull)
@@ -245,7 +247,7 @@ private void createDefaultSchemaBalFile() throws IOException, BalException {
245247
"but contains many files.");
246248
}
247249
if (schemaFiles.isEmpty()) {
248-
Utils.generateSchemaBalFile(Paths.get(sourcePath, PERSIST_DIRECTORY));
250+
FileUtils.generateSchemaBalFile(persistPath);
249251
}
250252
}
251253

persist-cli/src/main/java/io/ballerina/persist/cmd/Generate.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import io.ballerina.persist.nodegenerator.syntax.constants.BalSyntaxConstants;
2626
import io.ballerina.persist.nodegenerator.syntax.utils.TomlSyntaxUtils;
2727
import io.ballerina.persist.utils.BalProjectUtils;
28+
import io.ballerina.persist.utils.FileUtils;
2829
import io.ballerina.projects.util.ProjectUtils;
2930
import io.ballerina.toml.syntax.tree.DocumentMemberDeclarationNode;
3031
import io.ballerina.toml.syntax.tree.DocumentNode;
@@ -225,7 +226,7 @@ public void execute() {
225226
BalProjectUtils.updateToml(sourcePath, datastore, moduleNameWithPackage);
226227
String syntaxTree = updateBallerinaToml(Paths.get(this.sourcePath, BALLERINA_TOML),
227228
datastore, testDatastore);
228-
Utils.writeOutputString(syntaxTree,
229+
FileUtils.writeToTargetFile(syntaxTree,
229230
Paths.get(this.sourcePath, BALLERINA_TOML).toAbsolutePath().toString());
230231
BalProjectUtils.validateSchemaFile(schemaFilePath);
231232
Module module = BalProjectUtils.getEntities(schemaFilePath);

persist-cli/src/main/java/io/ballerina/persist/cmd/Init.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
import io.ballerina.cli.BLauncherCmd;
2121
import io.ballerina.persist.BalException;
22+
import io.ballerina.persist.utils.FileUtils;
2223
import picocli.CommandLine;
2324

2425
import java.io.IOException;
@@ -113,9 +114,9 @@ public void execute() {
113114
"but contains many files.");
114115
return;
115116
}
116-
if (schemaFiles.size() == 0) {
117+
if (schemaFiles.isEmpty()) {
117118
try {
118-
Utils.generateSchemaBalFile(persistDirPath);
119+
FileUtils.generateSchemaBalFile(persistDirPath);
119120
} catch (BalException e) {
120121
errStream.println("ERROR: failed to create the model definition file in persist directory. "
121122
+ e.getMessage());

persist-cli/src/main/java/io/ballerina/persist/cmd/PersistCodeGeneratorTool.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import io.ballerina.persist.nodegenerator.syntax.constants.BalSyntaxConstants;
2626
import io.ballerina.persist.nodegenerator.syntax.utils.TomlSyntaxUtils;
2727
import io.ballerina.persist.utils.BalProjectUtils;
28+
import io.ballerina.persist.utils.FileUtils;
2829
import io.ballerina.projects.buildtools.CodeGeneratorTool;
2930
import io.ballerina.projects.buildtools.ToolConfig;
3031
import io.ballerina.projects.buildtools.ToolContext;
@@ -78,8 +79,9 @@ public void execute(ToolContext toolContext) {
7879
BalProjectUtils.validateBallerinaProject(projectPath);
7980
packageName = TomlSyntaxUtils.readPackageName(projectPath.toString());
8081
schemaFilePath = BalProjectUtils.getSchemaFilePath(projectPath.toString());
82+
Path path = Paths.get(projectPath.toString(), BALLERINA_TOML);
8183
HashMap<String, String> ballerinaTomlConfig = TomlSyntaxUtils.readBallerinaTomlConfig(
82-
Paths.get(projectPath.toString(), BALLERINA_TOML));
84+
path);
8385
targetModule = ballerinaTomlConfig.get(TARGET_MODULE).trim();
8486
datastore = ballerinaTomlConfig.get(OPTION_DATASTORE).trim();
8587
testDatastore = ballerinaTomlConfig.get(OPTION_TEST_DATASTORE) == null ? null :
@@ -111,10 +113,8 @@ public void execute(ToolContext toolContext) {
111113
BalProjectUtils.validateSchemaFile(schemaFilePath);
112114
entityModule = BalProjectUtils.getEntities(schemaFilePath);
113115
validateEntityModule(entityModule, schemaFilePath);
114-
String syntaxTree = updateBallerinaToml(
115-
Paths.get(projectPath.toString(), BALLERINA_TOML), datastore, testDatastore);
116-
Utils.writeOutputString(syntaxTree,
117-
Paths.get(projectPath.toString(), BALLERINA_TOML).toAbsolutePath().toString());
116+
String syntaxTree = updateBallerinaToml(path, datastore, testDatastore);
117+
FileUtils.writeToTargetFile(syntaxTree, path.toAbsolutePath().toString());
118118
createGeneratedSourceDirIfNotExists(generatedSourceDirPath);
119119
generateSources(datastore, entityModule, targetModule, projectPath, generatedSourceDirPath,
120120
eagerLoading);

persist-cli/src/main/java/io/ballerina/persist/cmd/Utils.java

Lines changed: 0 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -18,104 +18,11 @@
1818

1919
package io.ballerina.persist.cmd;
2020

21-
import io.ballerina.compiler.syntax.tree.AbstractNodeFactory;
22-
import io.ballerina.compiler.syntax.tree.ImportDeclarationNode;
23-
import io.ballerina.compiler.syntax.tree.ModuleMemberDeclarationNode;
24-
import io.ballerina.compiler.syntax.tree.ModulePartNode;
25-
import io.ballerina.compiler.syntax.tree.NodeFactory;
26-
import io.ballerina.compiler.syntax.tree.NodeList;
27-
import io.ballerina.compiler.syntax.tree.NodeParser;
28-
import io.ballerina.compiler.syntax.tree.SyntaxTree;
29-
import io.ballerina.compiler.syntax.tree.Token;
30-
import io.ballerina.persist.BalException;
3121
import io.ballerina.persist.PersistToolsConstants;
32-
import io.ballerina.persist.nodegenerator.syntax.constants.BalSyntaxConstants;
33-
import io.ballerina.tools.text.TextDocument;
34-
import io.ballerina.tools.text.TextDocuments;
35-
import org.ballerinalang.formatter.core.Formatter;
36-
import org.ballerinalang.formatter.core.FormatterException;
3722

38-
import java.io.File;
39-
import java.io.IOException;
4023
import java.io.PrintStream;
41-
import java.io.PrintWriter;
42-
import java.nio.charset.StandardCharsets;
43-
import java.nio.file.Files;
44-
import java.nio.file.Path;
45-
import java.nio.file.Paths;
46-
import java.util.Objects;
47-
48-
import static io.ballerina.persist.PersistToolsConstants.SCHEMA_FILE_NAME;
49-
import static io.ballerina.persist.nodegenerator.syntax.constants.BalSyntaxConstants.BAL_EXTENSION;
5024

5125
public class Utils {
52-
public static void generateSchemaBalFile(Path persistPath) throws BalException {
53-
try {
54-
String configTree = generateSchemaSyntaxTree();
55-
writeOutputString(configTree, persistPath.resolve(SCHEMA_FILE_NAME + BAL_EXTENSION)
56-
.toAbsolutePath().toString());
57-
} catch (Exception e) {
58-
throw new BalException(e.getMessage());
59-
}
60-
}
61-
62-
public static void writeOutputString(String content, String outPath) throws BalException, IOException {
63-
Path pathToFile = Paths.get(outPath);
64-
Path parentDirectory = pathToFile.getParent();
65-
if (Objects.nonNull(parentDirectory)) {
66-
if (!Files.exists(parentDirectory)) {
67-
try {
68-
Files.createDirectories(parentDirectory);
69-
} catch (IOException e) {
70-
throw new BalException(
71-
String.format("could not create the parent directories of output path %s. %s",
72-
parentDirectory, e.getMessage()));
73-
}
74-
}
75-
try (PrintWriter writer = new PrintWriter(outPath, StandardCharsets.UTF_8)) {
76-
writer.println(content);
77-
}
78-
}
79-
}
80-
81-
public static void writeToTargetFile(String content, String outPath) throws BalException, IOException {
82-
Path pathToFile = Paths.get(outPath);
83-
Path parentDirectory = pathToFile.getParent();
84-
if (Objects.nonNull(parentDirectory)) {
85-
if (!Files.exists(parentDirectory)) {
86-
try {
87-
Files.createDirectories(parentDirectory);
88-
} catch (IOException e) {
89-
throw new BalException(
90-
String.format("could not create the parent directories of output path %s. %s",
91-
parentDirectory, e.getMessage()));
92-
}
93-
}
94-
File file = new File(pathToFile.toString());
95-
if (!file.exists()) {
96-
boolean fileCreated = file.createNewFile();
97-
if (!fileCreated) {
98-
throw new BalException(
99-
String.format("Could not create the file in the output path %s.", outPath));
100-
}
101-
}
102-
try (PrintWriter writer = new PrintWriter(outPath, StandardCharsets.UTF_8)) {
103-
writer.println(content);
104-
}
105-
}
106-
}
107-
108-
public static String generateSchemaSyntaxTree() throws FormatterException {
109-
NodeList<ImportDeclarationNode> imports = AbstractNodeFactory.createEmptyNodeList();
110-
NodeList<ModuleMemberDeclarationNode> moduleMembers = AbstractNodeFactory.createEmptyNodeList();
111-
112-
imports = imports.add(NodeParser.parseImportDeclaration("import ballerina/persist as _;"));
113-
Token eofToken = AbstractNodeFactory.createIdentifierToken(BalSyntaxConstants.EMPTY_STRING);
114-
ModulePartNode modulePartNode = NodeFactory.createModulePartNode(imports, moduleMembers, eofToken);
115-
TextDocument textDocument = TextDocuments.from(BalSyntaxConstants.EMPTY_STRING);
116-
SyntaxTree balTree = SyntaxTree.from(textDocument);
117-
return Formatter.format(balTree.modifyWith(modulePartNode).toSourceCode());
118-
}
11926

12027
public static boolean validateEagerLoading(String datastore, boolean eagerLoading, PrintStream errStream) {
12128
if (eagerLoading && !datastore.equals(PersistToolsConstants.SupportedDataSources.MYSQL_DB) &&

persist-cli/src/main/java/module-info.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
*/
1818

1919
module io.ballerina.persist {
20+
requires io.ballerina.persist.core;
2021
requires io.ballerina.runtime;
2122
requires io.ballerina.lang;
2223
requires io.ballerina.cli;

0 commit comments

Comments
 (0)