This is an automated email from the ASF dual-hosted git repository. asf-gitbox-commits pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/cayenne.git
commit ce42b1f871544ec4863fde2da45f699ab18b7313 Author: Andrus Adamchik <[email protected]> AuthorDate: Sun May 24 11:50:54 2026 -0400 CAY-2949 CayenneModeler MCP: dbimport_run tool no need to check for <reveng> section --- cayenne-mcp-server/PROTOCOL.md | 21 +++++---- .../mcp/tools/dbimport/DbImportRunTool.java | 50 +++++++++------------- .../tools/dbimport/protocol/DbImportErrorCode.java | 1 - .../dbimport/protocol/DbImportValidation.java | 3 +- .../cayenne/mcp/tools/dbimport/DbImportRunIT.java | 1 - .../mcp/tools/dbimport/DbImportRunMcpIT.java | 3 -- .../tools/dbimport/DbImportRunValidationTest.java | 18 ++++---- 7 files changed, 39 insertions(+), 58 deletions(-) diff --git a/cayenne-mcp-server/PROTOCOL.md b/cayenne-mcp-server/PROTOCOL.md index 4842929dc..b5d78d764 100644 --- a/cayenne-mcp-server/PROTOCOL.md +++ b/cayenne-mcp-server/PROTOCOL.md @@ -64,7 +64,7 @@ Both fields are required. ## `dbimport_run` -Runs Cayenne reverse-engineering (dbimport) for a named DataMap. Reads the `<reverse-engineering>` filter config from the DataMap XML and reads JDBC connection info from the DBConnector that CayenneModeler stored in preferences for this DataMap. Rewrites the DataMap XML on disk with the merged schema. +Runs Cayenne reverse-engineering (dbimport) for a named DataMap. Reads JDBC connection info from the DBConnector that CayenneModeler stored in preferences for this DataMap. If the DataMap has a `<reverse-engineering>` block its filters are applied; otherwise the full database schema is imported. Rewrites the DataMap XML on disk with the merged schema. ### Input @@ -75,7 +75,7 @@ Runs Cayenne reverse-engineering (dbimport) for a named DataMap. Reads the `<rev } ``` -Both fields are required. JDBC URL, driver, credentials, and schema filters are not inputs — they come from CayenneModeler preferences and the DataMap's `<reverse-engineering>` block respectively. +Both fields are required. JDBC URL, driver, and credentials are not inputs — they come from CayenneModeler preferences. Schema filters come from the DataMap's `<reverse-engineering>` block if present. ### Output @@ -98,15 +98,14 @@ Both fields are required. JDBC URL, driver, credentials, and schema filters are }, "warnings": ["string (captured WARN-level log lines from org.apache.cayenne.dbsync)"], "validation": { - "projectFound": true, - "dataMapFound": true, - "reverseEngineeringConfigPresent": true, - "dbConnectorPresent": true, - "jdbcDriverLoadable": true, - "jdbcConnectionOpened": true + "projectFound": true, + "dataMapFound": true, + "dbConnectorPresent": true, + "jdbcDriverLoadable": true, + "jdbcConnectionOpened": true }, "error": { - "code": "project_not_found | project_parse_failed | datamap_not_found | reverse_engineering_config_missing | dbconnector_not_configured | jdbc_driver_not_loadable | jdbc_connection_failed | dbimport_runtime_error", + "code": "project_not_found | project_parse_failed | datamap_not_found | dbconnector_not_configured | jdbc_driver_not_loadable | jdbc_connection_failed | dbimport_runtime_error", "message": "string" } } @@ -119,8 +118,8 @@ Both fields are required. JDBC URL, driver, credentials, and schema filters are - `error` — validation passed but dbimport threw mid-run; `summary` reflects counters captured before the failure `resolved` notes: -- Populated as soon as the connector is resolved (validation step 5), so it is present even on `jdbc_driver_not_loadable` and `jdbc_connection_failed` failures. -- `null` only when validation fails before the connector is read (steps 1–4). +- Populated as soon as the connector is resolved (validation step 4), so it is present even on `jdbc_driver_not_loadable` and `jdbc_connection_failed` failures. +- `null` only when validation fails before the connector is read (steps 1–3). - Never contains `userName` or `password`. `summary` notes: diff --git a/cayenne-mcp-server/src/main/java/org/apache/cayenne/mcp/tools/dbimport/DbImportRunTool.java b/cayenne-mcp-server/src/main/java/org/apache/cayenne/mcp/tools/dbimport/DbImportRunTool.java index a158ae0ed..a73b10b40 100644 --- a/cayenne-mcp-server/src/main/java/org/apache/cayenne/mcp/tools/dbimport/DbImportRunTool.java +++ b/cayenne-mcp-server/src/main/java/org/apache/cayenne/mcp/tools/dbimport/DbImportRunTool.java @@ -22,13 +22,11 @@ import io.modelcontextprotocol.json.McpJsonMapper; import io.modelcontextprotocol.server.McpServerFeatures; import io.modelcontextprotocol.spec.McpSchema; import org.apache.cayenne.configuration.DataChannelDescriptor; -import org.apache.cayenne.configuration.xml.DataChannelMetaData; import org.apache.cayenne.datasource.DriverDataSource; import org.apache.cayenne.dbsync.DbSyncModule; import org.apache.cayenne.dbsync.reverse.configuration.ToolsModule; import org.apache.cayenne.dbsync.reverse.dbimport.DbImportConfiguration; import org.apache.cayenne.dbsync.reverse.dbimport.DbImportModule; -import org.apache.cayenne.dbsync.reverse.dbimport.ReverseEngineering; import org.apache.cayenne.di.DIBootstrap; import org.apache.cayenne.di.Injector; import org.apache.cayenne.map.DataMap; @@ -68,9 +66,10 @@ import java.util.stream.Collectors; /** * MCP tool that runs Cayenne dbimport for a single DataMap inside a Cayenne project. - * Reads reverse-engineering filter config from the DataMap's {@code <reverse-engineering>} - * block and JDBC connection info from the DBConnector stored in CayenneModeler preferences - * for this DataMap. Returns a structured JSON summary of what changed. + * Reads JDBC connection info from the DBConnector stored in CayenneModeler preferences for + * this DataMap. If the DataMap has a {@code <reverse-engineering>} block its filters are + * applied; otherwise the full database schema is imported. Returns a structured JSON summary + * of what changed. * * @since 5.0 */ @@ -106,11 +105,12 @@ public class DbImportRunTool { NAME, null, """ - Run Cayenne dbimport for a named DataMap. Reads reverse-engineering filters \ - from the DataMap's <reverse-engineering> block and JDBC connection from the \ - DBConnector that CayenneModeler stored for this DataMap. Returns token-count \ - summary and resolved connection metadata; actual schema changes are written \ - to the DataMap XML on disk.""", + Run Cayenne dbimport for a named DataMap. Reads JDBC connection from the \ + DBConnector stored for this DataMap in CayenneModeler preferences. If the \ + DataMap has a <reverse-engineering> block its filters are applied; otherwise \ + the full database schema is imported. Returns token-count summary and \ + resolved connection metadata; actual schema changes are written to the \ + DataMap XML on disk.""", new McpSchema.JsonSchema( "object", Map.of( @@ -157,7 +157,7 @@ public class DbImportRunTool { if (!Files.isReadable(projectFile)) { return validationFailed(DbImportErrorCode.project_not_found, "No readable file at %s".formatted(projectPath), - new DbImportValidation(false, null, null, null, null, null)); + new DbImportValidation(false, null, null, null, null)); } // Step 2 — parses as Cayenne project? @@ -170,7 +170,7 @@ public class DbImportRunTool { } catch (Exception e) { return validationFailed(DbImportErrorCode.project_parse_failed, "Cayenne project loader rejected the descriptor: %s".formatted(e.getMessage()), - new DbImportValidation(true, null, null, null, null, null)); + new DbImportValidation(true, null, null, null, null)); } // Step 3 — DataMap present? @@ -184,23 +184,13 @@ public class DbImportRunTool { return validationFailed(DbImportErrorCode.datamap_not_found, "Project loaded successfully but contains no DataMap named '%s'. Available DataMaps: %s." .formatted(dataMapName, available), - new DbImportValidation(true, false, null, null, null, null)); - } - - // Step 4 — <reverse-engineering> config present? - DataChannelMetaData metaData = injector.getInstance(DataChannelMetaData.class); - ReverseEngineering reverseEngineering = metaData.get(dataMap, ReverseEngineering.class); - if (reverseEngineering == null) { - return validationFailed(DbImportErrorCode.reverse_engineering_config_missing, - "DataMap '%s' has no <reverse-engineering> configuration. Configure dbimport for this DataMap in CayenneModeler before invoking the tool." - .formatted(dataMapName), - new DbImportValidation(true, true, false, null, null, null)); + new DbImportValidation(true, false, null, null, null)); } // Resolve DataMap file path for preference node lookup Path dataMapFile = resolveDataMapFile(dataMap); - // Step 5 — DBConnector stored in preferences? + // Step 4 — DBConnector stored in preferences? String dataMapId = PreferenceNodeIds.idForPath(dataMapFile.toAbsolutePath().toString()); DBConnector connector = new DataMapPrefs(prefsLocator.dataMapNode(dataMapId)).getConnector(); if (connector == null) { @@ -211,7 +201,7 @@ public class DbImportRunTool { choose 'Reengineer Database Schema…', and pick a connection — \ its values will be saved to this DataMap's preferences.\ """.formatted(dataMapName, projectPath), - new DbImportValidation(true, true, true, false, null, null)); + new DbImportValidation(true, true, false, null, null)); } DbImportResolved resolved = new DbImportResolved( @@ -221,7 +211,7 @@ public class DbImportRunTool { connector.getDbAdapter() ); - // Step 6 — JDBC driver loadable from Preferences → Classpath? + // Step 5 — JDBC driver loadable from Preferences → Classpath? ClassLoader driverCl = buildDriverClassLoader(); Driver driver; try { @@ -230,17 +220,17 @@ public class DbImportRunTool { return validationFailed(DbImportErrorCode.jdbc_driver_not_loadable, "JDBC driver class '%s' could not be loaded. In CayenneModeler, open Preferences → Classpath, add the driver jar, then re-run — the MCP server reads the classpath fresh on each call." .formatted(connector.getJdbcDriver()), - new DbImportValidation(true, true, true, true, false, null), + new DbImportValidation(true, true, true, false, null), resolved); } catch (Exception e) { return validationFailed(DbImportErrorCode.jdbc_driver_not_loadable, "JDBC driver class '%s' could not be instantiated: %s" .formatted(connector.getJdbcDriver(), e.getMessage()), - new DbImportValidation(true, true, true, true, false, null), + new DbImportValidation(true, true, true, false, null), resolved); } - // Step 7 — JDBC connection opens? + // Step 6 — JDBC connection opens? Connection conn; try { conn = new DriverDataSource( @@ -254,7 +244,7 @@ public class DbImportRunTool { return validationFailed(DbImportErrorCode.jdbc_connection_failed, "Could not open JDBC connection to '%s' as '%s': %s%s." .formatted(connector.getUrl(), connector.getUserName(), e.getMessage(), sqlState), - new DbImportValidation(true, true, true, true, true, false), + new DbImportValidation(true, true, true, true, false), resolved); } diff --git a/cayenne-mcp-server/src/main/java/org/apache/cayenne/mcp/tools/dbimport/protocol/DbImportErrorCode.java b/cayenne-mcp-server/src/main/java/org/apache/cayenne/mcp/tools/dbimport/protocol/DbImportErrorCode.java index 352a6d351..c7a672f9f 100644 --- a/cayenne-mcp-server/src/main/java/org/apache/cayenne/mcp/tools/dbimport/protocol/DbImportErrorCode.java +++ b/cayenne-mcp-server/src/main/java/org/apache/cayenne/mcp/tools/dbimport/protocol/DbImportErrorCode.java @@ -22,7 +22,6 @@ public enum DbImportErrorCode { project_not_found, project_parse_failed, datamap_not_found, - reverse_engineering_config_missing, dbconnector_not_configured, jdbc_driver_not_loadable, jdbc_connection_failed, diff --git a/cayenne-mcp-server/src/main/java/org/apache/cayenne/mcp/tools/dbimport/protocol/DbImportValidation.java b/cayenne-mcp-server/src/main/java/org/apache/cayenne/mcp/tools/dbimport/protocol/DbImportValidation.java index f869b3f11..e48bc4979 100644 --- a/cayenne-mcp-server/src/main/java/org/apache/cayenne/mcp/tools/dbimport/protocol/DbImportValidation.java +++ b/cayenne-mcp-server/src/main/java/org/apache/cayenne/mcp/tools/dbimport/protocol/DbImportValidation.java @@ -27,10 +27,9 @@ package org.apache.cayenne.mcp.tools.dbimport.protocol; public record DbImportValidation( Boolean projectFound, Boolean dataMapFound, - Boolean reverseEngineeringConfigPresent, Boolean dbConnectorPresent, Boolean jdbcDriverLoadable, Boolean jdbcConnectionOpened ) { - public static final DbImportValidation ALL_PASSED = new DbImportValidation(true, true, true, true, true, true); + public static final DbImportValidation ALL_PASSED = new DbImportValidation(true, true, true, true, true); } diff --git a/cayenne-mcp-server/src/test/java/org/apache/cayenne/mcp/tools/dbimport/DbImportRunIT.java b/cayenne-mcp-server/src/test/java/org/apache/cayenne/mcp/tools/dbimport/DbImportRunIT.java index caf34e10b..4f5100445 100644 --- a/cayenne-mcp-server/src/test/java/org/apache/cayenne/mcp/tools/dbimport/DbImportRunIT.java +++ b/cayenne-mcp-server/src/test/java/org/apache/cayenne/mcp/tools/dbimport/DbImportRunIT.java @@ -115,7 +115,6 @@ public class DbImportRunIT { assertTrue(result.validation().projectFound()); assertTrue(result.validation().dataMapFound()); - assertTrue(result.validation().reverseEngineeringConfigPresent()); assertTrue(result.validation().dbConnectorPresent()); assertTrue(result.validation().jdbcDriverLoadable()); assertTrue(result.validation().jdbcConnectionOpened()); diff --git a/cayenne-mcp-server/src/test/java/org/apache/cayenne/mcp/tools/dbimport/DbImportRunMcpIT.java b/cayenne-mcp-server/src/test/java/org/apache/cayenne/mcp/tools/dbimport/DbImportRunMcpIT.java index 10ffa610e..13bbef7f3 100644 --- a/cayenne-mcp-server/src/test/java/org/apache/cayenne/mcp/tools/dbimport/DbImportRunMcpIT.java +++ b/cayenne-mcp-server/src/test/java/org/apache/cayenne/mcp/tools/dbimport/DbImportRunMcpIT.java @@ -144,7 +144,6 @@ public class DbImportRunMcpIT { "validation" : { "projectFound" : false, "dataMapFound" : null, - "reverseEngineeringConfigPresent" : null, "dbConnectorPresent" : null, "jdbcDriverLoadable" : null, "jdbcConnectionOpened" : null @@ -184,7 +183,6 @@ public class DbImportRunMcpIT { "validation" : { "projectFound" : true, "dataMapFound" : true, - "reverseEngineeringConfigPresent" : true, "dbConnectorPresent" : true, "jdbcDriverLoadable" : true, "jdbcConnectionOpened" : true @@ -225,7 +223,6 @@ public class DbImportRunMcpIT { "validation" : { "projectFound" : true, "dataMapFound" : true, - "reverseEngineeringConfigPresent" : true, "dbConnectorPresent" : true, "jdbcDriverLoadable" : true, "jdbcConnectionOpened" : true diff --git a/cayenne-mcp-server/src/test/java/org/apache/cayenne/mcp/tools/dbimport/DbImportRunValidationTest.java b/cayenne-mcp-server/src/test/java/org/apache/cayenne/mcp/tools/dbimport/DbImportRunValidationTest.java index c4f09307c..0c13205f7 100644 --- a/cayenne-mcp-server/src/test/java/org/apache/cayenne/mcp/tools/dbimport/DbImportRunValidationTest.java +++ b/cayenne-mcp-server/src/test/java/org/apache/cayenne/mcp/tools/dbimport/DbImportRunValidationTest.java @@ -70,7 +70,6 @@ public class DbImportRunValidationTest { assertEquals(DbImportErrorCode.project_not_found, result.error().code()); assertFalse(result.validation().projectFound()); assertNull(result.validation().dataMapFound()); - assertNull(result.validation().reverseEngineeringConfigPresent()); assertNull(result.validation().dbConnectorPresent()); assertNull(result.validation().jdbcDriverLoadable()); assertNull(result.validation().jdbcConnectionOpened()); @@ -89,7 +88,6 @@ public class DbImportRunValidationTest { assertEquals(DbImportErrorCode.project_parse_failed, result.error().code()); assertTrue(result.validation().projectFound()); assertNull(result.validation().dataMapFound()); - assertNull(result.validation().reverseEngineeringConfigPresent()); assertNull(result.validation().dbConnectorPresent()); assertNull(result.validation().jdbcDriverLoadable()); assertNull(result.validation().jdbcConnectionOpened()); @@ -108,7 +106,6 @@ public class DbImportRunValidationTest { assertTrue(result.error().message().contains("TestMap"), "Available maps should be listed"); assertTrue(result.validation().projectFound()); assertFalse(result.validation().dataMapFound()); - assertNull(result.validation().reverseEngineeringConfigPresent()); assertNull(result.validation().dbConnectorPresent()); assertNull(result.validation().jdbcDriverLoadable()); assertNull(result.validation().jdbcConnectionOpened()); @@ -116,17 +113,19 @@ public class DbImportRunValidationTest { } @Test - public void reverseEngineeringConfigMissing() throws URISyntaxException { - String projectPath = fixtureProject("no-dbimport"); + public void noReverseEngineeringProceedsThroughToConnectorCheck(@TempDir Path tmp) throws IOException { + Path projectFile = copyFixture("no-dbimport", tmp); + Preferences isolatedRoot = isolatedPrefsRoot(); - DbImportRunResult result = tool.run(projectPath, "TestMap"); + DbImportRunTool isolatedTool = new DbImportRunTool(new PrefsLocator(isolatedRoot)); + DbImportRunResult result = isolatedTool.run(projectFile.toString(), "TestMap"); + // Should not fail on missing reverse-engineering — proceeds to connector check instead assertEquals("validation_failed", result.status()); - assertEquals(DbImportErrorCode.reverse_engineering_config_missing, result.error().code()); + assertEquals(DbImportErrorCode.dbconnector_not_configured, result.error().code()); assertTrue(result.validation().projectFound()); assertTrue(result.validation().dataMapFound()); - assertFalse(result.validation().reverseEngineeringConfigPresent()); - assertNull(result.validation().dbConnectorPresent()); + assertFalse(result.validation().dbConnectorPresent()); assertNull(result.validation().jdbcDriverLoadable()); assertNull(result.validation().jdbcConnectionOpened()); assertNoCredentialsInResult(result); @@ -145,7 +144,6 @@ public class DbImportRunValidationTest { assertEquals(DbImportErrorCode.dbconnector_not_configured, result.error().code()); assertTrue(result.validation().projectFound()); assertTrue(result.validation().dataMapFound()); - assertTrue(result.validation().reverseEngineeringConfigPresent()); assertFalse(result.validation().dbConnectorPresent()); assertNull(result.validation().jdbcDriverLoadable()); assertNull(result.validation().jdbcConnectionOpened());
