Skip to content

Commit c5021f6

Browse files
committed
MLE-25666 Deferring construction of client when loading data
1 parent a1659d6 commit c5021f6

File tree

7 files changed

+64
-43
lines changed

7 files changed

+64
-43
lines changed

ml-app-deployer/src/main/java/com/marklogic/appdeployer/command/data/LoadDataCommand.java

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import com.marklogic.client.DatabaseClient;
1212
import com.marklogic.client.ext.file.FileLoader;
1313
import com.marklogic.client.ext.file.GenericFileLoader;
14+
import com.marklogic.client.ext.helper.DatabaseClientSupplier;
1415
import org.springframework.util.StringUtils;
1516

1617
import java.util.List;
@@ -42,21 +43,16 @@ public void execute(CommandContext context) {
4243
return;
4344
}
4445

45-
final FileLoader fileLoader = buildFileLoader(context.getAppConfig());
46-
for (String dataPath : dataPaths) {
47-
fileLoader.loadFiles(dataPath);
46+
try (DatabaseClientSupplier clientSupplier = new DatabaseClientSupplier(() -> determineDatabaseClient(context.getAppConfig()))) {
47+
final FileLoader fileLoader = buildFileLoader(context.getAppConfig(), clientSupplier);
48+
for (String dataPath : dataPaths) {
49+
fileLoader.loadFiles(dataPath);
50+
}
4851
}
4952
}
5053

