From ee4c7884b53720c2b4ea061c0e4d89087f162fe7 Mon Sep 17 00:00:00 2001 From: Rob Rudin Date: Mon, 1 Dec 2025 15:43:50 -0500 Subject: [PATCH] MLE-25666 Deferring construction of DatabaseClient This is just scratching the surface - next step will be to modify GenericFileLoader to accept a DatabaseClientSupplier instead of a DatabaseClient. That will allow the commands for loading modules, data, and schemas to only construct a client when necessary instead of eagerly. --- .../command/modules/LoadModulesCommand.java | 7 +-- .../plugins/InstallPluginsCommand.java | 27 ++++++------ ...InsertCertificateHostsTemplateCommand.java | 4 +- .../ext/helper/DatabaseClientSupplier.java | 43 +++++++++++++++++++ 4 files changed, 63 insertions(+), 18 deletions(-) create mode 100644 ml-javaclient-util/src/main/java/com/marklogic/client/ext/helper/DatabaseClientSupplier.java diff --git a/ml-app-deployer/src/main/java/com/marklogic/appdeployer/command/modules/LoadModulesCommand.java b/ml-app-deployer/src/main/java/com/marklogic/appdeployer/command/modules/LoadModulesCommand.java index 5eaef5b0..4543a03b 100644 --- a/ml-app-deployer/src/main/java/com/marklogic/appdeployer/command/modules/LoadModulesCommand.java +++ b/ml-app-deployer/src/main/java/com/marklogic/appdeployer/command/modules/LoadModulesCommand.java @@ -62,16 +62,13 @@ protected void loadModulesIntoMainServer(CommandContext context) { } AppConfig config = context.getAppConfig(); - DatabaseClient client = config.newDatabaseClient(); final List pathsList = config.getModulePaths(); final String[] pathsArray = pathsList.toArray(new String[]{}); - try { - logger.info("Loading modules from paths: " + pathsList); + try (DatabaseClient client = config.newDatabaseClient()) { + logger.info("Loading modules from paths: {}", pathsList); modulesLoader.loadModules(client, new DefaultModulesFinder(), pathsArray); - } finally { - client.release(); } } diff --git a/ml-app-deployer/src/main/java/com/marklogic/appdeployer/command/plugins/InstallPluginsCommand.java b/ml-app-deployer/src/main/java/com/marklogic/appdeployer/command/plugins/InstallPluginsCommand.java index ef4bb62b..7db0dc02 100644 --- a/ml-app-deployer/src/main/java/com/marklogic/appdeployer/command/plugins/InstallPluginsCommand.java +++ b/ml-app-deployer/src/main/java/com/marklogic/appdeployer/command/plugins/InstallPluginsCommand.java @@ -8,6 +8,7 @@ import com.marklogic.appdeployer.command.AbstractUndoableCommand; import com.marklogic.appdeployer.command.CommandContext; import com.marklogic.appdeployer.command.SortOrderConstants; +import com.marklogic.client.ext.helper.DatabaseClientSupplier; import com.marklogic.client.DatabaseClient; import com.marklogic.client.document.BinaryDocumentManager; import com.marklogic.client.eval.ServerEvaluationCall; @@ -39,9 +40,10 @@ public void execute(CommandContext context) { return; } - DatabaseClient client = determineDatabaseClient(context.getAppConfig()); - for (String path : paths) { - installPluginsInPath(path, context.getAppConfig(), client); + try (DatabaseClientSupplier clientSupplier = new DatabaseClientSupplier(() -> determineDatabaseClient(context.getAppConfig()))) { + for (String path : paths) { + installPluginsInPath(path, context.getAppConfig(), clientSupplier); + } } } @@ -52,9 +54,10 @@ public void undo(CommandContext context) { return; } - DatabaseClient client = determineDatabaseClient(context.getAppConfig()); - for (String path : paths) { - uninstallPluginsInPath(path, context.getAppConfig(), client); + try (DatabaseClientSupplier clientSupplier = new DatabaseClientSupplier(() -> determineDatabaseClient(context.getAppConfig()))) { + for (String path : paths) { + uninstallPluginsInPath(path, context.getAppConfig(), clientSupplier); + } } } @@ -72,7 +75,7 @@ protected List getPluginPaths(CommandContext context) { return config.getPluginPaths(); } - protected void installPluginsInPath(String path, AppConfig appConfig, DatabaseClient client) { + protected void installPluginsInPath(String path, AppConfig appConfig, DatabaseClientSupplier clientSupplier) { File pluginsDir = new File(path); if (pluginsDir == null || !pluginsDir.exists()) { return; @@ -86,9 +89,9 @@ protected void installPluginsInPath(String path, AppConfig appConfig, DatabaseCl } makePlugin(dir, appConfig); - final String binaryUri = insertPluginZip(dir, appConfig, client); + final String binaryUri = insertPluginZip(dir, appConfig, clientSupplier.get()); if (binaryUri != null) { - installPlugin(binaryUri, appConfig, client); + installPlugin(binaryUri, appConfig, clientSupplier.get()); } } } @@ -151,7 +154,7 @@ protected void installPlugin(String uri, AppConfig appConfig, DatabaseClient cli logger.info(format("Installed plugin with scope '%s', result: %s", scope, result)); } - protected void uninstallPluginsInPath(String path, AppConfig appConfig, DatabaseClient client) { + protected void uninstallPluginsInPath(String path, AppConfig appConfig, DatabaseClientSupplier clientSupplier) { File pluginsDir = new File(path); if (pluginsDir == null || !pluginsDir.exists()) { return; @@ -166,7 +169,7 @@ protected void uninstallPluginsInPath(String path, AppConfig appConfig, Database final String pluginName = getPluginName(file, appConfig); if (pluginName != null) { - uninstallPlugin(pluginName, appConfig, client); + uninstallPlugin(pluginName, appConfig, clientSupplier.get()); } } } @@ -174,7 +177,7 @@ protected void uninstallPluginsInPath(String path, AppConfig appConfig, Database protected String getPluginName(File dir, AppConfig appConfig) { File manifestFile = new File(dir, "manifest.xml"); - if (manifestFile == null || !manifestFile.exists()) { + if (!manifestFile.exists()) { // Need to make the plugin so the metadata file is guaranteed to exist makePlugin(dir, appConfig); manifestFile = new File(dir, "manifest.xml"); diff --git a/ml-app-deployer/src/main/java/com/marklogic/appdeployer/command/security/InsertCertificateHostsTemplateCommand.java b/ml-app-deployer/src/main/java/com/marklogic/appdeployer/command/security/InsertCertificateHostsTemplateCommand.java index 65872b9e..c7bf940b 100644 --- a/ml-app-deployer/src/main/java/com/marklogic/appdeployer/command/security/InsertCertificateHostsTemplateCommand.java +++ b/ml-app-deployer/src/main/java/com/marklogic/appdeployer/command/security/InsertCertificateHostsTemplateCommand.java @@ -37,10 +37,12 @@ public InsertCertificateHostsTemplateCommand() { @Override public void execute(CommandContext context) { + // A query has to be made to MarkLogic here to get the list of certificate template names, because otherwise, + // we don't know what template names to look for in the user's project directory. List templateNames = new CertificateTemplateManager(context.getManageClient()).getAsXml().getListItemNameRefs(); if (templateNames != null && !templateNames.isEmpty()) { if (logger.isInfoEnabled()) { - logger.info("Looking for host certificates to insert for certificate templates: " + templateNames); + logger.info("Looking for host certificates to insert for certificate templates: {}", templateNames); } for (String templateName : templateNames) { insertHostCertificatesForTemplate(context, templateName); diff --git a/ml-javaclient-util/src/main/java/com/marklogic/client/ext/helper/DatabaseClientSupplier.java b/ml-javaclient-util/src/main/java/com/marklogic/client/ext/helper/DatabaseClientSupplier.java new file mode 100644 index 00000000..53a74826 --- /dev/null +++ b/ml-javaclient-util/src/main/java/com/marklogic/client/ext/helper/DatabaseClientSupplier.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2015-2025 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved. + */ +package com.marklogic.client.ext.helper; + +import com.marklogic.client.DatabaseClient; + +import java.io.Closeable; +import java.util.function.Supplier; + +/** + * Preferred mechanism for lazy instantiation of a DatabaseClient. Will eventually deprecate DatabaseClientProvider in + * favor of this. + * + * @since 6.2.0 + */ +public class DatabaseClientSupplier implements Closeable, Supplier { + + private DatabaseClient databaseClient; + private final Supplier databaseClientSupplier; + + /** + * @param databaseClientSupplier delegates construction of the client to the given supplier. Will then hold onto + * an instance of the client after it's created so that it's only created once. + */ + public DatabaseClientSupplier(Supplier databaseClientSupplier) { + this.databaseClientSupplier = databaseClientSupplier; + } + + public DatabaseClient get() { + if (databaseClient == null) { + databaseClient = databaseClientSupplier.get(); + } + return databaseClient; + } + + @Override + public void close() { + if (databaseClient != null) { + databaseClient.close(); + } + } +}