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 488009ac220f5c2a74f73a3b0ac6211d46c1fc5e Author: Andrus Adamchik <[email protected]> AuthorDate: Sat May 23 17:08:59 2026 -0400 CAY-2949 CayenneModeler MCP: dbimport_run tool preliminary refactoring - sharing preferences between MCP and the Modeler --- cayenne-mcp-server/pom.xml | 6 + .../org/apache/cayenne/mcp/CayenneMcpServer.java | 4 +- .../apache/cayenne/mcp/tools/cgen/CgenRunTool.java | 2 +- .../mcp/tools/openproject/HandshakeWatcher.java | 64 +++-- .../mcp/tools/openproject/OpenProjectTool.java | 14 +- .../tools/openproject/HandshakeWatcherTest.java | 40 ++- .../mcp/tools/openproject/OpenProjectStubIT.java | 3 +- .../openproject/OpenProjectValidationTest.java | 3 +- modeler/cayenne-modeler-prefs/pom.xml | 49 ++++ .../apache/cayenne/modeler/pref/PrefsAdapter.java} | 4 +- .../apache/cayenne/modeler/pref/PrefsLocator.java | 39 ++- .../modeler/pref/adapters/ClasspathPrefs.java | 12 +- .../modeler/pref/adapters/DBConnectorPrefs.java | 8 +- .../modeler/pref/dbconnector/DBConnector.java | 150 +++++++++++ .../modeler/pref}/dbconnector/DBConnectors.java | 2 +- modeler/cayenne-modeler/pom.xml | 47 ++-- .../org/apache/cayenne/modeler/Application.java | 4 +- .../cayenne/modeler/dbconnector/DBConnector.java | 277 --------------------- .../modeler/dbconnector/DBConnectorFactory.java | 156 ++++++++++++ .../modeler/pref/adapters/CMTablePrefs.java | 4 +- .../pref/adapters/ComponentGeometryPrefs.java | 4 +- .../modeler/pref/adapters/DBGeneratorPrefs.java | 4 +- .../modeler/pref/adapters/DataMapPrefs.java | 6 +- .../modeler/pref/adapters/DataNodePrefs.java | 4 +- .../modeler/pref/adapters/FileChooserPrefs.java | 4 +- .../modeler/pref/adapters/GeneralPrefs.java | 4 +- .../modeler/pref/adapters/LogConsolePrefs.java | 4 +- .../modeler/pref/adapters/ProjectPrefs.java | 4 +- .../modeler/pref/adapters/RecentProjectsPrefs.java | 4 +- .../modeler/pref/adapters/SplitPanePrefs.java | 4 +- .../modeler/ui/action/DBConnectionAwareAction.java | 2 +- .../modeler/ui/datasource/DataSourceDialog.java | 10 +- .../modeler/ui/dbgen/DBGeneratorOptionsDialog.java | 6 +- .../modeler/ui/dbmerge/MergerOptionsDialog.java | 9 +- .../preferences/dbconnector/DBConnectorEditor.java | 2 +- .../dbconnector/DBConnectorPrefsPanel.java | 4 +- .../creator/DBConnectorCreatorDialog.java | 2 +- .../duplicator/DBConnectorDuplicatorDialog.java | 2 +- .../datamap/dbimport/DatabaseSchemaLoader.java | 13 +- .../dbimport/action/LoadDbSchemaAction.java | 2 +- .../dbimport/action/ModelerDbImportAction.java | 5 +- .../dbimport/runner/ModelerDbLoaderContext.java | 7 +- .../editor/datanode/DataNodeEditorPanel.java | 2 +- .../editor/datanode/jdbc/JDBCDataSourcePanel.java | 2 +- modeler/pom.xml | 1 + 45 files changed, 555 insertions(+), 444 deletions(-) diff --git a/cayenne-mcp-server/pom.xml b/cayenne-mcp-server/pom.xml index 7eca6077f..cf8f52b54 100644 --- a/cayenne-mcp-server/pom.xml +++ b/cayenne-mcp-server/pom.xml @@ -44,6 +44,12 @@ <artifactId>mcp</artifactId> </dependency> + <dependency> + <groupId>org.apache.cayenne.modeler</groupId> + <artifactId>cayenne-modeler-prefs</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> <groupId>org.apache.cayenne</groupId> <artifactId>cayenne-cgen</artifactId> diff --git a/cayenne-mcp-server/src/main/java/org/apache/cayenne/mcp/CayenneMcpServer.java b/cayenne-mcp-server/src/main/java/org/apache/cayenne/mcp/CayenneMcpServer.java index 6755fb5de..f0eb6971d 100644 --- a/cayenne-mcp-server/src/main/java/org/apache/cayenne/mcp/CayenneMcpServer.java +++ b/cayenne-mcp-server/src/main/java/org/apache/cayenne/mcp/CayenneMcpServer.java @@ -24,6 +24,7 @@ import io.modelcontextprotocol.server.McpServer; import io.modelcontextprotocol.server.McpSyncServer; import io.modelcontextprotocol.server.transport.StdioServerTransportProvider; import io.modelcontextprotocol.spec.McpSchema; +import org.apache.cayenne.modeler.pref.PrefsLocator; import org.apache.cayenne.mcp.tools.cgen.CgenRunTool; import org.apache.cayenne.mcp.tools.openproject.OpenProjectTool; import org.slf4j.Logger; @@ -49,12 +50,13 @@ public class CayenneMcpServer { .get(); StdioServerTransportProvider transport = new StdioServerTransportProvider(jsonMapper, in, out); + PrefsLocator prefsLocator = new PrefsLocator(); McpSyncServer server = McpServer.sync(transport) .serverInfo("cayenne-mcp-server", version) .capabilities(McpSchema.ServerCapabilities.builder().tools(true).build()) .tools(CgenRunTool.spec(jsonMapper)) - .tools(OpenProjectTool.spec(jsonMapper)) + .tools(OpenProjectTool.spec(jsonMapper, prefsLocator)) .build(); Runtime.getRuntime().addShutdownHook(new Thread(() -> { diff --git a/cayenne-mcp-server/src/main/java/org/apache/cayenne/mcp/tools/cgen/CgenRunTool.java b/cayenne-mcp-server/src/main/java/org/apache/cayenne/mcp/tools/cgen/CgenRunTool.java index 50a247a79..2f766baab 100644 --- a/cayenne-mcp-server/src/main/java/org/apache/cayenne/mcp/tools/cgen/CgenRunTool.java +++ b/cayenne-mcp-server/src/main/java/org/apache/cayenne/mcp/tools/cgen/CgenRunTool.java @@ -166,7 +166,7 @@ public class CgenRunTool { + "Configure code generation for this DataMap in CayenneModeler before invoking the tool.", new CgenValidation(true, true, false, null, null)); } - CgenConfiguration cgenConfig = configList.getAll().get(0); + CgenConfiguration cgenConfig = configList.getAll().getFirst(); // Step 5 — destDir specified? Path destDir = cgenConfig.buildOutputPath(); diff --git a/cayenne-mcp-server/src/main/java/org/apache/cayenne/mcp/tools/openproject/HandshakeWatcher.java b/cayenne-mcp-server/src/main/java/org/apache/cayenne/mcp/tools/openproject/HandshakeWatcher.java index 041bbc448..358987f4b 100644 --- a/cayenne-mcp-server/src/main/java/org/apache/cayenne/mcp/tools/openproject/HandshakeWatcher.java +++ b/cayenne-mcp-server/src/main/java/org/apache/cayenne/mcp/tools/openproject/HandshakeWatcher.java @@ -18,6 +18,7 @@ ****************************************************************/ package org.apache.cayenne.mcp.tools.openproject; +import org.apache.cayenne.modeler.pref.PrefsLocator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -35,21 +36,20 @@ import java.util.prefs.Preferences; * * @since 5.0 */ -final class HandshakeWatcher { +class HandshakeWatcher { private static final Logger LOGGER = LoggerFactory.getLogger(HandshakeWatcher.class); - /** Must match {@code McpHandshakeWriter.NODE_PREFIX} on the Modeler side. */ - static final String NODE_PREFIX = "/org/apache/cayenne/modeler/mcp-handshake"; - private static final long POLL_INTERVAL_MS = 200L; private static final Duration STALE_NODE_TTL = Duration.ofHours(24); - enum Outcome { HANDSHAKE_RECEIVED, SPAWNED_PROCESS_EXITED, TIMEOUT } + enum Outcome {HANDSHAKE_RECEIVED, SPAWNED_PROCESS_EXITED, TIMEOUT} - record WatchResult(Outcome outcome, HandshakeData data, long waitMs) {} + record WatchResult(Outcome outcome, HandshakeData data, long waitMs) { + } - record HandshakeData(long pid, String startedAt, String resolvedProjectPath) {} + record HandshakeData(long pid, String startedAt, String resolvedProjectPath) { + } private HandshakeWatcher() { } @@ -59,16 +59,20 @@ final class HandshakeWatcher { * the spawned process exits (when that signal is meaningful) or the timeout is hit. * Regardless of outcome, the nonce's subnode is removed and stale siblings are pruned. */ - static WatchResult await(String nonce, BooleanSupplier spawnedProcessAlive, Duration timeout) { + public static WatchResult await( + String nonce, + BooleanSupplier spawnedProcessAlive, + Duration timeout, + PrefsLocator locator) { + long start = System.currentTimeMillis(); long deadline = start + timeout.toMillis(); - String nodePath = NODE_PREFIX + "/" + nonce; - WatchResult result = null; + WatchResult result; try { while (true) { - if (nodeExists(nodePath)) { - HandshakeData data = readHandshake(nodePath); + if (locator.handshakeNodeExists(nonce)) { + HandshakeData data = readHandshake(locator.handshakeNode(nonce)); long waitMs = System.currentTimeMillis() - start; result = new WatchResult(Outcome.HANDSHAKE_RECEIVED, data, waitMs); break; @@ -96,36 +100,26 @@ final class HandshakeWatcher { } } } finally { - removeNode(nodePath); - pruneStaleSiblings(); + removeNode(locator, nonce); + pruneStaleSiblings(locator); } return result; } - private static boolean nodeExists(String absolutePath) { - try { - return Preferences.userRoot().nodeExists(absolutePath); - } catch (BackingStoreException e) { - LOGGER.warn("Failed to query preferences for {}: {}", absolutePath, e.toString()); - return false; - } - } - - private static HandshakeData readHandshake(String absolutePath) { - Preferences node = Preferences.userRoot().node(absolutePath); + private static HandshakeData readHandshake(Preferences node) { long pid = node.getLong("pid", -1L); String startedAt = node.get("startedAt", null); String resolvedProjectPath = node.get("projectPath", null); return new HandshakeData(pid, startedAt, resolvedProjectPath); } - private static void removeNode(String absolutePath) { + private static void removeNode(PrefsLocator locator, String nonce) { try { - if (Preferences.userRoot().nodeExists(absolutePath)) { - Preferences.userRoot().node(absolutePath).removeNode(); + if (locator.handshakeNodeExists(nonce)) { + locator.handshakeNode(nonce).removeNode(); } } catch (BackingStoreException | IllegalStateException e) { - LOGGER.warn("Failed to remove handshake node {}: {}", absolutePath, e.toString()); + LOGGER.warn("Failed to remove handshake node for nonce {}: {}", nonce, e.toString()); } } @@ -134,13 +128,13 @@ final class HandshakeWatcher { * Belt-and-suspenders cleanup against an MCP server that crashed between launching * the Modeler and reading the handshake. */ - private static void pruneStaleSiblings() { + private static void pruneStaleSiblings(PrefsLocator locator) { + if (!locator.handshakeRootNodeExists()) { + return; + } + try { - Preferences root = Preferences.userRoot(); - if (!root.nodeExists(NODE_PREFIX)) { - return; - } - Preferences parent = root.node(NODE_PREFIX); + Preferences parent = locator.handshakeRootNode(); Instant cutoff = Instant.now().minus(STALE_NODE_TTL); for (String child : parent.childrenNames()) { Preferences childNode = parent.node(child); diff --git a/cayenne-mcp-server/src/main/java/org/apache/cayenne/mcp/tools/openproject/OpenProjectTool.java b/cayenne-mcp-server/src/main/java/org/apache/cayenne/mcp/tools/openproject/OpenProjectTool.java index ced9e3a21..82de61236 100644 --- a/cayenne-mcp-server/src/main/java/org/apache/cayenne/mcp/tools/openproject/OpenProjectTool.java +++ b/cayenne-mcp-server/src/main/java/org/apache/cayenne/mcp/tools/openproject/OpenProjectTool.java @@ -34,6 +34,8 @@ import org.apache.cayenne.mcp.tools.openproject.protocol.OpenProjectResolved; import org.apache.cayenne.mcp.tools.openproject.protocol.OpenProjectResult; import org.apache.cayenne.mcp.tools.openproject.protocol.OpenProjectValidation; +import org.apache.cayenne.modeler.pref.PrefsLocator; + import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -57,8 +59,14 @@ public class OpenProjectTool { static final Duration HANDSHAKE_TIMEOUT = Duration.ofSeconds(15); - public static McpServerFeatures.SyncToolSpecification spec(McpJsonMapper jsonMapper) { - OpenProjectTool tool = new OpenProjectTool(); + private final PrefsLocator prefsLocator; + + public OpenProjectTool(PrefsLocator prefsLocator) { + this.prefsLocator = prefsLocator; + } + + public static McpServerFeatures.SyncToolSpecification spec(McpJsonMapper jsonMapper, PrefsLocator prefsLocator) { + OpenProjectTool tool = new OpenProjectTool(prefsLocator); McpSchema.Tool descriptor = new McpSchema.Tool( NAME, @@ -172,7 +180,7 @@ public class OpenProjectTool { launch.command()); // Step 5 — wait for the handshake. - WatchResult watch = HandshakeWatcher.await(nonce, () -> true, HANDSHAKE_TIMEOUT); + WatchResult watch = HandshakeWatcher.await(nonce, () -> true, HANDSHAKE_TIMEOUT, prefsLocator); return switch (watch.outcome()) { case HANDSHAKE_RECEIVED -> { diff --git a/cayenne-mcp-server/src/test/java/org/apache/cayenne/mcp/tools/openproject/HandshakeWatcherTest.java b/cayenne-mcp-server/src/test/java/org/apache/cayenne/mcp/tools/openproject/HandshakeWatcherTest.java index a429405a6..ea553fa17 100644 --- a/cayenne-mcp-server/src/test/java/org/apache/cayenne/mcp/tools/openproject/HandshakeWatcherTest.java +++ b/cayenne-mcp-server/src/test/java/org/apache/cayenne/mcp/tools/openproject/HandshakeWatcherTest.java @@ -18,6 +18,7 @@ ****************************************************************/ package org.apache.cayenne.mcp.tools.openproject; +import org.apache.cayenne.modeler.pref.PrefsLocator; import org.apache.cayenne.mcp.tools.openproject.HandshakeWatcher.Outcome; import org.apache.cayenne.mcp.tools.openproject.HandshakeWatcher.WatchResult; import org.junit.jupiter.api.AfterEach; @@ -40,27 +41,25 @@ import static org.junit.jupiter.api.Assertions.assertTrue; public class HandshakeWatcherTest { private static final BooleanSupplier ALIVE = () -> true; + private static final PrefsLocator LOCATOR = new PrefsLocator(); private final String nonce = "test-" + UUID.randomUUID().toString().replace("-", ""); @AfterEach public void cleanup() throws BackingStoreException { - Preferences root = Preferences.userRoot(); - if (root.nodeExists(HandshakeWatcher.NODE_PREFIX + "/" + nonce)) { - root.node(HandshakeWatcher.NODE_PREFIX + "/" + nonce).removeNode(); + if (LOCATOR.handshakeNodeExists(nonce)) { + LOCATOR.handshakeNode(nonce).removeNode(); } } @Test public void handshakeReceivedReadsPidAndPath() throws BackingStoreException { - Preferences node = Preferences - .userRoot() - .node(HandshakeWatcher.NODE_PREFIX + "/" + nonce); + Preferences node = LOCATOR.handshakeNode(nonce); node.putLong("pid", 4242L); node.put("startedAt", "2026-05-17T10:00:00Z"); node.put("projectPath", "/abs/cayenne-project.xml"); node.flush(); - WatchResult result = HandshakeWatcher.await(nonce, ALIVE, Duration.ofSeconds(2)); + WatchResult result = HandshakeWatcher.await(nonce, ALIVE, Duration.ofSeconds(2), LOCATOR); assertEquals(Outcome.HANDSHAKE_RECEIVED, result.outcome()); assertNotNull(result.data()); @@ -70,12 +69,12 @@ public class HandshakeWatcherTest { assertTrue(result.waitMs() >= 0); // Watcher must remove the node after reading. - assertFalse(Preferences.userRoot().nodeExists(HandshakeWatcher.NODE_PREFIX + "/" + nonce)); + assertFalse(LOCATOR.handshakeNodeExists(nonce)); } @Test public void timeoutOnMissingHandshake() { - WatchResult result = HandshakeWatcher.await(nonce, ALIVE, Duration.ofMillis(400)); + WatchResult result = HandshakeWatcher.await(nonce, ALIVE, Duration.ofMillis(400), LOCATOR); assertEquals(Outcome.TIMEOUT, result.outcome()); assertNull(result.data()); @@ -97,7 +96,7 @@ public class HandshakeWatcherTest { }, "test-killer").start(); long start = System.currentTimeMillis(); - WatchResult result = HandshakeWatcher.await(nonce, alive::get, Duration.ofSeconds(10)); + WatchResult result = HandshakeWatcher.await(nonce, alive::get, Duration.ofSeconds(10), LOCATOR); long elapsed = System.currentTimeMillis() - start; assertEquals(Outcome.SPAWNED_PROCESS_EXITED, result.outcome()); @@ -111,30 +110,27 @@ public class HandshakeWatcherTest { String freshNonce = "test-fresh-" + UUID.randomUUID().toString().replace("-", ""); String staleNonce = "test-stale-" + UUID.randomUUID().toString().replace("-", ""); try { - Preferences fresh = Preferences.userRoot() - .node(HandshakeWatcher.NODE_PREFIX + "/" + freshNonce); + Preferences fresh = LOCATOR.handshakeNode(freshNonce); fresh.put("startedAt", Instant.now().toString()); fresh.flush(); - Preferences stale = Preferences.userRoot() - .node(HandshakeWatcher.NODE_PREFIX + "/" + staleNonce); + Preferences stale = LOCATOR.handshakeNode(staleNonce); stale.put("startedAt", Instant.now().minus(Duration.ofDays(2)).toString()); stale.flush(); // Trigger pruning by running the watcher with a missing-handshake nonce. - HandshakeWatcher.await(nonce, ALIVE, Duration.ofMillis(200)); + HandshakeWatcher.await(nonce, ALIVE, Duration.ofMillis(200), LOCATOR); - assertTrue(Preferences.userRoot().nodeExists(HandshakeWatcher.NODE_PREFIX + "/" + freshNonce), + assertTrue(LOCATOR.handshakeNodeExists(freshNonce), "Recent sibling must be preserved"); - assertFalse(Preferences.userRoot().nodeExists(HandshakeWatcher.NODE_PREFIX + "/" + staleNonce), + assertFalse(LOCATOR.handshakeNodeExists(staleNonce), "Stale sibling must be pruned"); } finally { - Preferences root = Preferences.userRoot(); - if (root.nodeExists(HandshakeWatcher.NODE_PREFIX + "/" + freshNonce)) { - root.node(HandshakeWatcher.NODE_PREFIX + "/" + freshNonce).removeNode(); + if (LOCATOR.handshakeNodeExists(freshNonce)) { + LOCATOR.handshakeNode(freshNonce).removeNode(); } - if (root.nodeExists(HandshakeWatcher.NODE_PREFIX + "/" + staleNonce)) { - root.node(HandshakeWatcher.NODE_PREFIX + "/" + staleNonce).removeNode(); + if (LOCATOR.handshakeNodeExists(staleNonce)) { + LOCATOR.handshakeNode(staleNonce).removeNode(); } } } diff --git a/cayenne-mcp-server/src/test/java/org/apache/cayenne/mcp/tools/openproject/OpenProjectStubIT.java b/cayenne-mcp-server/src/test/java/org/apache/cayenne/mcp/tools/openproject/OpenProjectStubIT.java index 72a3a9919..6a32d24f9 100644 --- a/cayenne-mcp-server/src/test/java/org/apache/cayenne/mcp/tools/openproject/OpenProjectStubIT.java +++ b/cayenne-mcp-server/src/test/java/org/apache/cayenne/mcp/tools/openproject/OpenProjectStubIT.java @@ -18,6 +18,7 @@ ****************************************************************/ package org.apache.cayenne.mcp.tools.openproject; +import org.apache.cayenne.modeler.pref.PrefsLocator; import org.apache.cayenne.mcp.tools.openproject.HandshakeWatcher.Outcome; import org.apache.cayenne.mcp.tools.openproject.HandshakeWatcher.WatchResult; import org.apache.cayenne.mcp.tools.openproject.ModelerLauncher.LaunchResult; @@ -59,7 +60,7 @@ public class OpenProjectStubIT { try { WatchResult watch = HandshakeWatcher.await( - nonce, () -> launch.process().isAlive(), Duration.ofSeconds(15)); + nonce, () -> launch.process().isAlive(), Duration.ofSeconds(15), new PrefsLocator()); assertEquals(Outcome.HANDSHAKE_RECEIVED, watch.outcome(), "expected stub to write handshake within 15s"); diff --git a/cayenne-mcp-server/src/test/java/org/apache/cayenne/mcp/tools/openproject/OpenProjectValidationTest.java b/cayenne-mcp-server/src/test/java/org/apache/cayenne/mcp/tools/openproject/OpenProjectValidationTest.java index f17c91057..b13e12c2a 100644 --- a/cayenne-mcp-server/src/test/java/org/apache/cayenne/mcp/tools/openproject/OpenProjectValidationTest.java +++ b/cayenne-mcp-server/src/test/java/org/apache/cayenne/mcp/tools/openproject/OpenProjectValidationTest.java @@ -18,6 +18,7 @@ ****************************************************************/ package org.apache.cayenne.mcp.tools.openproject; +import org.apache.cayenne.modeler.pref.PrefsLocator; import org.apache.cayenne.mcp.tools.openproject.protocol.OpenProjectErrorCode; import org.apache.cayenne.mcp.tools.openproject.protocol.OpenProjectResult; import org.junit.jupiter.api.Test; @@ -28,7 +29,7 @@ import static org.junit.jupiter.api.Assertions.assertNull; public class OpenProjectValidationTest { - private final OpenProjectTool tool = new OpenProjectTool(); + private final OpenProjectTool tool = new OpenProjectTool(new PrefsLocator()); @Test public void projectNotFound() { diff --git a/modeler/cayenne-modeler-prefs/pom.xml b/modeler/cayenne-modeler-prefs/pom.xml new file mode 100644 index 000000000..174e489d3 --- /dev/null +++ b/modeler/cayenne-modeler-prefs/pom.xml @@ -0,0 +1,49 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.apache.cayenne.modeler</groupId> + <artifactId>cayenne-modeler-parent</artifactId> + <version>5.0-SNAPSHOT</version> + </parent> + + <artifactId>cayenne-modeler-prefs</artifactId> + <name>cayenne-modeler-prefs: Shared Modeler Preferences API</name> + <packaging>jar</packaging> + + <dependencies> + <dependency> + <groupId>org.apache.cayenne</groupId> + <artifactId>cayenne</artifactId> + <version>${project.version}</version> + </dependency> + + <!-- Test dependencies --> + <dependency> + <groupId>org.junit.jupiter</groupId> + <artifactId>junit-jupiter</artifactId> + <scope>test</scope> + </dependency> + </dependencies> +</project> diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/PreferenceAdapter.java b/modeler/cayenne-modeler-prefs/src/main/java/org/apache/cayenne/modeler/pref/PrefsAdapter.java similarity index 92% rename from modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/PreferenceAdapter.java rename to modeler/cayenne-modeler-prefs/src/main/java/org/apache/cayenne/modeler/pref/PrefsAdapter.java index ce0667f25..3fb1d3952 100644 --- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/PreferenceAdapter.java +++ b/modeler/cayenne-modeler-prefs/src/main/java/org/apache/cayenne/modeler/pref/PrefsAdapter.java @@ -24,11 +24,11 @@ import java.util.prefs.Preferences; /** * Superclass of objects linking preferences with components. */ -public abstract class PreferenceAdapter { +public abstract class PrefsAdapter { protected final Preferences prefs; - protected PreferenceAdapter(Preferences prefs) { + protected PrefsAdapter(Preferences prefs) { this.prefs = prefs; } } diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/PrefsLocator.java b/modeler/cayenne-modeler-prefs/src/main/java/org/apache/cayenne/modeler/pref/PrefsLocator.java similarity index 75% rename from modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/PrefsLocator.java rename to modeler/cayenne-modeler-prefs/src/main/java/org/apache/cayenne/modeler/pref/PrefsLocator.java index a466ddf40..73897618f 100644 --- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/PrefsLocator.java +++ b/modeler/cayenne-modeler-prefs/src/main/java/org/apache/cayenne/modeler/pref/PrefsLocator.java @@ -18,6 +18,7 @@ ****************************************************************/ package org.apache.cayenne.modeler.pref; +import java.util.prefs.BackingStoreException; import java.util.prefs.Preferences; /** @@ -82,13 +83,39 @@ public final class PrefsLocator { return root.node(DATAMAP_ROOT).node(dataMapId); } - /** - * Returns the per-nonce node under the MCP launch-handshake namespace - * ({@code org/apache/cayenne/modeler/mcp-handshake/<nonce>}). This subtree - * is intentionally a sibling of {@link #modelerRoot()} so that Modeler-wide - * resets do not clobber in-flight handshakes. - */ public Preferences handshakeNode(String nonce) { return root.node(HANDSHAKE_ROOT).node(nonce); } + + /** + * Returns the handshake namespace root node. Only call this after confirming the + * node exists via {@link #handshakeRootNodeExists()}. + */ + public Preferences handshakeRootNode() { + return root.node(HANDSHAKE_ROOT); + } + + /** + * Returns {@code true} if the per-nonce handshake node exists without creating it. + * Returns {@code false} if the backing store cannot be queried. + */ + public boolean handshakeNodeExists(String nonce) { + try { + return root.nodeExists(HANDSHAKE_ROOT + "/" + nonce); + } catch (BackingStoreException e) { + return false; + } + } + + /** + * Returns {@code true} if the handshake namespace root node exists without creating it. + * Returns {@code false} if the backing store cannot be queried. + */ + public boolean handshakeRootNodeExists() { + try { + return root.nodeExists(HANDSHAKE_ROOT); + } catch (BackingStoreException e) { + return false; + } + } } diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/adapters/ClasspathPrefs.java b/modeler/cayenne-modeler-prefs/src/main/java/org/apache/cayenne/modeler/pref/adapters/ClasspathPrefs.java similarity index 88% rename from modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/adapters/ClasspathPrefs.java rename to modeler/cayenne-modeler-prefs/src/main/java/org/apache/cayenne/modeler/pref/adapters/ClasspathPrefs.java index c514f3513..87e868658 100644 --- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/adapters/ClasspathPrefs.java +++ b/modeler/cayenne-modeler-prefs/src/main/java/org/apache/cayenne/modeler/pref/adapters/ClasspathPrefs.java @@ -19,9 +19,8 @@ package org.apache.cayenne.modeler.pref.adapters; -import org.apache.cayenne.modeler.pref.PreferenceAdapter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.apache.cayenne.CayenneRuntimeException; +import org.apache.cayenne.modeler.pref.PrefsAdapter; import java.util.ArrayList; import java.util.Comparator; @@ -29,9 +28,7 @@ import java.util.List; import java.util.prefs.BackingStoreException; import java.util.prefs.Preferences; -public final class ClasspathPrefs extends PreferenceAdapter { - - private static final Logger LOGGER = LoggerFactory.getLogger(ClasspathPrefs.class); +public final class ClasspathPrefs extends PrefsAdapter { public static final String NODE = "classpath"; @@ -84,8 +81,7 @@ public final class ClasspathPrefs extends PreferenceAdapter { try { return prefs.keys(); } catch (BackingStoreException e) { - LOGGER.info("Error loading preferences", e); - return new String[0]; + throw new CayenneRuntimeException("Error loading classpath preferences", e); } } } diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/adapters/DBConnectorPrefs.java b/modeler/cayenne-modeler-prefs/src/main/java/org/apache/cayenne/modeler/pref/adapters/DBConnectorPrefs.java similarity index 94% rename from modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/adapters/DBConnectorPrefs.java rename to modeler/cayenne-modeler-prefs/src/main/java/org/apache/cayenne/modeler/pref/adapters/DBConnectorPrefs.java index 4259f3729..21c42bb34 100644 --- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/adapters/DBConnectorPrefs.java +++ b/modeler/cayenne-modeler-prefs/src/main/java/org/apache/cayenne/modeler/pref/adapters/DBConnectorPrefs.java @@ -20,9 +20,9 @@ package org.apache.cayenne.modeler.pref.adapters; import org.apache.cayenne.CayenneRuntimeException; -import org.apache.cayenne.modeler.dbconnector.DBConnector; -import org.apache.cayenne.modeler.dbconnector.DBConnectors; -import org.apache.cayenne.modeler.pref.PreferenceAdapter; +import org.apache.cayenne.modeler.pref.dbconnector.DBConnector; +import org.apache.cayenne.modeler.pref.dbconnector.DBConnectors; +import org.apache.cayenne.modeler.pref.PrefsAdapter; import java.util.prefs.BackingStoreException; import java.util.prefs.Preferences; @@ -31,7 +31,7 @@ import java.util.prefs.Preferences; * Loads {@link DBConnectors} from the user prefs and binds the registry's * change events to the prefs node, so registry mutations are mirrored to disk. */ -public class DBConnectorPrefs extends PreferenceAdapter { +public class DBConnectorPrefs extends PrefsAdapter { public static final String NODE = "dbConnectors"; diff --git a/modeler/cayenne-modeler-prefs/src/main/java/org/apache/cayenne/modeler/pref/dbconnector/DBConnector.java b/modeler/cayenne-modeler-prefs/src/main/java/org/apache/cayenne/modeler/pref/dbconnector/DBConnector.java new file mode 100644 index 000000000..b5db35869 --- /dev/null +++ b/modeler/cayenne-modeler-prefs/src/main/java/org/apache/cayenne/modeler/pref/dbconnector/DBConnector.java @@ -0,0 +1,150 @@ +/***************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + ****************************************************************/ + +package org.apache.cayenne.modeler.pref.dbconnector; + +import org.apache.cayenne.configuration.DataSourceDescriptor; +import org.apache.cayenne.util.Util; + +/** + * Configuration record for a named database connection profile stored in user preferences. + * Holds the five connection parameters (adapter, driver, url, user, password). Runtime + * operations (creating a live {@code DataSource} or {@code DbAdapter}) are in + * {@code DBConnectorFactory} in the Modeler module. + */ +public class DBConnector { + + private static final String EMPTY_STRING = ""; + public static final String DB_ADAPTER_PROPERTY = "dbAdapter"; + public static final String JDBC_DRIVER_PROPERTY = "jdbcDriver"; + public static final String PASSWORD_PROPERTY = "password"; + public static final String URL_PROPERTY = "url"; + public static final String USER_NAME_PROPERTY = "userName"; + + private String dbAdapter; + private String jdbcDriver; + private String password; + private String url; + private String userName; + + public String getDbAdapter() { + return dbAdapter; + } + + public void setDbAdapter(final String dbAdapter) { + this.dbAdapter = dbAdapter; + } + + public String getJdbcDriver() { + return jdbcDriver; + } + + public void setJdbcDriver(final String jdbcDriver) { + this.jdbcDriver = jdbcDriver; + } + + public String getPassword() { + return password == null ? EMPTY_STRING : password; + } + + public void setPassword(final String password) { + this.password = password; + } + + public String getUrl() { + return url; + } + + public void setUrl(final String url) { + this.url = url; + } + + public String getUserName() { + return userName == null ? EMPTY_STRING : userName; + } + + public void setUserName(final String userName) { + this.userName = userName; + } + + /** + * Copies this connector's values into another {@link DBConnector}. + * Returns {@code true} if any field changed. + */ + public boolean copyTo(DBConnector connector) { + boolean updated = false; + + if (!Util.nullSafeEquals(connector.getUrl(), getUrl())) { + connector.setUrl(getUrl()); + updated = true; + } + + if (!Util.nullSafeEquals(connector.getUserName(), getUserName())) { + connector.setUserName(getUserName()); + updated = true; + } + + if (!Util.nullSafeEquals(connector.getPassword(), getPassword())) { + connector.setPassword(getPassword()); + updated = true; + } + + if (!Util.nullSafeEquals(connector.getJdbcDriver(), getJdbcDriver())) { + connector.setJdbcDriver(getJdbcDriver()); + updated = true; + } + + if (!Util.nullSafeEquals(connector.getDbAdapter(), getDbAdapter())) { + connector.setDbAdapter(getDbAdapter()); + updated = true; + } + + return updated; + } + + /** + * Updates a {@link DataSourceDescriptor} with this connector's values. + * Returns {@code true} if any field changed. + */ + public boolean copyTo(final DataSourceDescriptor dataSourceInfo) { + boolean updated = false; + + if (!Util.nullSafeEquals(dataSourceInfo.getDataSourceUrl(), getUrl())) { + dataSourceInfo.setDataSourceUrl(getUrl()); + updated = true; + } + + if (!Util.nullSafeEquals(dataSourceInfo.getUserName(), getUserName())) { + dataSourceInfo.setUserName(getUserName()); + updated = true; + } + + if (!Util.nullSafeEquals(dataSourceInfo.getPassword(), getPassword())) { + dataSourceInfo.setPassword(getPassword()); + updated = true; + } + + if (!Util.nullSafeEquals(dataSourceInfo.getJdbcDriver(), getJdbcDriver())) { + dataSourceInfo.setJdbcDriver(getJdbcDriver()); + updated = true; + } + + return updated; + } +} diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dbconnector/DBConnectors.java b/modeler/cayenne-modeler-prefs/src/main/java/org/apache/cayenne/modeler/pref/dbconnector/DBConnectors.java similarity index 97% rename from modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dbconnector/DBConnectors.java rename to modeler/cayenne-modeler-prefs/src/main/java/org/apache/cayenne/modeler/pref/dbconnector/DBConnectors.java index 57534ea5a..b694df69b 100644 --- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dbconnector/DBConnectors.java +++ b/modeler/cayenne-modeler-prefs/src/main/java/org/apache/cayenne/modeler/pref/dbconnector/DBConnectors.java @@ -17,7 +17,7 @@ * under the License. ****************************************************************/ -package org.apache.cayenne.modeler.dbconnector; +package org.apache.cayenne.modeler.pref.dbconnector; import org.apache.cayenne.modeler.pref.adapters.DBConnectorPrefs; diff --git a/modeler/cayenne-modeler/pom.xml b/modeler/cayenne-modeler/pom.xml index 5936a08cd..b690f264a 100644 --- a/modeler/cayenne-modeler/pom.xml +++ b/modeler/cayenne-modeler/pom.xml @@ -32,68 +32,63 @@ <packaging>jar</packaging> <dependencies> - - <dependency> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-api</artifactId> - </dependency> - - <dependency> - <groupId>com.jgoodies</groupId> - <artifactId>forms</artifactId> - </dependency> - - <dependency> - <groupId>com.jgoodies</groupId> - <artifactId>jgoodies-looks</artifactId> - </dependency> - <dependency> <groupId>org.apache.cayenne</groupId> <artifactId>cayenne</artifactId> <version>${project.version}</version> </dependency> - <dependency> <groupId>org.apache.cayenne</groupId> <artifactId>cayenne-project</artifactId> <version>${project.version}</version> </dependency> - <dependency> <groupId>org.apache.cayenne</groupId> <artifactId>cayenne-cgen</artifactId> <version>${project.version}</version> </dependency> - <dependency> <groupId>org.apache.cayenne</groupId> <artifactId>cayenne-dbsync</artifactId> <version>${project.version}</version> </dependency> - <dependency> <groupId>org.apache.cayenne.modeler</groupId> <artifactId>cayenne-wocompat</artifactId> <version>${project.version}</version> </dependency> - <dependency> - <groupId>org.junit.jupiter</groupId> - <artifactId>junit-jupiter</artifactId> - <scope>test</scope> + <groupId>org.apache.cayenne.modeler</groupId> + <artifactId>cayenne-modeler-prefs</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + </dependency> + <dependency> + <groupId>com.jgoodies</groupId> + <artifactId>forms</artifactId> + </dependency> + <dependency> + <groupId>com.jgoodies</groupId> + <artifactId>jgoodies-looks</artifactId> </dependency> - <dependency> <groupId>com.fifesoft</groupId> <artifactId>rsyntaxtextarea</artifactId> </dependency> + <!-- Test dependencies --> + <dependency> + <groupId>org.junit.jupiter</groupId> + <artifactId>junit-jupiter</artifactId> + <scope>test</scope> + </dependency> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> <scope>test</scope> </dependency> - </dependencies> </project> diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/Application.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/Application.java index d0dc916c0..8311aee3b 100644 --- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/Application.java +++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/Application.java @@ -28,7 +28,7 @@ import org.apache.cayenne.dbsync.DbSyncModule; import org.apache.cayenne.dbsync.merge.factory.MergerTokenFactoryProvider; import org.apache.cayenne.di.DIBootstrap; import org.apache.cayenne.di.Injector; -import org.apache.cayenne.modeler.dbconnector.DBConnectors; +import org.apache.cayenne.modeler.pref.dbconnector.DBConnectors; import org.apache.cayenne.modeler.log.ModelerLogFactory; import org.apache.cayenne.modeler.platform.UIInitializer; import org.apache.cayenne.modeler.toolkit.filechooser.FileChooserFactory; @@ -206,7 +206,7 @@ public class Application { this.undoManager = new CayenneUndoManager(this); this.frame = new MainFrame(this); this.platformInit.afterFrameCreated(this); - + // open up frame.onStartup(); diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dbconnector/DBConnector.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dbconnector/DBConnector.java deleted file mode 100644 index c0f397057..000000000 --- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dbconnector/DBConnector.java +++ /dev/null @@ -1,277 +0,0 @@ -/***************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - ****************************************************************/ - -package org.apache.cayenne.modeler.dbconnector; - -import org.apache.cayenne.configuration.DataNodeDescriptor; -import org.apache.cayenne.configuration.DataSourceDescriptor; -import org.apache.cayenne.configuration.runtime.DbAdapterFactory; -import org.apache.cayenne.datasource.DriverDataSource; -import org.apache.cayenne.dba.DbAdapter; -import org.apache.cayenne.modeler.service.classloader.ModelerClassLoader; -import org.apache.cayenne.util.Util; - -import javax.sql.DataSource; -import java.io.PrintWriter; -import java.sql.Connection; -import java.sql.Driver; -import java.sql.SQLException; -import java.sql.SQLFeatureNotSupportedException; -import java.util.logging.Logger; - -public class DBConnector { - - private static final String EMPTY_STRING = ""; - public static final String DB_ADAPTER_PROPERTY = "dbAdapter"; - public static final String JDBC_DRIVER_PROPERTY = "jdbcDriver"; - public static final String PASSWORD_PROPERTY = "password"; - public static final String URL_PROPERTY = "url"; - public static final String USER_NAME_PROPERTY = "userName"; - - private String dbAdapter; - private String jdbcDriver; - private String password; - private String url; - private String userName; - - private boolean allowDataSourceFailure; - - public void setAllowDataSourceFailure(boolean allowDataSourceFailure) { - this.allowDataSourceFailure = allowDataSourceFailure; - } - - public String getDbAdapter() { - return dbAdapter; - } - - public void setDbAdapter(final String dbAdapter) { - this.dbAdapter = dbAdapter; - } - - public String getJdbcDriver() { - return jdbcDriver; - } - - public void setJdbcDriver(final String jdbcDriver) { - this.jdbcDriver = jdbcDriver; - } - - public String getPassword() { - return password == null ? EMPTY_STRING : password; - } - - public void setPassword(final String password) { - this.password = password; - } - - public String getUrl() { - return url; - } - - public void setUrl(final String url) { - this.url = url; - } - - public String getUserName() { - return userName == null ? EMPTY_STRING : userName; - } - - public void setUserName(final String userName) { - this.userName = userName; - } - - /** - * Creates a DbAdapter based on configured values. - */ - public DbAdapter makeAdapter(ModelerClassLoader classLoader, DbAdapterFactory adapterFactory) throws Exception { - DataNodeDescriptor descriptor = new DataNodeDescriptor(); - descriptor.setAdapterType(getDbAdapter()); - DataSource dataSource = makeDataSource(classLoader); - return adapterFactory.createAdapter(descriptor, dataSource); - } - - /** - * Returns a DataSource that uses connection information from this object. - * Returned DataSource is not pooling its connections. It can be wrapped in - * PoolManager if pooling is needed. - */ - public DataSource makeDataSource(ModelerClassLoader classLoader) throws SQLException { - - // validate... - if (getJdbcDriver() == null) { - if (allowDataSourceFailure) { - return new DeferredDataSource(classLoader); - } - throw new SQLException("No JDBC driver set."); - } - - if (getUrl() == null) { - if (allowDataSourceFailure) { - return new DeferredDataSource(classLoader); - } - throw new SQLException("No DB URL set."); - } - - if (!Util.isBlank(getPassword()) && Util.isBlank(getUserName())) { - throw new SQLException("No username when password is set."); - } - - // load driver... - Driver driver; - - try { - driver = classLoader.loadClass(Driver.class, getJdbcDriver()).getDeclaredConstructor().newInstance(); - } catch (Throwable th) { - throw new SQLException("Driver load error: " + Util.unwindException(th).getLocalizedMessage()); - } - - return new DriverDataSource(driver, getUrl(), getUserName(), getPassword()); - } - - /** - * Updates another DBConnectionInfo with this object's values. - */ - public boolean copyTo(DBConnector connector) { - boolean updated = false; - - if (!Util.nullSafeEquals(connector.getUrl(), getUrl())) { - connector.setUrl(getUrl()); - updated = true; - } - - if (!Util.nullSafeEquals(connector.getUserName(), getUserName())) { - connector.setUserName(getUserName()); - updated = true; - } - - if (!Util.nullSafeEquals(connector.getPassword(), getPassword())) { - connector.setPassword(getPassword()); - updated = true; - } - - if (!Util.nullSafeEquals(connector.getJdbcDriver(), getJdbcDriver())) { - connector.setJdbcDriver(getJdbcDriver()); - updated = true; - } - - if (!Util.nullSafeEquals(connector.getDbAdapter(), getDbAdapter())) { - connector.setDbAdapter(getDbAdapter()); - updated = true; - } - - return updated; - } - - /** - * Updates DataSourceInfo with this object's values. - * <p> - * <i>Currently doesn't set the adapter property. Need to change the UI to - * handle adapter via DataSourceInfo first, and then it should be safe to do - * an adapter update here. </i> - * </p> - */ - public boolean copyTo(final DataSourceDescriptor dataSourceInfo) { - boolean updated = false; - - if (!Util.nullSafeEquals(dataSourceInfo.getDataSourceUrl(), getUrl())) { - dataSourceInfo.setDataSourceUrl(getUrl()); - updated = true; - } - - if (!Util.nullSafeEquals(dataSourceInfo.getUserName(), getUserName())) { - dataSourceInfo.setUserName(getUserName()); - updated = true; - } - - if (!Util.nullSafeEquals(dataSourceInfo.getPassword(), getPassword())) { - dataSourceInfo.setPassword(getPassword()); - updated = true; - } - - if (!Util.nullSafeEquals(dataSourceInfo.getJdbcDriver(), getJdbcDriver())) { - dataSourceInfo.setJdbcDriver(getJdbcDriver()); - updated = true; - } - - return updated; - } - - private class DeferredDataSource implements DataSource { - - private final ModelerClassLoader classLoader; - - public DeferredDataSource(ModelerClassLoader classLoader) { - this.classLoader = classLoader; - } - - DataSource getDeferredDataSource() throws SQLException { - allowDataSourceFailure = false; - return makeDataSource(classLoader); - } - - @Override - public Connection getConnection() throws SQLException { - return getDeferredDataSource().getConnection(); - } - - @Override - public Connection getConnection(String username, String password) throws SQLException { - return getDeferredDataSource().getConnection(username, password); - } - - @Override - public PrintWriter getLogWriter() throws SQLException { - return getDeferredDataSource().getLogWriter(); - } - - @Override - public void setLogWriter(PrintWriter out) throws SQLException { - getDeferredDataSource().setLogWriter(out); - } - - @Override - public void setLoginTimeout(int seconds) throws SQLException { - getDeferredDataSource().setLoginTimeout(seconds); - } - - @Override - public int getLoginTimeout() throws SQLException { - return getDeferredDataSource().getLoginTimeout(); - } - - @Override - public <T> T unwrap(Class<T> iface) throws SQLException { - return getDeferredDataSource().unwrap(iface); - } - - @Override - public boolean isWrapperFor(Class<?> iface) throws SQLException { - return getDeferredDataSource().isWrapperFor(iface); - } - - @Override - public Logger getParentLogger() throws SQLFeatureNotSupportedException { - try { - return getDeferredDataSource().getParentLogger(); - } catch (SQLException e) { - throw new SQLFeatureNotSupportedException(e); - } - } - } -} diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dbconnector/DBConnectorFactory.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dbconnector/DBConnectorFactory.java new file mode 100644 index 000000000..24c111b7b --- /dev/null +++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dbconnector/DBConnectorFactory.java @@ -0,0 +1,156 @@ +/***************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + ****************************************************************/ + +package org.apache.cayenne.modeler.dbconnector; + +import org.apache.cayenne.configuration.DataNodeDescriptor; +import org.apache.cayenne.configuration.runtime.DbAdapterFactory; +import org.apache.cayenne.datasource.DriverDataSource; +import org.apache.cayenne.dba.DbAdapter; +import org.apache.cayenne.modeler.pref.dbconnector.DBConnector; +import org.apache.cayenne.modeler.service.classloader.ModelerClassLoader; +import org.apache.cayenne.util.Util; + +import javax.sql.DataSource; +import java.io.PrintWriter; +import java.sql.Connection; +import java.sql.Driver; +import java.sql.SQLException; +import java.sql.SQLFeatureNotSupportedException; +import java.util.logging.Logger; + +/** + * Creates live {@code DataSource} and {@code DbAdapter} instances from a {@link DBConnector} + * configuration, using a {@link ModelerClassLoader} to load the JDBC driver at runtime. + */ +public class DBConnectorFactory { + + private final ModelerClassLoader classLoader; + + public DBConnectorFactory(ModelerClassLoader classLoader) { + this.classLoader = classLoader; + } + + public DbAdapter makeAdapter(DBConnector connector, DbAdapterFactory adapterFactory) throws Exception { + return makeAdapter(connector, adapterFactory, false); + } + + public DbAdapter makeAdapter(DBConnector connector, DbAdapterFactory adapterFactory, + boolean allowDataSourceFailure) throws Exception { + DataNodeDescriptor descriptor = new DataNodeDescriptor(); + descriptor.setAdapterType(connector.getDbAdapter()); + DataSource dataSource = makeDataSource(connector, allowDataSourceFailure); + return adapterFactory.createAdapter(descriptor, dataSource); + } + + public DataSource makeDataSource(DBConnector connector) throws SQLException { + return makeDataSource(connector, false); + } + + public DataSource makeDataSource(DBConnector connector, boolean allowDataSourceFailure) throws SQLException { + if (connector.getJdbcDriver() == null) { + if (allowDataSourceFailure) { + return new DeferredDataSource(connector); + } + throw new SQLException("No JDBC driver set."); + } + + if (connector.getUrl() == null) { + if (allowDataSourceFailure) { + return new DeferredDataSource(connector); + } + throw new SQLException("No DB URL set."); + } + + if (!Util.isBlank(connector.getPassword()) && Util.isBlank(connector.getUserName())) { + throw new SQLException("No username when password is set."); + } + + Driver driver; + try { + driver = classLoader.loadClass(Driver.class, connector.getJdbcDriver()).getDeclaredConstructor().newInstance(); + } catch (Throwable th) { + throw new SQLException("Driver load error: " + Util.unwindException(th).getLocalizedMessage()); + } + + return new DriverDataSource(driver, connector.getUrl(), connector.getUserName(), connector.getPassword()); + } + + private class DeferredDataSource implements DataSource { + + private final DBConnector connector; + + DeferredDataSource(DBConnector connector) { + this.connector = connector; + } + + DataSource getDelegate() throws SQLException { + return makeDataSource(connector, false); + } + + @Override + public Connection getConnection() throws SQLException { + return getDelegate().getConnection(); + } + + @Override + public Connection getConnection(String username, String password) throws SQLException { + return getDelegate().getConnection(username, password); + } + + @Override + public PrintWriter getLogWriter() throws SQLException { + return getDelegate().getLogWriter(); + } + + @Override + public void setLogWriter(PrintWriter out) throws SQLException { + getDelegate().setLogWriter(out); + } + + @Override + public void setLoginTimeout(int seconds) throws SQLException { + getDelegate().setLoginTimeout(seconds); + } + + @Override + public int getLoginTimeout() throws SQLException { + return getDelegate().getLoginTimeout(); + } + + @Override + public <T> T unwrap(Class<T> iface) throws SQLException { + return getDelegate().unwrap(iface); + } + + @Override + public boolean isWrapperFor(Class<?> iface) throws SQLException { + return getDelegate().isWrapperFor(iface); + } + + @Override + public Logger getParentLogger() throws SQLFeatureNotSupportedException { + try { + return getDelegate().getParentLogger(); + } catch (SQLException e) { + throw new SQLFeatureNotSupportedException(e); + } + } + } +} diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/adapters/CMTablePrefs.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/adapters/CMTablePrefs.java index 7d23c14e4..90c957337 100644 --- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/adapters/CMTablePrefs.java +++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/adapters/CMTablePrefs.java @@ -18,7 +18,7 @@ ****************************************************************/ package org.apache.cayenne.modeler.pref.adapters; -import org.apache.cayenne.modeler.pref.PreferenceAdapter; +import org.apache.cayenne.modeler.pref.PrefsAdapter; import org.apache.cayenne.modeler.toolkit.table.CMTable; import javax.swing.event.ChangeEvent; @@ -31,7 +31,7 @@ import javax.swing.table.TableModel; import java.util.Map; import java.util.prefs.Preferences; -public final class CMTablePrefs extends PreferenceAdapter { +public final class CMTablePrefs extends PrefsAdapter { private static final String SORT_COLUMN_KEY = "sortColumn"; private static final String SORT_ORDER_KEY = "sortOrder"; diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/adapters/ComponentGeometryPrefs.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/adapters/ComponentGeometryPrefs.java index 6acf954a6..7097c6805 100644 --- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/adapters/ComponentGeometryPrefs.java +++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/adapters/ComponentGeometryPrefs.java @@ -19,14 +19,14 @@ package org.apache.cayenne.modeler.pref.adapters; -import org.apache.cayenne.modeler.pref.PreferenceAdapter; +import org.apache.cayenne.modeler.pref.PrefsAdapter; import java.awt.*; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import java.util.prefs.Preferences; -public final class ComponentGeometryPrefs extends PreferenceAdapter { +public final class ComponentGeometryPrefs extends PrefsAdapter { private static final String HEIGHT_PROPERTY = "height"; private static final String WIDTH_PROPERTY = "width"; diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/adapters/DBGeneratorPrefs.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/adapters/DBGeneratorPrefs.java index 699fef1f0..af2d0f9ee 100644 --- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/adapters/DBGeneratorPrefs.java +++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/adapters/DBGeneratorPrefs.java @@ -18,14 +18,14 @@ ****************************************************************/ package org.apache.cayenne.modeler.pref.adapters; -import org.apache.cayenne.modeler.pref.PreferenceAdapter; +import org.apache.cayenne.modeler.pref.PrefsAdapter; import java.util.prefs.Preferences; /** * Persistence for the DB Generator dialog's checkbox options. */ -public class DBGeneratorPrefs extends PreferenceAdapter { +public class DBGeneratorPrefs extends PrefsAdapter { public static final String NODE = "dbGenerator"; diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/adapters/DataMapPrefs.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/adapters/DataMapPrefs.java index 83926e8c4..31da2ff49 100644 --- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/adapters/DataMapPrefs.java +++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/adapters/DataMapPrefs.java @@ -18,12 +18,12 @@ ****************************************************************/ package org.apache.cayenne.modeler.pref.adapters; -import org.apache.cayenne.modeler.dbconnector.DBConnector; -import org.apache.cayenne.modeler.pref.PreferenceAdapter; +import org.apache.cayenne.modeler.pref.dbconnector.DBConnector; +import org.apache.cayenne.modeler.pref.PrefsAdapter; import java.util.prefs.Preferences; -public final class DataMapPrefs extends PreferenceAdapter { +public final class DataMapPrefs extends PrefsAdapter { public static final String SUPERCLASS_PACKAGE_PROPERTY = "superclassPackage"; public static final String DEFAULT_SUPERCLASS_PACKAGE_SUFFIX = "auto"; diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/adapters/DataNodePrefs.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/adapters/DataNodePrefs.java index b3b449e79..b723affcc 100644 --- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/adapters/DataNodePrefs.java +++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/adapters/DataNodePrefs.java @@ -18,12 +18,12 @@ ****************************************************************/ package org.apache.cayenne.modeler.pref.adapters; -import org.apache.cayenne.modeler.pref.PreferenceAdapter; +import org.apache.cayenne.modeler.pref.PrefsAdapter; import org.apache.cayenne.modeler.pref.PrefsCopier; import java.util.prefs.Preferences; -public final class DataNodePrefs extends PreferenceAdapter { +public final class DataNodePrefs extends PrefsAdapter { public static final String LOCAL_DATA_SOURCE_PROPERTY = "localDataSource"; diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/adapters/FileChooserPrefs.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/adapters/FileChooserPrefs.java index 1a339f489..2b345f6da 100644 --- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/adapters/FileChooserPrefs.java +++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/adapters/FileChooserPrefs.java @@ -19,7 +19,7 @@ package org.apache.cayenne.modeler.pref.adapters; -import org.apache.cayenne.modeler.pref.PreferenceAdapter; +import org.apache.cayenne.modeler.pref.PrefsAdapter; import javax.swing.JFileChooser; import java.awt.FileDialog; @@ -28,7 +28,7 @@ import java.awt.event.ComponentEvent; import java.io.File; import java.util.prefs.Preferences; -public final class FileChooserPrefs extends PreferenceAdapter { +public final class FileChooserPrefs extends PrefsAdapter { private static final String PATH_PROPERTY = "path"; diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/adapters/GeneralPrefs.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/adapters/GeneralPrefs.java index 95b58f99d..55fc0a2e6 100644 --- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/adapters/GeneralPrefs.java +++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/adapters/GeneralPrefs.java @@ -19,11 +19,11 @@ package org.apache.cayenne.modeler.pref.adapters; -import org.apache.cayenne.modeler.pref.PreferenceAdapter; +import org.apache.cayenne.modeler.pref.PrefsAdapter; import java.util.prefs.Preferences; -public final class GeneralPrefs extends PreferenceAdapter { +public final class GeneralPrefs extends PrefsAdapter { public static final String NODE = "general"; diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/adapters/LogConsolePrefs.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/adapters/LogConsolePrefs.java index 3e371264b..70026e5f7 100644 --- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/adapters/LogConsolePrefs.java +++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/adapters/LogConsolePrefs.java @@ -19,11 +19,11 @@ package org.apache.cayenne.modeler.pref.adapters; -import org.apache.cayenne.modeler.pref.PreferenceAdapter; +import org.apache.cayenne.modeler.pref.PrefsAdapter; import java.util.prefs.Preferences; -public final class LogConsolePrefs extends PreferenceAdapter { +public final class LogConsolePrefs extends PrefsAdapter { public static final String NODE = "logConsole"; static final String SHOW_CONSOLE = "showLogConsole"; diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/adapters/ProjectPrefs.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/adapters/ProjectPrefs.java index b9da3f04e..f6328ce70 100644 --- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/adapters/ProjectPrefs.java +++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/adapters/ProjectPrefs.java @@ -52,7 +52,7 @@ import org.apache.cayenne.modeler.event.display.ObjRelationshipDisplayEvent; import org.apache.cayenne.modeler.event.display.ProcedureDisplayEvent; import org.apache.cayenne.modeler.event.display.ProcedureParameterDisplayEvent; import org.apache.cayenne.modeler.event.display.QueryDisplayEvent; -import org.apache.cayenne.modeler.pref.PreferenceAdapter; +import org.apache.cayenne.modeler.pref.PrefsAdapter; import org.apache.cayenne.modeler.project.ProjectSession; import org.apache.cayenne.util.CayenneMapEntry; @@ -65,7 +65,7 @@ import java.util.prefs.Preferences; * Binding-style handler for the Modeler's last project selection. Loaded on project * open to restore selection, flushed on project close or Modeler close to persist it. */ -public final class ProjectPrefs extends PreferenceAdapter { +public final class ProjectPrefs extends PrefsAdapter { private static final String EVENT_KEY = "event"; diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/adapters/RecentProjectsPrefs.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/adapters/RecentProjectsPrefs.java index 924211b40..41f43a557 100644 --- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/adapters/RecentProjectsPrefs.java +++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/adapters/RecentProjectsPrefs.java @@ -19,7 +19,7 @@ package org.apache.cayenne.modeler.pref.adapters; -import org.apache.cayenne.modeler.pref.PreferenceAdapter; +import org.apache.cayenne.modeler.pref.PrefsAdapter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -29,7 +29,7 @@ import java.util.List; import java.util.prefs.BackingStoreException; import java.util.prefs.Preferences; -public final class RecentProjectsPrefs extends PreferenceAdapter { +public final class RecentProjectsPrefs extends PrefsAdapter { private static final Logger LOGGER = LoggerFactory.getLogger(RecentProjectsPrefs.class); diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/adapters/SplitPanePrefs.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/adapters/SplitPanePrefs.java index 30bb7bb6d..35335ee3d 100644 --- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/adapters/SplitPanePrefs.java +++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/adapters/SplitPanePrefs.java @@ -19,13 +19,13 @@ package org.apache.cayenne.modeler.pref.adapters; -import org.apache.cayenne.modeler.pref.PreferenceAdapter; +import org.apache.cayenne.modeler.pref.PrefsAdapter; import javax.swing.*; import java.beans.PropertyChangeListener; import java.util.prefs.Preferences; -public final class SplitPanePrefs extends PreferenceAdapter { +public final class SplitPanePrefs extends PrefsAdapter { private PropertyChangeListener listener; diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/action/DBConnectionAwareAction.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/action/DBConnectionAwareAction.java index 349396b29..6c8c90365 100644 --- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/action/DBConnectionAwareAction.java +++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/action/DBConnectionAwareAction.java @@ -23,7 +23,7 @@ import org.apache.cayenne.map.DataMap; import org.apache.cayenne.modeler.Application; import org.apache.cayenne.modeler.toolkit.AppAction; import org.apache.cayenne.modeler.ui.datasource.DataSourceDialog; -import org.apache.cayenne.modeler.dbconnector.DBConnector; +import org.apache.cayenne.modeler.pref.dbconnector.DBConnector; import org.apache.cayenne.modeler.pref.adapters.DataMapPrefs; /** diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/datasource/DataSourceDialog.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/datasource/DataSourceDialog.java index 14a604a0a..726b37cd2 100644 --- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/datasource/DataSourceDialog.java +++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/datasource/DataSourceDialog.java @@ -23,8 +23,9 @@ import com.jgoodies.forms.builder.PanelBuilder; import com.jgoodies.forms.layout.CellConstraints; import com.jgoodies.forms.layout.FormLayout; import org.apache.cayenne.dba.DbAdapter; -import org.apache.cayenne.modeler.dbconnector.DBConnector; -import org.apache.cayenne.modeler.dbconnector.DBConnectors; +import org.apache.cayenne.modeler.pref.dbconnector.DBConnector; +import org.apache.cayenne.modeler.dbconnector.DBConnectorFactory; +import org.apache.cayenne.modeler.pref.dbconnector.DBConnectors; import org.apache.cayenne.modeler.pref.adapters.DataMapPrefs; import org.apache.cayenne.modeler.pref.adapters.GeneralPrefs; import org.apache.cayenne.modeler.service.classloader.ModelerClassLoader; @@ -175,8 +176,9 @@ public class DataSourceDialog extends ProjectDialog { // doing connection testing... try { try { - this.adapter = info.makeAdapter(classLoader, app.getDbAdapterFactory()); - this.dataSource = info.makeDataSource(classLoader); + DBConnectorFactory factory = new DBConnectorFactory(classLoader); + this.adapter = factory.makeAdapter(info, app.getDbAdapterFactory()); + this.dataSource = factory.makeDataSource(info); } catch (SQLException ignore) { showNoConnectorDialog("Unable to load driver '" + info.getJdbcDriver() + "'"); return; diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/dbgen/DBGeneratorOptionsDialog.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/dbgen/DBGeneratorOptionsDialog.java index 318676d51..500e7759f 100644 --- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/dbgen/DBGeneratorOptionsDialog.java +++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/dbgen/DBGeneratorOptionsDialog.java @@ -27,7 +27,8 @@ import org.apache.cayenne.access.DbGenerator; import org.apache.cayenne.dba.DbAdapter; import org.apache.cayenne.log.NoopJdbcEventLogger; import org.apache.cayenne.map.DataMap; -import org.apache.cayenne.modeler.dbconnector.DBConnector; +import org.apache.cayenne.modeler.pref.dbconnector.DBConnector; +import org.apache.cayenne.modeler.dbconnector.DBConnectorFactory; import org.apache.cayenne.modeler.pref.adapters.DBGeneratorPrefs; import org.apache.cayenne.modeler.toolkit.border.TopBorder; import org.apache.cayenne.modeler.toolkit.ProjectDialog; @@ -105,7 +106,6 @@ public class DBGeneratorOptionsDialog extends ProjectDialog { this.tables = new TableSelectorPanel(app); this.connector = new DBConnector(); - this.connector.setAllowDataSourceFailure(true); this.generatorDefaults = new DBGeneratorPrefs(app.getPrefsManager().projectPref(session.project(), DBGeneratorPrefs.NODE)); // create widgets — set initial state before wiring listeners so we @@ -259,7 +259,7 @@ public class DBGeneratorOptionsDialog extends ProjectDialog { private void prepareGenerator() { try { - DbAdapter adapter = connector.makeAdapter(app.getClassLoader(), app.getDbAdapterFactory()); + DbAdapter adapter = new DBConnectorFactory(app.getClassLoader()).makeAdapter(connector, app.getDbAdapterFactory(), true); generators = new ArrayList<>(); for (DataMap dataMap : dataMaps) { generators.add(new DbGenerator( diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/dbmerge/MergerOptionsDialog.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/dbmerge/MergerOptionsDialog.java index 5bad5ae0e..6a18bc636 100644 --- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/dbmerge/MergerOptionsDialog.java +++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/dbmerge/MergerOptionsDialog.java @@ -46,7 +46,8 @@ import org.apache.cayenne.dbsync.reverse.filters.PatternFilter; import org.apache.cayenne.dbsync.reverse.filters.TableFilter; import org.apache.cayenne.map.DataMap; import org.apache.cayenne.map.ObjEntity; -import org.apache.cayenne.modeler.dbconnector.DBConnector; +import org.apache.cayenne.modeler.pref.dbconnector.DBConnector; +import org.apache.cayenne.modeler.dbconnector.DBConnectorFactory; import org.apache.cayenne.modeler.event.model.DataMapEvent; import org.apache.cayenne.modeler.toolkit.border.TopBorder; import org.apache.cayenne.modeler.toolkit.text.CMTextArea; @@ -192,7 +193,7 @@ public class MergerOptionsDialog extends ProjectDialog { private void prepareMigrator() { try { - adapter = connectionInfo.makeAdapter(app.getClassLoader(), app.getDbAdapterFactory()); + adapter = new DBConnectorFactory(app.getClassLoader()).makeAdapter(connectionInfo, app.getDbAdapterFactory()); MergerTokenFactory mergerTokenFactory = mergerTokenFactoryProvider.get(adapter); tokens.setMergerTokenFactory(mergerTokenFactory); @@ -207,7 +208,7 @@ public class MergerOptionsDialog extends ProjectDialog { DbLoaderConfiguration config = new DbLoaderConfiguration(); config.setFiltersConfig(filters); - DataSource dataSource = connectionInfo.makeDataSource(app.getClassLoader()); + DataSource dataSource = new DBConnectorFactory(app.getClassLoader()).makeDataSource(connectionInfo); DataMap dbImport; try (Connection conn = dataSource.getConnection()) { @@ -263,7 +264,7 @@ public class MergerOptionsDialog extends ProjectDialog { DataSource dataSource; try { - dataSource = connectionInfo.makeDataSource(app.getClassLoader()); + dataSource = new DBConnectorFactory(app.getClassLoader()).makeDataSource(connectionInfo); } catch (SQLException ex) { reportError("Migration Error", ex); return; diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/dbconnector/DBConnectorEditor.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/dbconnector/DBConnectorEditor.java index f7d7b9728..1598be025 100644 --- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/dbconnector/DBConnectorEditor.java +++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/dbconnector/DBConnectorEditor.java @@ -21,7 +21,7 @@ package org.apache.cayenne.modeler.ui.preferences.dbconnector; import com.jgoodies.forms.builder.DefaultFormBuilder; import com.jgoodies.forms.layout.FormLayout; -import org.apache.cayenne.modeler.dbconnector.DBConnector; +import org.apache.cayenne.modeler.pref.dbconnector.DBConnector; import org.apache.cayenne.modeler.toolkit.text.CMPasswordField; import org.apache.cayenne.modeler.toolkit.text.CMTextField; import org.apache.cayenne.modeler.dbadapter.DbAdapters; diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/dbconnector/DBConnectorPrefsPanel.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/dbconnector/DBConnectorPrefsPanel.java index 9d5be1253..576e205f6 100644 --- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/dbconnector/DBConnectorPrefsPanel.java +++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/dbconnector/DBConnectorPrefsPanel.java @@ -24,8 +24,8 @@ import com.jgoodies.forms.layout.CellConstraints; import com.jgoodies.forms.layout.FormLayout; import org.apache.cayenne.datasource.DriverDataSource; import org.apache.cayenne.modeler.Application; -import org.apache.cayenne.modeler.dbconnector.DBConnector; -import org.apache.cayenne.modeler.dbconnector.DBConnectors; +import org.apache.cayenne.modeler.pref.dbconnector.DBConnector; +import org.apache.cayenne.modeler.pref.dbconnector.DBConnectors; import org.apache.cayenne.modeler.service.classloader.ModelerClassLoader; import org.apache.cayenne.modeler.toolkit.AppPanel; import org.apache.cayenne.modeler.ui.preferences.classpath.ClasspathPrefsPanel; diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/dbconnector/creator/DBConnectorCreatorDialog.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/dbconnector/creator/DBConnectorCreatorDialog.java index 8aa13a172..1ceff0120 100644 --- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/dbconnector/creator/DBConnectorCreatorDialog.java +++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/dbconnector/creator/DBConnectorCreatorDialog.java @@ -22,7 +22,7 @@ package org.apache.cayenne.modeler.ui.preferences.dbconnector.creator; import com.jgoodies.forms.builder.DefaultFormBuilder; import com.jgoodies.forms.layout.FormLayout; import org.apache.cayenne.modeler.Application; -import org.apache.cayenne.modeler.dbconnector.DBConnector; +import org.apache.cayenne.modeler.pref.dbconnector.DBConnector; import org.apache.cayenne.modeler.toolkit.AppDialog; import org.apache.cayenne.modeler.ui.preferences.dbconnector.DBConnectorPrefsPanel; import org.apache.cayenne.modeler.dbadapter.DbAdapters; diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/dbconnector/duplicator/DBConnectorDuplicatorDialog.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/dbconnector/duplicator/DBConnectorDuplicatorDialog.java index d1de2130e..f66105333 100644 --- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/dbconnector/duplicator/DBConnectorDuplicatorDialog.java +++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/preferences/dbconnector/duplicator/DBConnectorDuplicatorDialog.java @@ -22,7 +22,7 @@ package org.apache.cayenne.modeler.ui.preferences.dbconnector.duplicator; import com.jgoodies.forms.builder.DefaultFormBuilder; import com.jgoodies.forms.layout.FormLayout; import org.apache.cayenne.modeler.Application; -import org.apache.cayenne.modeler.dbconnector.DBConnector; +import org.apache.cayenne.modeler.pref.dbconnector.DBConnector; import org.apache.cayenne.modeler.toolkit.AppDialog; import org.apache.cayenne.modeler.ui.preferences.dbconnector.DBConnectorPrefsPanel; diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datamap/dbimport/DatabaseSchemaLoader.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datamap/dbimport/DatabaseSchemaLoader.java index a0e6e0851..00e86de0a 100644 --- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datamap/dbimport/DatabaseSchemaLoader.java +++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datamap/dbimport/DatabaseSchemaLoader.java @@ -41,7 +41,8 @@ import org.apache.cayenne.dbsync.reverse.dbimport.Schema; import org.apache.cayenne.dbsync.reverse.dbimport.SchemaContainer; import org.apache.cayenne.modeler.service.classloader.ModelerClassLoader; import org.apache.cayenne.modeler.ui.project.editor.datamap.dbimport.tree.DbImportTreeNode; -import org.apache.cayenne.modeler.dbconnector.DBConnector; +import org.apache.cayenne.modeler.pref.dbconnector.DBConnector; +import org.apache.cayenne.modeler.dbconnector.DBConnectorFactory; public class DatabaseSchemaLoader { @@ -57,8 +58,8 @@ public class DatabaseSchemaLoader { public ReverseEngineering load(DBConnector connectionInfo, ModelerClassLoader loadingService) throws Exception { - DbAdapter dbAdapter = connectionInfo.makeAdapter(loadingService, adapterFactory); - try (Connection connection = connectionInfo.makeDataSource(loadingService).getConnection()) { + DbAdapter dbAdapter = new DBConnectorFactory(loadingService).makeAdapter(connectionInfo, adapterFactory); + try (Connection connection = new DBConnectorFactory(loadingService).makeDataSource(connectionInfo).getConnection()) { processCatalogs(connection, dbAdapter); } @@ -131,7 +132,7 @@ public class DatabaseSchemaLoader { String[] tableTypesFromConfig) throws Exception { int pathIndex = 1; String catalogName = null, schemaName = null; - DbAdapter adapter = connectionInfo.makeAdapter(loadingService, adapterFactory); + DbAdapter adapter = new DBConnectorFactory(loadingService).makeAdapter(connectionInfo, adapterFactory); Object userObject = getUserObjectOrNull(path, pathIndex); if (userObject != null) { @@ -149,7 +150,7 @@ public class DatabaseSchemaLoader { } } - try (Connection connection = connectionInfo.makeDataSource(loadingService).getConnection()) { + try (Connection connection = new DBConnectorFactory(loadingService).makeDataSource(connectionInfo).getConnection()) { String[] types = tableTypesFromConfig != null && tableTypesFromConfig.length != 0 ? tableTypesFromConfig : new String[]{"TABLE", "VIEW", "SYSTEM TABLE", @@ -193,7 +194,7 @@ public class DatabaseSchemaLoader { } String tableName = processTable(userObject); - try (Connection connection = connectionInfo.makeDataSource(loadingService).getConnection()) { + try (Connection connection = new DBConnectorFactory(loadingService).makeDataSource(connectionInfo).getConnection()) { try (ResultSet rs = connection.getMetaData().getColumns(catalogName, schemaName, tableName, null)) { while (rs.next()) { String column = rs.getString("COLUMN_NAME"); diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datamap/dbimport/action/LoadDbSchemaAction.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datamap/dbimport/action/LoadDbSchemaAction.java index fc690bbde..59e3b846e 100644 --- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datamap/dbimport/action/LoadDbSchemaAction.java +++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datamap/dbimport/action/LoadDbSchemaAction.java @@ -32,7 +32,7 @@ import org.apache.cayenne.modeler.ui.project.editor.datamap.dbimport.DbImportVie import org.apache.cayenne.modeler.ui.project.editor.datamap.dbimport.DBSchemaPanel; import org.apache.cayenne.modeler.ui.project.editor.datamap.dbimport.PrintColumnsBiFunction; import org.apache.cayenne.modeler.ui.project.editor.datamap.dbimport.PrintTablesBiFunction; -import org.apache.cayenne.modeler.dbconnector.DBConnector; +import org.apache.cayenne.modeler.pref.dbconnector.DBConnector; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datamap/dbimport/action/ModelerDbImportAction.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datamap/dbimport/action/ModelerDbImportAction.java index f04fa4586..4c59f1228 100644 --- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datamap/dbimport/action/ModelerDbImportAction.java +++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datamap/dbimport/action/ModelerDbImportAction.java @@ -28,7 +28,8 @@ import org.apache.cayenne.di.DIBootstrap; import org.apache.cayenne.di.Injector; import org.apache.cayenne.map.DataMap; import org.apache.cayenne.modeler.Application; -import org.apache.cayenne.modeler.dbconnector.DBConnector; +import org.apache.cayenne.modeler.pref.dbconnector.DBConnector; +import org.apache.cayenne.modeler.dbconnector.DBConnectorFactory; import org.apache.cayenne.modeler.project.DataMapOps; import org.apache.cayenne.modeler.ui.project.editor.datamap.dbimport.progress.DbImportProgressDialog; import org.apache.cayenne.modeler.ui.action.DBConnectionAwareAction; @@ -81,7 +82,7 @@ public class ModelerDbImportAction extends DBConnectionAwareAction { } try { - context.setConnection(connectionInfo.makeDataSource(app.getClassLoader()).getConnection()); + context.setConnection(new DBConnectorFactory(app.getClassLoader()).makeDataSource(connectionInfo).getConnection()); } catch (SQLException ex) { JOptionPane.showMessageDialog( app.getFrame(), diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datamap/dbimport/runner/ModelerDbLoaderContext.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datamap/dbimport/runner/ModelerDbLoaderContext.java index 3aefca96d..98c107b31 100644 --- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datamap/dbimport/runner/ModelerDbLoaderContext.java +++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datamap/dbimport/runner/ModelerDbLoaderContext.java @@ -25,7 +25,8 @@ import org.apache.cayenne.dbsync.reverse.dbload.DbLoaderDelegate; import org.apache.cayenne.dbsync.reverse.filters.FiltersConfigBuilder; import org.apache.cayenne.map.DataMap; import org.apache.cayenne.modeler.Application; -import org.apache.cayenne.modeler.dbconnector.DBConnector; +import org.apache.cayenne.modeler.pref.dbconnector.DBConnector; +import org.apache.cayenne.modeler.dbconnector.DBConnectorFactory; import org.apache.cayenne.modeler.service.classloader.ModelerClassLoader; import org.apache.cayenne.modeler.project.ProjectSession; import org.apache.cayenne.util.Util; @@ -137,8 +138,8 @@ public class ModelerDbLoaderContext { try { ModelerClassLoader classLoader = application.getClassLoader(); config.getDbLoaderConfig().setFiltersConfig(new FiltersConfigBuilder(reverseEngineering) - .dataSource(connectionInfo.makeDataSource(classLoader)) - .dbAdapter(connectionInfo.makeAdapter(classLoader, application.getDbAdapterFactory())) + .dataSource(new DBConnectorFactory(classLoader).makeDataSource(connectionInfo)) + .dbAdapter(new DBConnectorFactory(classLoader).makeAdapter(connectionInfo, application.getDbAdapterFactory())) .build()); } catch (Exception e) { processException(e, "Fail while building configs."); diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datanode/DataNodeEditorPanel.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datanode/DataNodeEditorPanel.java index 8c8e4d997..e9d1f8b90 100644 --- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datanode/DataNodeEditorPanel.java +++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datanode/DataNodeEditorPanel.java @@ -28,7 +28,7 @@ import org.apache.cayenne.access.dbsync.ThrowOnPartialSchemaStrategy; import org.apache.cayenne.configuration.DataChannelDescriptor; import org.apache.cayenne.configuration.DataNodeDescriptor; import org.apache.cayenne.configuration.runtime.XMLPoolingDataSourceFactory; -import org.apache.cayenne.modeler.dbconnector.DBConnector; +import org.apache.cayenne.modeler.pref.dbconnector.DBConnector; import org.apache.cayenne.modeler.event.model.DataNodeEvent; import org.apache.cayenne.modeler.pref.adapters.DataNodePrefs; import org.apache.cayenne.modeler.project.ProjectSession; diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datanode/jdbc/JDBCDataSourcePanel.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datanode/jdbc/JDBCDataSourcePanel.java index 4e5a22ea1..25427ee2d 100644 --- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datanode/jdbc/JDBCDataSourcePanel.java +++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datanode/jdbc/JDBCDataSourcePanel.java @@ -25,7 +25,7 @@ import com.jgoodies.forms.layout.FormLayout; import org.apache.cayenne.configuration.DataNodeDescriptor; import org.apache.cayenne.configuration.DataSourceDescriptor; import org.apache.cayenne.modeler.Application; -import org.apache.cayenne.modeler.dbconnector.DBConnector; +import org.apache.cayenne.modeler.pref.dbconnector.DBConnector; import org.apache.cayenne.modeler.pref.adapters.DataNodePrefs; import org.apache.cayenne.modeler.toolkit.text.CMPasswordField; import org.apache.cayenne.modeler.toolkit.text.CMUndoableTextField; diff --git a/modeler/pom.xml b/modeler/pom.xml index 2db49f95b..3ff2d3e9b 100644 --- a/modeler/pom.xml +++ b/modeler/pom.xml @@ -34,6 +34,7 @@ <modules> <module>cayenne-wocompat</module> + <module>cayenne-modeler-prefs</module> <module>cayenne-modeler</module> <module>cayenne-modeler-generic</module> <module>cayenne-modeler-mac</module>