51-
/**
52-
* Build a FileLoader based on the configuration in the given AppConfig object.
53-
*
54-
* @param appConfig
55-
* @return
56-
*/
57-
protected FileLoader buildFileLoader(AppConfig appConfig) {
58-
final DatabaseClient client = determineDatabaseClient(appConfig);
59-
final GenericFileLoader loader = new GenericFileLoader(client);
54+
protected final FileLoader buildFileLoader(AppConfig appConfig, DatabaseClientSupplier supplier) {
55+
final GenericFileLoader loader = new GenericFileLoader(supplier);
6056

6157
loader.setCascadeCollections(appConfig.isCascadeCollections());
6258
loader.setCascadePermissions(appConfig.isCascadePermissions());
@@ -97,11 +93,11 @@ protected FileLoader buildFileLoader(AppConfig appConfig) {
9793
* @param appConfig
9894
* @return
9995
*/
100-
protected DatabaseClient determineDatabaseClient(AppConfig appConfig) {
96+
protected final DatabaseClient determineDatabaseClient(AppConfig appConfig) {
10197
DataConfig dataConfig = appConfig.getDataConfig();
10298
final String databaseName = dataConfig.getDatabaseName();
10399
if (StringUtils.hasText(databaseName)) {
104-
logger.info("Will load data via App-Services port into database: " + databaseName);
100+
logger.info("Will load data via App-Services port into database: {}", databaseName);
105101
return appConfig.newAppServicesDatabaseClient(databaseName);
106102
}
107103
return appConfig.newDatabaseClient();

ml-app-deployer/src/main/java/com/marklogic/appdeployer/command/pdc/DeployMarkLogicEndpointsCommand.java

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -56,15 +56,11 @@ private List<MarkLogicHttpEndpoint> readEndpointDefinitionsFromFiles(CommandCont
5656
File serviceDir = new File(pdcConfigPath, "service");
5757
File endpointsDir = new File(serviceDir, "mlendpoints");
5858
if (!endpointsDir.exists()) {
59-
if (logger.isDebugEnabled()) {
60-
logger.debug("MarkLogic endpoints directory does not exist: {}", endpointsDir.getAbsolutePath());
61-
}
59+
logger.info("MarkLogic endpoints directory does not exist: {}", endpointsDir.getAbsolutePath());
6260
continue;
6361
}
6462

65-
if (logger.isInfoEnabled()) {
66-
logger.info("Reading MarkLogic endpoints from: {}", endpointsDir.getAbsolutePath());
67-
}
63+
logger.info("Reading MarkLogic endpoints from: {}", endpointsDir.getAbsolutePath());
6864

6965
try (Stream<Path> paths = Files.walk(endpointsDir.toPath())) {
7066
paths.filter(Files::isRegularFile)
@@ -106,9 +102,7 @@ private void deployEndpoints(CommandContext context, List<MarkLogicHttpEndpoint>
106102
if (endpointsToDeploy.isEmpty()) {
107103
logger.info("All {} endpoint(s) are up to date; nothing to deploy.", endpoints.size());
108104
} else {
109-
if (logger.isInfoEnabled()) {
110-
logger.info("Deploying {} new or updated endpoint(s) out of {} total.", endpointsToDeploy.size(), endpoints.size());
111-
}
105+
logger.info("Deploying {} new or updated endpoint(s) out of {} total.", endpointsToDeploy.size(), endpoints.size());
112106
serviceApi.apiServiceMlendpointsIdHttpPut(markLogicServiceId, endpointsToDeploy);
113107
logger.info("Successfully deployed {} endpoint(s).", endpointsToDeploy.size());
114108
}

ml-app-deployer/src/test/java/com/marklogic/appdeployer/command/data/LoadDataTest.java

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,12 @@
1616
import java.io.File;
1717
import java.util.Set;
1818

19-
import static org.junit.jupiter.api.Assertions.assertEquals;
20-
import static org.junit.jupiter.api.Assertions.assertFalse;
21-
import static org.junit.jupiter.api.Assertions.assertNotNull;
22-
import static org.junit.jupiter.api.Assertions.assertNull;
23-
import static org.junit.jupiter.api.Assertions.assertTrue;
19+
import static org.junit.jupiter.api.Assertions.*;
2420

25-
public class LoadDataTest extends AbstractAppDeployerTest {
21+
class LoadDataTest extends AbstractAppDeployerTest {
2622

2723
@AfterEach
28-
public void teardown() {
24+
void teardown() {
2925
undeploySampleApp();
3026
}
3127

@@ -34,7 +30,7 @@ public void teardown() {
3430
* just does some basic assertions to make sure all is well.
3531
*/
3632
@Test
37-
public void multiplePaths() {
33+
void multiplePaths() {
3834
DataConfig dataConfig = appConfig.getDataConfig();
3935
dataConfig.getDataPaths().add(new File(dataConfig.getProjectDir(), "src/main/more-data").getAbsolutePath());
4036

@@ -72,7 +68,7 @@ public void multiplePaths() {
7268
}
7369

7470
@Test
75-
public void databaseNameIsSet() {
71+
void databaseNameIsSet() {
7672
LoadDataCommand command = new LoadDataCommand();
7773
DatabaseClient client = command.determineDatabaseClient(appConfig);
7874
assertNull(client.getDatabase(), "The database property isn't set on a DatabaseClient when no value is provided when the " +
@@ -94,7 +90,7 @@ void cascadeCollectionsAndPermissions() {
9490
appConfig.setCascadePermissions(true);
9591
appConfig.setCascadeCollections(true);
9692

97-
GenericFileLoader loader = (GenericFileLoader) new LoadDataCommand().buildFileLoader(appConfig);
93+
GenericFileLoader loader = (GenericFileLoader) new LoadDataCommand().buildFileLoader(appConfig, null);
9894

9995
assertTrue(loader.isCascadeCollections());
10096
assertTrue(loader.isCascadePermissions());

ml-javaclient-util/src/main/java/com/marklogic/client/ext/file/GenericFileLoader.java

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,15 @@
77
import com.marklogic.client.document.DocumentWriteOperation;
88
import com.marklogic.client.ext.batch.BatchWriter;
99
import com.marklogic.client.ext.batch.RestBatchWriter;
10+
import com.marklogic.client.ext.helper.DatabaseClientSupplier;
1011
import com.marklogic.client.ext.helper.LoggingObject;
1112
import com.marklogic.client.ext.tokenreplacer.TokenReplacer;
1213

1314
import java.io.FileFilter;
1415
import java.util.ArrayList;
1516
import java.util.List;
17+
import java.util.Objects;
18+
import java.util.function.Supplier;
1619
import java.util.stream.Collectors;
1720

1821
/**
@@ -28,6 +31,7 @@ public class GenericFileLoader extends LoggingObject implements FileLoader {
2831

2932
private DocumentFileReader documentFileReader;
3033
private BatchWriter batchWriter;
34+
private Supplier<DatabaseClient> databaseClientSupplier;
3135
private boolean waitForCompletion = true;
3236
private boolean logFileUris = true;
3337
private Integer batchSize;
@@ -44,6 +48,20 @@ public class GenericFileLoader extends LoggingObject implements FileLoader {
4448
private boolean cascadeCollections;
4549
private boolean cascadePermissions;
4650

51+
/**
52+
* The given DatabaseClientSupplier is used to lazily construct a BatchWriter that writes to MarkLogic via the REST API.
53+
* The DatabaseClient will only be created when files are actually written, avoiding unnecessary client creation.
54+
* <p>
55+
* The expectation is that the client will then either call setDocumentFileReader or will rely on the default one
56+
* that's created by this class if one has not yet been set.
57+
*
58+
* @param databaseClientSupplier supplier for lazy client creation
59+
* @since 6.2.0
60+
*/
61+
public GenericFileLoader(Supplier<DatabaseClient> databaseClientSupplier) {
62+
this.databaseClientSupplier = databaseClientSupplier;
63+
}
64+
4765
/**
4866
* The given DatabaseClient is used to construct a BatchWriter that writes to MarkLogic via the REST API. The
4967
* expectation is that the client will then either call setDocumentFileReader or will rely on the default one
@@ -52,9 +70,7 @@ public class GenericFileLoader extends LoggingObject implements FileLoader {
5270
* @param client
5371
*/
5472
public GenericFileLoader(DatabaseClient client) {
55-
RestBatchWriter restBatchWriter = new RestBatchWriter(client);
56-
restBatchWriter.setReleaseDatabaseClients(false);
57-
this.batchWriter = restBatchWriter;
73+
this(new DatabaseClientSupplier(() -> client));
5874
}
5975

6076
/**
@@ -87,7 +103,7 @@ protected final List<DocumentFile> getDocumentFiles(String... paths) {
87103

88104
protected final void writeDocumentFiles(List<DocumentFile> documentFiles) {
89105
if (documentFiles != null && !documentFiles.isEmpty()) {
90-
batchWriter.initialize();
106+
initializeBatchWriter();
91107
writeBatchOfDocuments(documentFiles, 0);
92108
if (waitForCompletion) {
93109
batchWriter.waitForCompletion();
@@ -140,6 +156,21 @@ protected void writeBatchOfDocuments(List<DocumentFile> documentFiles, final int
140156
}
141157
}
142158

159+
/**
160+
* Lazily initializes the BatchWriter from the DatabaseClientSupplier if needed.
161+
* This ensures the DatabaseClient is only created when files actually need to be written.
162+
*/
163+
private void initializeBatchWriter() {
164+
if (batchWriter == null) {
165+
Objects.requireNonNull(databaseClientSupplier, "A DatabaseClient supplier is required to lazily create a BatchWriter.");
166+
RestBatchWriter restBatchWriter = new RestBatchWriter(databaseClientSupplier.get());
167+
restBatchWriter.setReleaseDatabaseClients(false);
168+
this.batchWriter = restBatchWriter;
169+
}
170+
171+
batchWriter.initialize();
172+
}
173+
143174
/**
144175
* If no DocumentFileReader is set, this will construct a DefaultDocumentFileReader, which is then configured based
145176
* on several properties of this class.

ml-javaclient-util/src/main/java/com/marklogic/client/ext/helper/DatabaseClientSupplier.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
/**
1212
* Preferred mechanism for lazy instantiation of a DatabaseClient. Will eventually deprecate DatabaseClientProvider in
13-
* favor of this.
13+
* favor of this. Wraps a {@code Supplier<DatabaseClient>} and handles releasing the client if it was created.
1414
*
1515
* @since 6.2.0
1616
*/
@@ -27,6 +27,10 @@ public DatabaseClientSupplier(Supplier<DatabaseClient> databaseClientSupplier) {
2727
this.databaseClientSupplier = databaseClientSupplier;
2828
}
2929

30+
/**
31+
* @return the DatabaseClient, creating it via the supplier if it hasn't already been created. May return null if
32+
* the supplier is not able to create a client.
33+
*/
3034
public DatabaseClient get() {
3135
if (databaseClient == null) {
3236
databaseClient = databaseClientSupplier.get();

ml-javaclient-util/src/main/java/com/marklogic/client/ext/modulesloader/impl/AssetFileLoader.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public AssetFileLoader(DatabaseClient modulesDatabaseClient) {
2121
}
2222

2323
public AssetFileLoader(DatabaseClient modulesDatabaseClient, ModulesManager modulesManager) {
24-
super(modulesDatabaseClient);
24+
super(() -> modulesDatabaseClient);
2525
initializeAssetFileLoader(modulesManager);
2626
}
2727

ml-javaclient-util/src/test/java/com/marklogic/client/ext/file/SetAdditionalBinaryExtensionsTest.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@
1010
import java.nio.file.Paths;
1111
import java.util.List;
1212

13-
import static org.junit.jupiter.api.Assertions.*;
13+
import static org.junit.jupiter.api.Assertions.assertEquals;
1414

15-
public class SetAdditionalBinaryExtensionsTest extends AbstractIntegrationTest {
15+
class SetAdditionalBinaryExtensionsTest extends AbstractIntegrationTest {
1616

1717
@Test
18-
public void test() {
18+
void test() {
1919
client = newClient(CONTENT_DATABASE);
20-
client.newServerEval().xquery("cts:uris((), (), cts:not-query(cts:collection-query('test-data'))) ! xdmp:document-delete(.)").eval();
20+
client.newServerEval().xquery("cts:uris((), (), cts:not-query(cts:collection-query('test-data'))) ! xdmp:document-delete(.)").evalAs(String.class);
2121

2222
GenericFileLoader loader = new GenericFileLoader(client);
2323
loader.setAdditionalBinaryExtensions("test1", "test2");

0 commit comments

Comments
 (0)