blob: 6cb7b60962821abaa7cf2fe739b31880d43ece73 [file] [log] [blame]
kmoorec7fdcd42011-02-05 17:01:41 +00001/*******************************************************************************
bvosburghd1d8d172011-03-03 00:11:32 +00002 * Copyright (c) 2006, 2011 Oracle. All rights reserved.
kmoorec7fdcd42011-02-05 17:01:41 +00003 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v1.0, which accompanies this distribution
5 * and is available at http://www.eclipse.org/legal/epl-v10.html.
6 *
7 * Contributors:
8 * Oracle - initial API and implementation
9 ******************************************************************************/
10package org.eclipse.jpt.jpa.db.tests.internal.platforms;
11
12import java.io.File;
13import java.io.IOException;
14import java.io.OutputStreamWriter;
15import java.net.URL;
16import java.sql.Connection;
17import java.sql.DatabaseMetaData;
18import java.sql.ResultSet;
bvosburghd1d8d172011-03-03 00:11:32 +000019import java.sql.ResultSetMetaData;
kmoorec7fdcd42011-02-05 17:01:41 +000020import java.sql.SQLException;
21import java.sql.Statement;
22import java.util.ArrayList;
bvosburghd1d8d172011-03-03 00:11:32 +000023import java.util.HashMap;
kmoorec7fdcd42011-02-05 17:01:41 +000024import java.util.Iterator;
25import java.util.List;
bvosburghd1d8d172011-03-03 00:11:32 +000026import java.util.Map;
kmoorec7fdcd42011-02-05 17:01:41 +000027import java.util.Properties;
kmoorec7fdcd42011-02-05 17:01:41 +000028import junit.framework.TestCase;
kmoorec7fdcd42011-02-05 17:01:41 +000029import org.eclipse.core.runtime.CoreException;
30import org.eclipse.core.runtime.IPath;
31import org.eclipse.core.runtime.IStatus;
32import org.eclipse.core.runtime.Platform;
33import org.eclipse.datatools.connectivity.ConnectionProfileException;
34import org.eclipse.datatools.connectivity.IConnectionProfile;
kmoorec7fdcd42011-02-05 17:01:41 +000035import org.eclipse.datatools.connectivity.ProfileManager;
36import org.eclipse.datatools.connectivity.drivers.IDriverMgmtConstants;
37import org.eclipse.datatools.connectivity.drivers.IPropertySet;
38import org.eclipse.datatools.connectivity.drivers.PropertySetImpl;
39import org.eclipse.datatools.connectivity.drivers.XMLFileManager;
40import org.eclipse.datatools.connectivity.drivers.jdbc.IJDBCDriverDefinitionConstants;
41import org.eclipse.datatools.connectivity.internal.ConnectivityPlugin;
kmoorec7fdcd42011-02-05 17:01:41 +000042import org.eclipse.datatools.connectivity.sqm.core.rte.ICatalogObject;
43import org.eclipse.jpt.common.utility.IndentingPrintWriter;
bvosburghd1d8d172011-03-03 00:11:32 +000044import org.eclipse.jpt.common.utility.internal.CollectionTools;
kmoorec7fdcd42011-02-05 17:01:41 +000045import org.eclipse.jpt.common.utility.internal.ReflectionTools;
46import org.eclipse.jpt.common.utility.internal.StringTools;
47import org.eclipse.jpt.common.utility.internal.iterators.ResultSetIterator;
48import org.eclipse.jpt.jpa.db.Catalog;
49import org.eclipse.jpt.jpa.db.Column;
50import org.eclipse.jpt.jpa.db.ConnectionListener;
51import org.eclipse.jpt.jpa.db.ConnectionProfile;
52import org.eclipse.jpt.jpa.db.ConnectionProfileFactory;
53import org.eclipse.jpt.jpa.db.ConnectionProfileListener;
54import org.eclipse.jpt.jpa.db.Database;
55import org.eclipse.jpt.jpa.db.DatabaseIdentifierAdapter;
56import org.eclipse.jpt.jpa.db.ForeignKey;
57import org.eclipse.jpt.jpa.db.JptJpaDbPlugin;
58import org.eclipse.jpt.jpa.db.Schema;
59import org.eclipse.jpt.jpa.db.SchemaContainer;
60import org.eclipse.jpt.jpa.db.Sequence;
61import org.eclipse.jpt.jpa.db.Table;
kmoorec7fdcd42011-02-05 17:01:41 +000062import org.eclipse.jpt.jpa.db.tests.internal.JptJpaDbTestsPlugin;
63
64/**
65 * Base class for testing DTP wrappers on various databases.
66 */
67@SuppressWarnings("nls")
68public abstract class DTPPlatformTests extends TestCase {
69
70 /**
71 * The platform properties are loaded from a Java properties file in the
72 * 'org.eclipse.jpt.jpa.db.tests/config' directory. Each database platform has
73 * its own properties file (e.g. 'derby.properties').
74 */
75 private Properties platformProperties;
76
77 /**
78 * This is the Dali connection profile wrapper.
79 */
80 protected ConnectionProfile connectionProfile;
81
82
83 // ********** constants **********
84
85 private static final String PLATFORM_CONFIG_DIRECTORY = "config";
86
87 private static final String DB_USER_ID_PROPERTY = "userID";
88 private static final String DB_USER_ID_DEFAULT = "user";
89
90 private static final String DB_PASSWORD_PROPERTY = "password";
91 private static final String DB_PASSWORD_DEFAULT = "";
92
93 private static final String DB_DRIVER_JARS_PROPERTY = "jars";
94 // required - no default
95
96 private static final String DB_URL_PROPERTY = "url";
97 // required - no default
98
99
100
101 // ********** constructor **********
102
103 protected DTPPlatformTests(String name) {
104 super(name);
105 }
106
107
108 // ********** set-up/tear-down **********
109
110 @Override
111 protected void setUp() throws Exception {
112 super.setUp();
113
114 this.platformProperties = this.loadPlatformProperties();
115 this.buildDTPDriverDefinitionFile();
116 this.buildDTPConnectionProfile();
117 this.connectionProfile = this.getConnectionProfileFactory().buildConnectionProfile(this.getProfileName(), DatabaseIdentifierAdapter.Default.instance());
118 }
119
120 @Override
121 protected void tearDown() throws Exception {
122 this.connectionProfile = null;
123 this.platformProperties = null;
124
125 super.tearDown();
126 }
127
128 // ***** platform properties file
129 private Properties loadPlatformProperties() throws IOException {
130 Properties p = new Properties();
131 p.load(this.buildPlatformPropertiesFileURL().openStream());
132 return p;
133 }
134
135 private URL buildPlatformPropertiesFileURL() {
136 return Platform.getBundle(this.getTestPluginBundleID()).getEntry(this.getPlatformPropertiesFilePath());
137 }
138
139 private String getTestPluginBundleID() {
140 return JptJpaDbTestsPlugin.BUNDLE_ID;
141 }
142
143 private String getPlatformPropertiesFilePath() {
144 return this.getPlatformPropertiesDirectoryName() + '/' + this.getPlatformPropertiesFileName();
145 }
146
147 private String getPlatformPropertiesDirectoryName() {
148 return PLATFORM_CONFIG_DIRECTORY;
149 }
150
151 /**
152 * Each database platform has a separate properties file in the 'config'
153 * directory that must be customized by whomever is executing the tests.
154 */
155 protected abstract String getPlatformPropertiesFileName();
156
157 // ***** driver definition file
158 private void buildDTPDriverDefinitionFile() throws CoreException {
159 XMLFileManager.setStorageLocation(this.getDTPDriverDefinitionLocation());
160 XMLFileManager.setFileName(this.getDTPDriverFileName());
161
162 IPropertySet[] sets = XMLFileManager.loadPropertySets();
163 for (IPropertySet set : sets) {
164 if (set.getID().equals(this.getDriverDefinitionID())) {
165 return; // property sets live across tests
166 }
167 }
168
169 XMLFileManager.saveNamedPropertySet(this.buildDTPDriverDefinitionPropertySets());
170
171 // verify the file was created:
172 File driverDefinitioneFile = this.getDTPDriverDefinitionLocation().append(this.getDTPDriverFileName()).toFile();
173 assertTrue(driverDefinitioneFile.exists());
174 }
175
176 private IPath getDTPDriverDefinitionLocation() {
177 return ConnectivityPlugin.getDefault().getStateLocation();
178 }
179
180 private String getDTPDriverFileName() {
181 return IDriverMgmtConstants.DRIVER_FILE;
182 }
183
184 private IPropertySet[] buildDTPDriverDefinitionPropertySets() {
185 IPropertySet[] propertySets = new IPropertySet[1];
186 PropertySetImpl propertySet = new PropertySetImpl(this.getDriverName(), this.getDriverDefinitionID());
187 propertySet.setProperties(this.getDriverDefinitionID(), this.buildDTPDriverDefinitionProperties());
188 propertySets[0] = propertySet;
189 return propertySets;
190 }
191
192 protected abstract String getDriverName();
193
194 protected abstract String getDriverDefinitionID();
195
196 private Properties buildDTPDriverDefinitionProperties() {
197 Properties p = new Properties();
198 p.setProperty(ConnectionProfile.DRIVER_DEFINITION_TYPE_PROP_ID, this.getDriverDefinitionType());
199 p.setProperty(ConnectionProfile.DRIVER_JAR_LIST_PROP_ID, this.getJDBCDriverJarList());
200 p.setProperty(IJDBCDriverDefinitionConstants.DATABASE_VENDOR_PROP_ID, this.getDatabaseVendor());
201 p.setProperty(IJDBCDriverDefinitionConstants.DATABASE_VERSION_PROP_ID, this.getDatabaseVersion());
202 p.setProperty(IJDBCDriverDefinitionConstants.DRIVER_CLASS_PROP_ID, this.getDriverClass());
203 p.setProperty(IJDBCDriverDefinitionConstants.URL_PROP_ID, this.getJDBCURL());
204 p.setProperty(IJDBCDriverDefinitionConstants.USERNAME_PROP_ID, this.getUserID());
205 p.setProperty(IJDBCDriverDefinitionConstants.PASSWORD_PROP_ID, this.getPassword());
206 return p;
207 }
208
209 protected abstract String getDriverDefinitionType();
210
211 /**
212 * The JAR list is workspace-specific and is set in the properties file.
213 */
214 private String getJDBCDriverJarList() {
215 return this.getRequiredPlatformProperty(DB_DRIVER_JARS_PROPERTY);
216 }
217
218 protected abstract String getDatabaseVendor();
219
220 protected abstract String getDatabaseVersion();
221
222 protected abstract String getDriverClass();
223
224 /**
225 * The database URL is workspace-specific and is set in the properties file
226 * for some databases.
227 */
228 private String getJDBCURL() {
229 return this.platformProperties.getProperty(DB_URL_PROPERTY, this.getDefaultJDBCURL());
230 }
231
232 protected String getDefaultJDBCURL() {
233 return "";
234 }
235
236 /**
237 * The user ID is optional and can be set in the properties file.
238 */
239 protected String getUserID() {
240 return this.platformProperties.getProperty(DB_USER_ID_PROPERTY, DB_USER_ID_DEFAULT);
241 }
242
243 /**
244 * The password is optional and can be set in the properties file.
245 */
246 private String getPassword() {
247 return this.platformProperties.getProperty(DB_PASSWORD_PROPERTY, DB_PASSWORD_DEFAULT);
248 }
249
250 // ***** DTP connection profile
251 private void buildDTPConnectionProfile() throws ConnectionProfileException {
252 if (this.getDTPProfileManager().getProfileByName(this.getProfileName()) != null) {
253 return; // profiles live across tests
254 }
255 this.createProfile(this.getProfileName());
256 assertNotNull(this.getDTPProfileManager().getProfileByName(this.getProfileName()));
257 }
258
259 protected void createProfile(String profileName) throws ConnectionProfileException {
260 this.getDTPProfileManager().createProfile(
261 profileName,
262 this.getProfileDescription(),
263 this.getProviderID(),
264 this.buildDTPConnectionProfileProperties()
265 );
266 }
267
268 protected abstract String getProfileName();
269
270 protected abstract String getProfileDescription();
271
272 protected String getProviderID() {
273 return ConnectionProfile.CONNECTION_PROFILE_TYPE;
274 }
275
276 protected Properties buildDTPConnectionProfileProperties() {
277 Properties p = new Properties();
278 p.setProperty(IJDBCDriverDefinitionConstants.USERNAME_PROP_ID, this.getUserID());
279 p.setProperty(IJDBCDriverDefinitionConstants.PASSWORD_PROP_ID, this.getPassword());
280 p.setProperty(ConnectionProfile.DRIVER_DEFINITION_PROP_ID, this.getDriverDefinitionID());
281
282 p.setProperty(IJDBCDriverDefinitionConstants.DRIVER_CLASS_PROP_ID, this.getDriverClass());
283 p.setProperty(IJDBCDriverDefinitionConstants.URL_PROP_ID, this.getJDBCURL());
284 p.setProperty(IJDBCDriverDefinitionConstants.DATABASE_VENDOR_PROP_ID, this.getDatabaseVendor());
285 p.setProperty(IJDBCDriverDefinitionConstants.DATABASE_VERSION_PROP_ID, this.getDatabaseVersion());
286
287 p.setProperty(ConnectionProfile.DATABASE_SAVE_PWD_PROP_ID, this.passwordIsSaved());
288 return p;
289 }
290
291 private String passwordIsSaved() {
292 return "true";
293 }
294
295
296 // ********** tests **********
297
298 public void testConnectionProfileListener() throws ConnectionProfileException {
299 TestConnectionProfileListener listener = new TestConnectionProfileListener();
300 this.getConnectionProfileFactory().addConnectionProfileListener(listener);
301
302 String cpName1 = this.getProfileName() + "1";
303 this.createProfile(cpName1);
304 IConnectionProfile dtpCP = this.getDTPProfileManager().getProfileByName(cpName1);
305 assertNotNull(dtpCP);
306
307 assertEquals(cpName1, listener.addedName);
308 listener.clear();
309
310 String cpName2 = this.getProfileName() + "2";
311 this.getDTPProfileManager().modifyProfile(dtpCP, cpName2, null);
312 assertEquals(cpName1, listener.renamedOldName);
313 assertEquals(cpName2, listener.renamedNewName);
314 listener.clear();
315
316 ConnectionProfile cp = this.getConnectionProfileFactory().buildConnectionProfile(cpName2);
317 assertNotNull(cp);
318
319 this.getDTPProfileManager().deleteProfile(dtpCP);
320 assertEquals(cpName2, listener.removedName);
321 listener.clear();
322
323 cp = this.getConnectionProfileFactory().buildConnectionProfile(cpName2);
324 assertNull(cp);
325
326 this.getConnectionProfileFactory().removeConnectionProfileListener(listener);
327 }
328
329 public void testName() {
330 assertEquals(this.getProfileName(), this.connectionProfile.getName());
331 }
332
333 public void testConnection() throws Exception {
334 assertTrue(this.connectionProfile.isInactive());
335 assertTrue(this.connectionProfile.isDisconnected());
336 this.connectionProfile.connect();
337 assertTrue(this.connectionProfile.isActive());
338 assertTrue(this.connectionProfile.isConnected());
339
340 this.verifyDatabaseVersionNumber();
341 this.verifyDatabaseVendor();
342 this.verifyDatabaseContent();
343
344 this.connectionProfile.disconnect();
345 assertTrue(this.connectionProfile.isInactive());
346 assertTrue(this.connectionProfile.isDisconnected());
347 }
348
349 private void verifyDatabaseVersionNumber() {
350 Database database = this.connectionProfile.getDatabase();
351 assertNotNull(database);
352
353 String actual = database.getVersion();
354 String expected = this.getDatabaseVersion();
355 String errorMessage = "expected: " + expected + " - actual: " + actual;
356 // partial match is good enough
357 assertTrue(errorMessage, actual.indexOf(expected) != -1);
358 }
359
360 private void verifyDatabaseVendor() {
361 Database database = this.connectionProfile.getDatabase();
362 String actual = database.getVendorName();
363 String expected = this.getDatabaseVendor();
364 assertEquals(expected, actual);
365 }
366
367 private void verifyDatabaseContent() {
368 Database database = this.connectionProfile.getDatabase();
369 assertTrue(database.getSchemataSize() >= 0);
370
371 Schema schema = database.getDefaultSchema();
372 if (schema != null) {
373 if (schema.getTablesSize() > 0) {
374 Table table = schema.getTables().iterator().next();
375 assertTrue(table.getColumnsSize() >= 0);
376 assertTrue(table.getPrimaryKeyColumnsSize() >= 0);
377 assertTrue(table.getForeignKeysSize() >= 0);
378 }
379 }
380 }
381
382 protected abstract boolean executeOfflineTests();
383
384 public final void testOffline() {
385 if ( ! this.executeOfflineTests()) {
386 return;
387 }
388 if ( ! this.connectionProfile.supportsWorkOfflineMode()) {
389 return;
390 }
391
392 this.prepareForOfflineWork();
393
394 IStatus status = this.connectionProfile.workOffline();
395 assertTrue(status.isOK());
396 assertTrue(this.connectionProfile.isActive());
397 assertTrue(this.connectionProfile.isWorkingOffline());
398
399 this.connectionProfile.disconnect();
400 assertTrue(this.connectionProfile.isInactive());
401 assertTrue(this.connectionProfile.isDisconnected());
402 }
403
404 protected void prepareForOfflineWork() {
405 if ( ! this.connectionProfile.canWorkOffline()) {
406 this.connectionProfile.connect();
407 IStatus status = this.connectionProfile.saveWorkOfflineData();
408 assertTrue(status.isOK());
409 this.connectionProfile.disconnect();
410 assertTrue(this.connectionProfile.canWorkOffline());
411 }
412 }
413
414 public void testConnectionListenerConnect() {
415 assertTrue(this.connectionProfileHasNoListeners());
416 TestConnectionListener listener = new TestConnectionListener();
417 this.connectionProfile.addConnectionListener(listener);
418 assertTrue(this.connectionProfileHasAnyListeners());
419
420 this.connectionProfile.connect();
421 assertSame(this.connectionProfile, listener.openedProfile);
422 listener.clear();
423
424 this.connectionProfile.disconnect();
425 assertSame(this.connectionProfile, listener.okToCloseProfile);
426 assertSame(this.connectionProfile, listener.aboutToCloseProfile);
427 assertSame(this.connectionProfile, listener.closedProfile);
428
429 this.connectionProfile.removeConnectionListener(listener);
430 assertTrue(this.connectionProfileHasNoListeners());
431 }
432
433 public final void testConnectionListenerOffline() {
434 if ( ! this.executeOfflineTests()) {
435 return;
436 }
437 TestConnectionListener listener = new TestConnectionListener();
438 this.connectionProfile.addConnectionListener(listener);
439
440 this.prepareForOfflineWork();
441 listener.clear();
442
443 this.connectionProfile.workOffline();
444 assertSame(this.connectionProfile, listener.openedProfile);
445 listener.clear();
446
447 this.connectionProfile.disconnect();
448 assertSame(this.connectionProfile, listener.okToCloseProfile);
449 assertSame(this.connectionProfile, listener.aboutToCloseProfile);
450 assertSame(this.connectionProfile, listener.closedProfile);
451 listener.clear();
452
453 this.connectionProfile.removeConnectionListener(listener);
454 }
455
456 public void testConnectionListenerDatabase() {
457 this.connectionProfile.connect();
458 TestConnectionListener listener = new TestConnectionListener();
459 this.connectionProfile.addConnectionListener(listener);
460
461 ((ICatalogObject) this.getDTPDatabase()).refresh();
462 assertSame(this.connectionProfile.getDatabase(), listener.changedDatabase);
463
464 this.connectionProfile.removeConnectionListener(listener);
465 this.connectionProfile.disconnect();
466 }
467
468 public void testConnectionListenerCatalog() {
469 this.connectionProfile.connect();
470 if ( ! this.connectionProfile.getDatabase().supportsCatalogs()) {
471 this.connectionProfile.disconnect();
472 return;
473 }
474
475 TestConnectionListener listener = new TestConnectionListener();
476 this.connectionProfile.addConnectionListener(listener);
477
478 // take the first catalog
479 org.eclipse.datatools.modelbase.sql.schema.Catalog dtpCatalog = this.getFirstDTPCatalog();
480 Catalog catalog = this.getCatalogNamed(dtpCatalog.getName());
481 ((ICatalogObject) dtpCatalog).refresh();
482 assertSame(catalog, listener.changedCatalog);
483
484 this.connectionProfile.removeConnectionListener(listener);
485 this.connectionProfile.disconnect();
486 }
487
488 public void testConnectionListenerSchema() {
489 this.connectionProfile.connect();
490 TestConnectionListener listener = new TestConnectionListener();
491 this.connectionProfile.addConnectionListener(listener);
492
493 List<org.eclipse.datatools.modelbase.sql.schema.Catalog> dtpCatalogs = this.getDTPCatalogs();
494 org.eclipse.datatools.modelbase.sql.schema.Catalog dtpCatalog = null;
495 org.eclipse.datatools.modelbase.sql.schema.Schema dtpSchema = null;
496 Schema schema = null;
497 if (this.connectionProfile.getDatabase().supportsCatalogs()) {
498 dtpCatalog = dtpCatalogs.get(0);
499 dtpSchema = (org.eclipse.datatools.modelbase.sql.schema.Schema) dtpCatalog.getSchemas().get(0);
500 schema = this.getCatalogNamed(dtpCatalog.getName()).getSchemaNamed(dtpSchema.getName());
501 } else {
502 if (dtpCatalogs.isEmpty()) {
503 dtpSchema = (org.eclipse.datatools.modelbase.sql.schema.Schema) this.getDTPDatabase().getSchemas().get(0);
504 schema = this.connectionProfile.getDatabase().getSchemaNamed(dtpSchema.getName());
505 } else {
506 dtpCatalog = dtpCatalogs.get(0); // should be the "virtual" catalog
507 assertEquals("", dtpCatalog.getName());
508 dtpSchema = (org.eclipse.datatools.modelbase.sql.schema.Schema) dtpCatalog.getSchemas().get(0);
509 // the schemata are held directly by the database in this situation
510 schema = this.getDatabase().getSchemaNamed(dtpSchema.getName());
511 }
512 }
513 assertTrue(schema.getTablesSize() >= 0); // force tables to be loaded
514 ((ICatalogObject) dtpSchema).refresh();
515 assertSame(schema, listener.changedSchema);
516
517 this.connectionProfile.removeConnectionListener(listener);
518 this.connectionProfile.disconnect();
519 }
520
521 public void testSupportsCatalogs() {
522 this.connectionProfile.connect();
523 TestConnectionListener listener = new TestConnectionListener();
524 this.connectionProfile.addConnectionListener(listener);
525
526 boolean supportsCatalogs = this.supportsCatalogs();
527 assertEquals(supportsCatalogs, this.connectionProfile.getDatabase().supportsCatalogs());
528 if (supportsCatalogs) {
529 assertTrue(this.connectionProfile.getDatabase().getCatalogsSize() > 0);
530 assertEquals(0, this.connectionProfile.getDatabase().getSchemataSize());
531 } else {
532 assertEquals(0, this.connectionProfile.getDatabase().getCatalogsSize());
533 assertTrue(this.connectionProfile.getDatabase().getSchemataSize() > 0);
534 }
535
536 this.connectionProfile.removeConnectionListener(listener);
537 this.connectionProfile.disconnect();
538 }
539
540 protected abstract boolean supportsCatalogs();
541
542// public void testDEBUG() throws Exception {
543// this.connectionProfile.connect();
544// this.dumpJDBCCatalogs();
545// this.dumpJDBCSchemata();
546// this.dumpDatabaseContainers();
547// this.connectionProfile.disconnect();
548// }
549
550
551 // ********** convenience methods **********
552
553 protected ConnectionProfileFactory getConnectionProfileFactory() {
554 return JptJpaDbPlugin.getConnectionProfileFactory();
555 }
556
557 protected ConnectionProfile getConnectionProfile() {
558 return this.connectionProfile;
559 }
560
561 protected Database getDatabase() {
562 return this.connectionProfile.getDatabase();
563 }
564
565 protected Catalog getDefaultCatalog() {
566 return this.getDatabase().getDefaultCatalog();
567 }
568
569 /**
570 * only valid on databases that do not support catalogs
571 */
572 protected Schema getDefaultSchema() {
573 return this.getDatabase().getDefaultSchema();
574 }
575
576 protected Catalog getCatalogNamed(String catalogName) {
577 return this.connectionProfile.getDatabase().getCatalogNamed(catalogName);
578 }
579
580 protected String getRequiredPlatformProperty(String propertyKey) {
581 String propertyValue = this.platformProperties.getProperty(propertyKey);
582 if (StringTools.stringIsEmpty(propertyValue)) {
583 throw new IllegalArgumentException("The database platform properties file '" + this.getPlatformPropertiesFilePath()
584 + "' is missing a value for the property '" + propertyKey + "'.");
585 }
586 return propertyValue;
587 }
588
589 protected boolean connectionProfileHasAnyListeners() {
590 return connectionProfileHasAnyListeners(this.connectionProfile);
591 }
592
593 protected static boolean connectionProfileHasAnyListeners(ConnectionProfile cp) {
594 return ((Boolean) ReflectionTools.executeMethod(cp, "hasAnyListeners")).booleanValue();
595 }
596
597 protected boolean connectionProfileHasNoListeners() {
598 return connectionProfileHasNoListeners(this.connectionProfile);
599 }
600
601 protected static boolean connectionProfileHasNoListeners(ConnectionProfile cp) {
602 return ((Boolean) ReflectionTools.executeMethod(cp, "hasNoListeners")).booleanValue();
603 }
604
605
606 // ********** DTP model **********
607
608 protected ProfileManager getDTPProfileManager() {
609 return ProfileManager.getInstance();
610 }
611
612 protected IConnectionProfile getDTPConnectionProfile() {
613 return getDTPConnectionProfile(this.connectionProfile);
614 }
615
616 protected static IConnectionProfile getDTPConnectionProfile(ConnectionProfile cp) {
617 return (IConnectionProfile) ReflectionTools.getFieldValue(cp, "dtpConnectionProfile");
618 }
619
kmoorec7fdcd42011-02-05 17:01:41 +0000620 protected org.eclipse.datatools.modelbase.sql.schema.Database getDTPDatabase() {
621 return getDTPDatabase(this.connectionProfile.getDatabase());
622 }
623
624 protected static org.eclipse.datatools.modelbase.sql.schema.Database getDTPDatabase(Database database) {
625 return (org.eclipse.datatools.modelbase.sql.schema.Database) ReflectionTools.getFieldValue(database, "dtpDatabase");
626 }
627
628 @SuppressWarnings("unchecked")
629 protected List<org.eclipse.datatools.modelbase.sql.schema.Catalog> getDTPCatalogs() {
630 return this.getDTPDatabase().getCatalogs();
631 }
632
633 protected org.eclipse.datatools.modelbase.sql.schema.Catalog getFirstDTPCatalog() {
634 return this.getDTPCatalogs().get(0);
635 }
636
637 protected org.eclipse.datatools.modelbase.sql.schema.Catalog getDTPCatalogNamed(String name) {
638 return getDTPCatalog(this.getDatabase().getCatalogNamed(name));
639 }
640
641 protected static org.eclipse.datatools.modelbase.sql.schema.Catalog getDTPCatalog(Catalog catalog) {
642 return (org.eclipse.datatools.modelbase.sql.schema.Catalog) ReflectionTools.getFieldValue(catalog, "dtpCatalog");
643 }
644
645 protected org.eclipse.datatools.modelbase.sql.schema.Schema getDTPSchemaNamed(String name) {
646 return getDTPSchema(this.getDatabase().getSchemaNamed(name));
647 }
648
649 protected static org.eclipse.datatools.modelbase.sql.schema.Schema getDTPSchema(Schema schema) {
650 return (org.eclipse.datatools.modelbase.sql.schema.Schema) ReflectionTools.getFieldValue(schema, "dtpSchema");
651 }
652
653
654 // ********** execute SQL **********
655
656 /**
657 * ignore any errors (useful for dropping database objects that might
658 * not be there)
659 */
660 protected void executeUpdateIgnoreErrors(String sql) {
661 try {
662 this.executeUpdate(sql);
663 } catch (Exception ex) {
664// System.err.println("SQL: " + sql);
665// ex.printStackTrace();
666 }
667 }
668
669 protected void executeUpdate(String sql) throws SQLException {
670 Statement jdbcStatement = this.createJDBCStatement();
671 try {
672 jdbcStatement.executeUpdate(sql);
673 } finally {
674 jdbcStatement.close();
675 }
676 }
677
678 protected void dump(String sql) throws SQLException {
bvosburghd1d8d172011-03-03 00:11:32 +0000679 this.dump(sql, 30);
kmoorec7fdcd42011-02-05 17:01:41 +0000680 }
681
682 protected void dump(String sql, int columnWidth) throws SQLException {
683 IndentingPrintWriter pw = new IndentingPrintWriter(new OutputStreamWriter(System.out));
684 // synchronize the console so everything is contiguous
685 synchronized (System.out) {
686 this.dumpOn(sql, pw, columnWidth);
687 }
688 pw.flush();
689 }
690
691 protected void dumpOn(String sql, IndentingPrintWriter pw, int columnWidth) throws SQLException {
692 pw.println(sql);
bvosburghd1d8d172011-03-03 00:11:32 +0000693 for (HashMap<String, Object> row : this.execute(sql)) {
694 for (Map.Entry<String, Object> field : row.entrySet()) {
695 StringTools.padOrTruncateOn(String.valueOf(field.getKey()), columnWidth/2, pw);
696 pw.print('=');
697 StringTools.padOrTruncateOn(String.valueOf(field.getValue()), columnWidth/2, pw);
kmoorec7fdcd42011-02-05 17:01:41 +0000698 pw.print(' ');
699 }
700 pw.println();
701 }
702 }
703
bvosburghd1d8d172011-03-03 00:11:32 +0000704 protected ArrayList<HashMap<String, Object>> execute(String sql) throws SQLException {
kmoorec7fdcd42011-02-05 17:01:41 +0000705 Statement jdbcStatement = this.createJDBCStatement();
706 jdbcStatement.execute(sql);
bvosburghd1d8d172011-03-03 00:11:32 +0000707 ArrayList<HashMap<String, Object>> rows = this.buildRows(jdbcStatement.getResultSet());
kmoorec7fdcd42011-02-05 17:01:41 +0000708 jdbcStatement.close();
709 return rows;
710 }
711
bvosburghd1d8d172011-03-03 00:11:32 +0000712 protected ArrayList<HashMap<String, Object>> buildRows(ResultSet resultSet) throws SQLException {
713 ArrayList<HashMap<String, Object>> rows = new ArrayList<HashMap<String, Object>>();
714 CollectionTools.addAll(rows, this.buildResultSetIterator(resultSet));
kmoorec7fdcd42011-02-05 17:01:41 +0000715 return rows;
716 }
717
bvosburghd1d8d172011-03-03 00:11:32 +0000718 protected Iterator<HashMap<String, Object>> buildResultSetIterator(ResultSet resultSet) throws SQLException {
719 return new ResultSetIterator<HashMap<String, Object>>(resultSet, new MapResultSetIteratorAdapter(resultSet.getMetaData()));
kmoorec7fdcd42011-02-05 17:01:41 +0000720 }
721
bvosburghd1d8d172011-03-03 00:11:32 +0000722 public static class MapResultSetIteratorAdapter
723 implements ResultSetIterator.Adapter<HashMap<String, Object>>
724 {
kmoorec7fdcd42011-02-05 17:01:41 +0000725 private final int columnCount;
bvosburghd1d8d172011-03-03 00:11:32 +0000726 private final String[] columnNames;
727 public MapResultSetIteratorAdapter(ResultSetMetaData rsMetaData) throws SQLException {
kmoorec7fdcd42011-02-05 17:01:41 +0000728 super();
bvosburghd1d8d172011-03-03 00:11:32 +0000729 this.columnCount = rsMetaData.getColumnCount();
730 this.columnNames = new String[this.columnCount + 1]; // leave zero slot empty
kmoorec7fdcd42011-02-05 17:01:41 +0000731 for (int i = 1; i <= this.columnCount; i++) { // NB: ResultSet index/subscript is 1-based
bvosburghd1d8d172011-03-03 00:11:32 +0000732 this.columnNames[i] = rsMetaData.getColumnName(i);
kmoorec7fdcd42011-02-05 17:01:41 +0000733 }
bvosburghd1d8d172011-03-03 00:11:32 +0000734 }
735 public HashMap<String, Object> buildNext(ResultSet rs) throws SQLException {
736 HashMap<String, Object> row = new HashMap<String, Object>(this.columnCount);
737 for (int i = 1; i <= this.columnCount; i++) { // NB: ResultSet index/subscript is 1-based
738 row.put(this.columnNames[i], rs.getObject(i));
739 }
740 return row;
kmoorec7fdcd42011-02-05 17:01:41 +0000741 }
742 }
743
744 protected Statement createJDBCStatement() throws SQLException {
745 return this.getJDBCConnection().createStatement();
746 }
747
748 protected Connection getJDBCConnection() {
bvosburghd1d8d172011-03-03 00:11:32 +0000749 return this.connectionProfile.getJDBCConnection();
kmoorec7fdcd42011-02-05 17:01:41 +0000750 }
751
752 protected DatabaseMetaData getDatabaseMetaData() throws SQLException {
753 return this.getJDBCConnection().getMetaData();
754 }
755
756
757 // ********** dump DTP metadata **********
758
759 /**
760 * dump all the database metadata to the console
761 */
762 protected void dumpDatabase() {
763 this.dumpDatabase(true);
764 }
765
766 /**
767 * dump the database catalogs and schemata to the console
768 */
769 protected void dumpDatabaseContainers() {
770 this.dumpDatabase(false);
771 }
772
773 protected void dumpDatabase(boolean deep) {
774 IndentingPrintWriter pw = new IndentingPrintWriter(new OutputStreamWriter(System.out));
775 // synchronize the console so everything is contiguous
776 synchronized (System.out) {
777 this.dumpDatabaseOn(pw, deep);
778 }
779 pw.flush();
780 }
781
782 protected void dumpDatabaseOn(IndentingPrintWriter pw, boolean deep) {
783 Database database = this.connectionProfile.getDatabase();
784 pw.print("database: ");
785 pw.println(database.getName());
786 if (database.supportsCatalogs()) {
787 for (Catalog catalog : database.getCatalogs()) {
788 this.dumpCatalogOn(catalog, pw, deep);
789 }
790 } else {
791 this.dumpSchemaContainerOn(database, pw, deep);
792 }
793 }
794
795 protected void dumpCatalogOn(Catalog catalog, IndentingPrintWriter pw, boolean deep) {
796 pw.print("catalog: ");
797 pw.println(catalog.getName());
798 pw.indent();
799 this.dumpSchemaContainerOn(catalog, pw, deep);
800 pw.undent();
801 }
802
803 protected void dumpSchemaContainerOn(SchemaContainer schemaContainer, IndentingPrintWriter pw, boolean deep) {
804 for (Schema schema : schemaContainer.getSchemata()) {
805 this.dumpSchemaOn(schema, pw, deep);
806 }
807 }
808
809 protected void dumpSchema(Schema schema) {
810 this.dumpSchema(schema, true);
811 }
812
813 protected void dumpSchema(Schema schema, boolean deep) {
814 IndentingPrintWriter pw = new IndentingPrintWriter(new OutputStreamWriter(System.out));
815 // synchronize the console so everything is contiguous
816 synchronized (System.out) {
817 this.dumpSchemaOn(schema, pw, deep);
818 }
819 pw.flush();
820 }
821
822 protected void dumpSchemaOn(Schema schema, IndentingPrintWriter pw, boolean deep) {
823 pw.print("schema: ");
824 pw.println(schema.getName());
825 if (deep) {
826 pw.indent();
827 for (Table table : schema.getTables()) {
828 this.dumpTableOn(table, pw);
829 }
830 for (Sequence sequence : schema.getSequences()) {
831 this.dumpSequenceOn(sequence, pw);
832 }
833 pw.undent();
834 }
835 }
836
837 protected void dumpTableOn(Table table, IndentingPrintWriter pw) {
838 pw.print("table: ");
839 pw.println(table.getName());
840 pw.indent();
841 for (Column column : table.getColumns()) {
842 this.dumpColumnOn(column, pw);
843 }
844 for (ForeignKey foreignKey : table.getForeignKeys()) {
845 this.dumpForeignKeyOn(foreignKey, pw);
846 }
847 pw.undent();
848 }
849
850 protected void dumpColumnOn(Column column, IndentingPrintWriter pw) {
851 pw.print("column: ");
852 pw.print(column.getName());
853 pw.print(" : ");
854 pw.print(column.getDataTypeName());
855 if (column.isPartOfPrimaryKey()) {
856 pw.print(" [primary key]");
857 }
858 pw.println();
859 }
860
861 protected void dumpForeignKeyOn(ForeignKey foreignKey, IndentingPrintWriter pw) {
862 pw.print("foreign key: ");
863 pw.print(foreignKey.getName());
864 pw.print("=>");
865 pw.print(foreignKey.getReferencedTable().getName());
866 pw.print(" (");
bvosburghd1d8d172011-03-03 00:11:32 +0000867 for (Iterator<ForeignKey.ColumnPair> stream = foreignKey.getColumnPairs().iterator(); stream.hasNext(); ) {
868 ForeignKey.ColumnPair cp = stream.next();
kmoorec7fdcd42011-02-05 17:01:41 +0000869 pw.print(cp.getBaseColumn().getName());
870 pw.print("=>");
871 pw.print(cp.getReferencedColumn().getName());
872 if (stream.hasNext()) {
873 pw.print(", ");
874 }
875 }
876 pw.print(')');
877 pw.println();
878 }
879
880 protected void dumpSequenceOn(Sequence sequence, IndentingPrintWriter pw) {
881 pw.print("sequence: ");
882 pw.println(sequence.getName());
883 }
884
885
886 // ********** dump JDBC metadata **********
887
888 protected void dumpJDBCCatalogs() throws SQLException {
889 IndentingPrintWriter pw = new IndentingPrintWriter(new OutputStreamWriter(System.out));
890 // synchronize the console so everything is contiguous
891 synchronized (System.out) {
892 this.dumpJDBCCatalogsOn(pw);
893 }
894 pw.flush();
895 }
896
897 protected void dumpJDBCCatalogsOn(IndentingPrintWriter pw) throws SQLException {
898 pw.println("JDBC catalogs: ");
899 pw.indent();
bvosburghd1d8d172011-03-03 00:11:32 +0000900 ArrayList<HashMap<String, Object>> rows = this.buildRows(this.getDatabaseMetaData().getCatalogs());
901 for (Iterator<HashMap<String, Object>> stream = rows.iterator(); stream.hasNext(); ) {
902 HashMap<String, Object> row = stream.next();
903 pw.println(row.get("TABLE_CAT"));
kmoorec7fdcd42011-02-05 17:01:41 +0000904 }
905 pw.undent();
906 }
907
908 protected void dumpJDBCSchemata() throws SQLException {
909 IndentingPrintWriter pw = new IndentingPrintWriter(new OutputStreamWriter(System.out));
910 // synchronize the console so everything is contiguous
911 synchronized (System.out) {
912 this.dumpJDBCSchemataOn(pw);
913 }
914 pw.flush();
915 }
916
917 protected void dumpJDBCSchemataOn(IndentingPrintWriter pw) throws SQLException {
918 pw.println("JDBC schemata: ");
919 pw.indent();
bvosburghd1d8d172011-03-03 00:11:32 +0000920 ArrayList<HashMap<String, Object>> rows = this.buildRows(this.getDatabaseMetaData().getSchemas());
921 for (HashMap<String, Object> row : rows) {
kmoorec7fdcd42011-02-05 17:01:41 +0000922 if (row.size() == 2) { // catalogs were added in jdk 1.4
bvosburghd1d8d172011-03-03 00:11:32 +0000923 Object catalog = row.get("TABLE_CATALOG");
kmoorec7fdcd42011-02-05 17:01:41 +0000924 pw.print(catalog);
925 pw.print('.');
926 }
bvosburghd1d8d172011-03-03 00:11:32 +0000927 Object schema = row.get("TABLE_SCHEM");
kmoorec7fdcd42011-02-05 17:01:41 +0000928 pw.println(schema);
929 }
930 pw.undent();
931 }
932
933
934 // ********** connection profile listener **********
935
936 protected static class TestConnectionProfileListener implements ConnectionProfileListener {
937 public String addedName;
938 public String removedName;
939 public String renamedOldName;
940 public String renamedNewName;
941
942 public void connectionProfileAdded(String name) {
943 this.addedName = name;
944 }
945 public void connectionProfileRemoved(String name) {
946 this.removedName = name;
947 }
948 public void connectionProfileRenamed(String oldName, String newName) {
949 this.renamedOldName = oldName;
950 this.renamedNewName = newName;
951 }
952 public void clear() {
953 this.addedName = null;
954 this.removedName = null;
955 this.renamedOldName = null;
956 this.renamedNewName = null;
957 }
958 }
959
960
961 // ********** connection listener **********
962
963 protected static class TestConnectionListener implements ConnectionListener {
964 public ConnectionProfile openedProfile;
965 public ConnectionProfile modifiedProfile;
966 public ConnectionProfile okToCloseProfile;
967 public ConnectionProfile aboutToCloseProfile;
968 public ConnectionProfile closedProfile;
969 public Database changedDatabase;
970 public Catalog changedCatalog;
971 public Schema changedSchema;
972 public Sequence changedSequence;
973 public Table changedTable;
974 public Column changedColumn;
975 public ForeignKey changedForeignKey;
976
977 public void opened(ConnectionProfile profile) {
978 this.openedProfile = profile;
979 }
980 public void modified(ConnectionProfile profile) {
981 this.modifiedProfile = profile;
982 }
983 public boolean okToClose(ConnectionProfile profile) {
984 this.okToCloseProfile = profile;
985 return true;
986 }
987 public void aboutToClose(ConnectionProfile profile) {
988 this.aboutToCloseProfile = profile;
989 }
990 public void closed(ConnectionProfile profile) {
991 this.closedProfile = profile;
992 }
993 public void databaseChanged(ConnectionProfile profile, Database database) {
994 this.changedDatabase = database;
995 }
996 public void catalogChanged(ConnectionProfile profile, Catalog catalog) {
997 this.changedCatalog = catalog;
998 }
999 public void schemaChanged(ConnectionProfile profile, Schema schema) {
1000 this.changedSchema = schema;
1001 }
1002 public void sequenceChanged(ConnectionProfile profile, Sequence sequence) {
1003 this.changedSequence = sequence;
1004 }
1005 public void tableChanged(ConnectionProfile profile, Table table) {
1006 this.changedTable = table;
1007 }
1008 public void columnChanged(ConnectionProfile profile, Column column) {
1009 this.changedColumn = column;
1010 }
1011 public void foreignKeyChanged(ConnectionProfile profile, ForeignKey foreignKey) {
1012 this.changedForeignKey = foreignKey;
1013 }
1014 public void clear() {
1015 this.openedProfile = null;
1016 this.modifiedProfile = null;
1017 this.okToCloseProfile = null;
1018 this.aboutToCloseProfile = null;
1019 this.closedProfile = null;
1020 this.changedDatabase = null;
1021 this.changedCatalog = null;
1022 this.changedSchema = null;
1023 this.changedSequence = null;
1024 this.changedTable = null;
1025 this.changedColumn = null;
1026 this.changedForeignKey = null;
1027 }
1028 }
1029
1030}