Skip to content

Commit 401d00b

Browse files
committed
Add empty catalog, so the server can come up even with bad or missing connection information
1 parent 2553548 commit 401d00b

File tree

4 files changed

+302
-6
lines changed

4 files changed

+302
-6
lines changed
Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
package schemacrawler.tools.ai.mcpserver;
2+
3+
import java.util.Collection;
4+
import java.util.Collections;
5+
import java.util.Map;
6+
import java.util.Optional;
7+
import schemacrawler.schema.Catalog;
8+
import schemacrawler.schema.Column;
9+
import schemacrawler.schema.ColumnDataType;
10+
import schemacrawler.schema.CrawlInfo;
11+
import schemacrawler.schema.DatabaseInfo;
12+
import schemacrawler.schema.DatabaseUser;
13+
import schemacrawler.schema.JdbcDriverInfo;
14+
import schemacrawler.schema.NamedObject;
15+
import schemacrawler.schema.NamedObjectKey;
16+
import schemacrawler.schema.Reducer;
17+
import schemacrawler.schema.Routine;
18+
import schemacrawler.schema.Schema;
19+
import schemacrawler.schema.Sequence;
20+
import schemacrawler.schema.Synonym;
21+
import schemacrawler.schema.Table;
22+
23+
public class EmptyCatalog implements Catalog {
24+
25+
private static final long serialVersionUID = -8018517276190501450L;
26+
27+
@Override
28+
public int compareTo(final NamedObject o) {
29+
return -1;
30+
}
31+
32+
@Override
33+
public <T> T getAttribute(final String name) {
34+
return null;
35+
}
36+
37+
@Override
38+
public <T> T getAttribute(final String name, final T defaultValue) throws ClassCastException {
39+
return null;
40+
}
41+
42+
@Override
43+
public Map<String, Object> getAttributes() {
44+
return Collections.emptyMap();
45+
}
46+
47+
@Override
48+
public Collection<ColumnDataType> getColumnDataTypes() {
49+
return Collections.emptyList();
50+
}
51+
52+
@Override
53+
public Collection<ColumnDataType> getColumnDataTypes(final Schema schema) {
54+
return Collections.emptyList();
55+
}
56+
57+
@Override
58+
public CrawlInfo getCrawlInfo() {
59+
throw new UnsupportedOperationException("No supported in an empty catalog");
60+
}
61+
62+
@Override
63+
public DatabaseInfo getDatabaseInfo() {
64+
throw new UnsupportedOperationException("No supported in an empty catalog");
65+
}
66+
67+
@Override
68+
public Collection<DatabaseUser> getDatabaseUsers() {
69+
return Collections.emptyList();
70+
}
71+
72+
@Override
73+
public String getFullName() {
74+
return getName();
75+
}
76+
77+
@Override
78+
public JdbcDriverInfo getJdbcDriverInfo() {
79+
throw new UnsupportedOperationException("No supported in an empty catalog");
80+
}
81+
82+
@Override
83+
public String getName() {
84+
return "empty-catalog";
85+
}
86+
87+
@Override
88+
public String getRemarks() {
89+
return getName();
90+
}
91+
92+
@Override
93+
public Collection<Routine> getRoutines() {
94+
return Collections.emptyList();
95+
}
96+
97+
@Override
98+
public Collection<Routine> getRoutines(final Schema schema) {
99+
return Collections.emptyList();
100+
}
101+
102+
@Override
103+
public Collection<Routine> getRoutines(final Schema schema, final String routineName) {
104+
return Collections.emptyList();
105+
}
106+
107+
@Override
108+
public Collection<Schema> getSchemas() {
109+
return Collections.emptyList();
110+
}
111+
112+
@Override
113+
public Collection<Sequence> getSequences() {
114+
return Collections.emptyList();
115+
}
116+
117+
@Override
118+
public Collection<Sequence> getSequences(final Schema schema) {
119+
return Collections.emptyList();
120+
}
121+
122+
@Override
123+
public Collection<Synonym> getSynonyms() {
124+
return Collections.emptyList();
125+
}
126+
127+
@Override
128+
public Collection<Synonym> getSynonyms(final Schema schema) {
129+
return Collections.emptyList();
130+
}
131+
132+
@Override
133+
public Collection<ColumnDataType> getSystemColumnDataTypes() {
134+
return Collections.emptyList();
135+
}
136+
137+
@Override
138+
public Collection<Table> getTables() {
139+
return Collections.emptyList();
140+
}
141+
142+
@Override
143+
public Collection<Table> getTables(final Schema schema) {
144+
return Collections.emptyList();
145+
}
146+
147+
@Override
148+
public boolean hasAttribute(final String name) {
149+
return false;
150+
}
151+
152+
@Override
153+
public boolean hasRemarks() {
154+
return false;
155+
}
156+
157+
@Override
158+
public NamedObjectKey key() {
159+
return new NamedObjectKey((String) null);
160+
}
161+
162+
@Override
163+
public <T> Optional<T> lookupAttribute(final String name) {
164+
return Optional.empty();
165+
}
166+
167+
@Override
168+
public Optional<Column> lookupColumn(
169+
final Schema schema, final String tableName, final String name) {
170+
return Optional.empty();
171+
}
172+
173+
@Override
174+
public <C extends ColumnDataType> Optional<C> lookupColumnDataType(
175+
final Schema schema, final String dataTypeName) {
176+
return Optional.empty();
177+
}
178+
179+
@Override
180+
public <S extends Schema> Optional<S> lookupSchema(final String name) {
181+
return Optional.empty();
182+
}
183+
184+
@Override
185+
public <S extends Sequence> Optional<S> lookupSequence(
186+
final Schema schema, final String sequenceName) {
187+
return Optional.empty();
188+
}
189+
190+
@Override
191+
public <S extends Synonym> Optional<S> lookupSynonym(
192+
final Schema schema, final String synonymName) {
193+
return Optional.empty();
194+
}
195+
196+
@Override
197+
public <C extends ColumnDataType> Optional<C> lookupSystemColumnDataType(final String name) {
198+
return Optional.empty();
199+
}
200+
201+
@Override
202+
public <T extends Table> Optional<T> lookupTable(final Schema schema, final String tableName) {
203+
return Optional.empty();
204+
}
205+
206+
@Override
207+
public <N extends NamedObject> void reduce(final Class<N> clazz, final Reducer<N> reducer) {
208+
// No-op
209+
}
210+
211+
@Override
212+
public void removeAttribute(final String name) {
213+
// No-op
214+
}
215+
216+
@Override
217+
public <T> void setAttribute(final String name, final T value) {
218+
// No-op
219+
}
220+
221+
@Override
222+
public void setRemarks(final String remarks) {
223+
// No-op
224+
}
225+
226+
@Override
227+
public <N extends NamedObject> void undo(final Class<N> clazz, final Reducer<N> reducer) {
228+
// No-op
229+
}
230+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package schemacrawler.tools.ai.mcpserver;
2+
3+
import java.sql.Connection;
4+
import java.sql.DriverManager;
5+
import java.sql.SQLException;
6+
import java.util.function.Consumer;
7+
import java.util.logging.Level;
8+
import java.util.logging.Logger;
9+
import schemacrawler.schemacrawler.exceptions.DatabaseAccessException;
10+
import us.fatehi.utility.datasource.DatabaseConnectionSource;
11+
12+
public class EmptyDatabaseConnectionSource implements DatabaseConnectionSource {
13+
14+
private static final Logger LOGGER =
15+
Logger.getLogger(EmptyDatabaseConnectionSource.class.getName());
16+
17+
@Override
18+
public void close() throws Exception {
19+
// No-op
20+
}
21+
22+
/** Get a connection to an empty SQLite in memory database. */
23+
@Override
24+
public Connection get() {
25+
try {
26+
final Connection connection = DriverManager.getConnection("jdbc:sqlite::memory:");
27+
return connection;
28+
} catch (final SQLException e) {
29+
final String message = "Could not create an empty connection";
30+
LOGGER.log(Level.WARNING, message, e);
31+
throw new DatabaseAccessException(message, e);
32+
}
33+
}
34+
35+
@Override
36+
public boolean releaseConnection(final Connection connection) {
37+
return false;
38+
}
39+
40+
@Override
41+
public void setFirstConnectionInitializer(final Consumer<Connection> connectionInitializer) {
42+
// No-op
43+
}
44+
}

schemacrawler-ai-mcpserver/src/main/java/schemacrawler/tools/ai/mcpserver/McpServerMain.java

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010

1111
import static schemacrawler.tools.ai.mcpserver.McpServerUtility.startMcpServer;
1212

13+
import java.util.logging.Level;
14+
import java.util.logging.Logger;
1315
import schemacrawler.schema.Catalog;
1416
import schemacrawler.schemacrawler.SchemaCrawlerOptions;
1517
import schemacrawler.tools.ai.mcpserver.server.ConfigurationManager;
@@ -22,6 +24,8 @@
2224
*/
2325
public class McpServerMain {
2426

27+
private static final Logger LOGGER = Logger.getLogger(McpServerMain.class.getName());
28+
2529
/**
2630
* Main method that reads environment variables, constructs arguments, and runs SchemaCrawler MCP
2731
* Server.
@@ -32,14 +36,28 @@ public class McpServerMain {
3236
public static void main(final String[] args) throws Exception {
3337
// Read options from environmental variable
3438
final McpServerContext context = new McpServerContext();
35-
final SchemaCrawlerOptions schemaCrawlerOptions = context.getSchemaCrawlerOptions();
36-
final DatabaseConnectionSource connectionSource =
37-
context.buildCatalogDatabaseConnectionSource();
38-
// Obtain the database catalog
39-
final Catalog catalog = SchemaCrawlerUtility.getCatalog(connectionSource, schemaCrawlerOptions);
40-
ConnectionService.instantiate(connectionSource);
39+
final Catalog catalog = getCatalog(context);
4140
ConfigurationManager.instantiate(catalog);
4241
// Start the MCP server
4342
startMcpServer(context.mcpTransport());
4443
}
44+
45+
private static Catalog getCatalog(final McpServerContext context) {
46+
try {
47+
final SchemaCrawlerOptions schemaCrawlerOptions = context.getSchemaCrawlerOptions();
48+
final DatabaseConnectionSource connectionSource =
49+
context.buildCatalogDatabaseConnectionSource();
50+
// Obtain the database catalog
51+
final Catalog catalog =
52+
SchemaCrawlerUtility.getCatalog(connectionSource, schemaCrawlerOptions);
53+
ConnectionService.instantiate(connectionSource);
54+
return catalog;
55+
} catch (final Exception e) {
56+
LOGGER.log(Level.SEVERE, "Could not load catalog", e);
57+
if (!ConnectionService.isInstantiated()) {
58+
ConnectionService.instantiate(new EmptyDatabaseConnectionSource());
59+
}
60+
return new EmptyCatalog();
61+
}
62+
}
4563
}

schemacrawler-ai-mcpserver/src/main/java/schemacrawler/tools/ai/mcpserver/server/ConnectionService.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ public static void instantiate(final DatabaseConnectionSource dbConnectionSource
7171
}
7272
}
7373

74+
public static boolean isInstantiated() {
75+
return instance != null;
76+
}
77+
7478
private static DatabaseConnectionSource newDatabaseConnectionSource(final Connection connection) {
7579
DatabaseConnectionSource dbConnectionSource = null;
7680

0 commit comments

Comments
 (0)