001: package com.quantum.dbunit.wizard;
002:
003: import java.io.File;
004: import java.io.FileOutputStream;
005: import java.sql.Connection;
006: import java.sql.DatabaseMetaData;
007: import java.sql.SQLException;
008:
009: import org.dbunit.database.DatabaseConfig;
010: import org.dbunit.database.DatabaseConnection;
011: import org.dbunit.database.DatabaseSequenceFilter;
012: import org.dbunit.database.ForwardOnlyResultSetTableFactory;
013: import org.dbunit.database.IDatabaseConnection;
014: import org.dbunit.dataset.Column;
015: import org.dbunit.dataset.FilteredDataSet;
016: import org.dbunit.dataset.IDataSet;
017: import org.dbunit.dataset.filter.IColumnFilter;
018: import org.dbunit.dataset.filter.ITableFilter;
019: import org.dbunit.dataset.stream.IDataSetProducer;
020: import org.dbunit.dataset.stream.StreamingDataSet;
021: import org.dbunit.dataset.xml.FlatXmlDataSet;
022: import org.dbunit.dataset.xml.FlatXmlProducer;
023: import org.dbunit.ext.db2.Db2DataTypeFactory;
024: import org.dbunit.ext.mssql.MsSqlDataTypeFactory;
025: import org.dbunit.ext.mysql.MySqlDataTypeFactory;
026: import org.dbunit.ext.oracle.OracleDataTypeFactory;
027: import org.dbunit.operation.DatabaseOperation;
028: import org.eclipse.jface.dialogs.MessageDialog;
029: import org.eclipse.swt.widgets.Shell;
030: import org.xml.sax.InputSource;
031:
032: import com.quantum.adapters.AdapterFactory;
033: import com.quantum.adapters.DatabaseAdapter;
034: import com.quantum.model.Bookmark;
035: import com.quantum.model.Entity;
036:
037: /**
038: * @author Julen
039: *
040: */
041:
042: //Void primary key filter to avoid getPrimaryKeys calls in substandard drivers
043: class MyPrimaryKeyFilter implements IColumnFilter {
044:
045: /* (non-Javadoc)
046: * @see org.dbunit.dataset.filter.IColumnFilter#accept(java.lang.String, org.dbunit.dataset.Column)
047: */
048: public boolean accept(String arg0, Column arg1) {
049: return false;
050: }
051: }
052:
053: /**
054: * Will convert to and from dbunit flatXML format
055: */
056: public class ConverterDBUnit {
057:
058: /**
059: * Dumps in the outputStream the selected entities, using the dbUnit XML format
060: *
061: * @param outputStream An open output stream into which dump all the entities data
062: * @param entities An array of selected Entities (Tables or Views or Synonyms)
063: * They should be filtered so only Tables (or Views or Synonyms) are present, no mixing.
064: * @param schema The schema of the entities, if all are from the same schema, null if not
065: * @param useDBSequence If an ordering based on the foreign keys dependences must be used
066: * @param qualifyNames If the table names should be qualified with the schema
067: * @throws Exception
068: */
069: public void convert(FileOutputStream outputStream,
070: Entity[] entities, String schema, boolean useDBSequence,
071: boolean qualifyNames, Shell shell) throws Exception {
072: if (entities.length < 1)
073: return;
074: Connection connection = entities[0].getBookmark()
075: .getConnection();
076: DatabaseAdapter adapter = entities[0].getBookmark()
077: .getAdapter();
078: if (connection == null)
079: return;
080:
081: IDatabaseConnection dbUnitConnection;
082: if (schema != null) {
083: dbUnitConnection = new DatabaseConnection(connection,
084: entities[0].getSchema());
085: } else {
086: dbUnitConnection = new DatabaseConnection(connection);
087: }
088: DatabaseConfig config = dbUnitConnection.getConfig();
089: // Set the type of recordset to be the simplest one, allows bigger recordset without running out of memory
090: // We can only do this if not going to use the DB Sequence to optimize foreign key order
091: if (!useDBSequence) {
092: config.setProperty(
093: DatabaseConfig.PROPERTY_RESULTSET_TABLE_FACTORY,
094: new ForwardOnlyResultSetTableFactory());
095: }
096:
097: // Will recognize tables and views and synonyms, no mixing allowed due to limitations of some drivers (DB2)
098: // The entities array should be already filtered, so the type of the first one should be the type of all.
099: // (isSynonym() MUST be checked first, as synonyms can also be tables or views)
100: if (entities[0].isSynonym())
101: config.setProperty(DatabaseConfig.PROPERTY_TABLE_TYPE,
102: new String[] { "SYNONYM" });
103: else if (entities[0].getType().equals(Entity.TABLE_TYPE))
104: config.setProperty(DatabaseConfig.PROPERTY_TABLE_TYPE,
105: new String[] { "TABLE" });
106: else if (entities[0].getType().equals(Entity.VIEW_TYPE))
107: config.setProperty(DatabaseConfig.PROPERTY_TABLE_TYPE,
108: new String[] { "VIEW" });
109:
110: // Some databases have data factories, better use them
111: if (adapter.getType().equals(AdapterFactory.DB2))
112: config.setProperty(
113: DatabaseConfig.PROPERTY_DATATYPE_FACTORY,
114: new Db2DataTypeFactory());
115: else if (adapter.getType().equals(AdapterFactory.ORACLE))
116: config.setProperty(
117: DatabaseConfig.PROPERTY_DATATYPE_FACTORY,
118: new OracleDataTypeFactory());
119: else if (adapter.getType().equals(AdapterFactory.MYSQL))
120: config.setProperty(
121: DatabaseConfig.PROPERTY_DATATYPE_FACTORY,
122: new MySqlDataTypeFactory());
123: else if (adapter.getType().equals(AdapterFactory.MS_SQL_SERVER))
124: config.setProperty(
125: DatabaseConfig.PROPERTY_DATATYPE_FACTORY,
126: new MsSqlDataTypeFactory());
127:
128: DatabaseMetaData metadata = connection.getMetaData();
129: // Check if the jdbc driver supports the getPrimaryKeys call
130: // If if does't, the export will fail, and we need to define a void filter for primary keys
131: boolean limitedDriver = false;
132: try {
133: metadata.getPrimaryKeys(null, null, null);
134: } catch (SQLException e) {
135: limitedDriver = true;
136: // If it doesn't, instruct it to not use the getPrimaryKeys(), define a void filter
137: config.setProperty(
138: DatabaseConfig.PROPERTY_PRIMARY_KEY_FILTER,
139: new MyPrimaryKeyFilter());
140: } catch (Exception e) {
141: // do nothing, it fails but it's not an SQLException, perhaps they don't like the
142: // three null parameters. In any case, possibly supports the operation, because if not
143: // it's easier to simply return an SQLException.
144: }
145:
146: //If names are to be qualified we inform dbunit of the fact
147: if (qualifyNames) {
148: config.setFeature(
149: DatabaseConfig.FEATURE_QUALIFIED_TABLE_NAMES, true);
150: }
151: // Make an array with the table names
152: String[] tableNames = new String[entities.length];
153: for (int i = 0; i < entities.length; i++) {
154: if (qualifyNames) {
155: tableNames[i] = entities[i].getQualifiedName();
156: } else {
157: tableNames[i] = entities[i].getName();
158: }
159: }
160: IDataSet dataSet = null;
161: // If the driver doesn't know about keys, won't know about foreign keys
162: if (limitedDriver || !useDBSequence) {
163: dataSet = dbUnitConnection.createDataSet(tableNames);
164: } else {
165: // If driver supports it, and user desires it,
166: // we export in the best order to maintain foreign keys
167: ITableFilter filter = new DatabaseSequenceFilter(
168: dbUnitConnection, tableNames);
169: dataSet = new FilteredDataSet(filter, dbUnitConnection
170: .createDataSet());
171: }
172: try {
173: FlatXmlDataSet.write(dataSet, outputStream);
174: } catch (Exception e) {
175: MessageDialog.openInformation(shell, e.toString(), e
176: .getLocalizedMessage());
177: }
178: }
179:
180: /**
181: * Extracts from the file represented by the fileName the rows previously written there, and puts them back into
182: * the proper tables
183: *
184: * @param fileName The file name with the XML file in dbUnit format
185: * @param bookmark The bookmark where the tables to be filled are located
186: * @param deletePreviousContent
187: * @param namesAreQualified
188: * @throws Exception
189: */
190: public void convert(String fileName, Bookmark bookmark,
191: String schema, boolean deletePreviousContent,
192: boolean namesAreQualified) throws Exception {
193:
194: Connection connection;
195: connection = bookmark.getConnection();
196: IDatabaseConnection dbUnitConnection = null;
197: DatabaseMetaData metadata = connection.getMetaData();
198:
199: // The schema tells the dbunit library to "hard-code" a schema. If we have qualified names, that already
200: // have their schema, will return an error.
201: if (schema != null && !schema.equals("")
202: && metadata.supportsSchemasInDataManipulation()
203: && !namesAreQualified) {
204: dbUnitConnection = new DatabaseConnection(connection,
205: schema);
206: } else {
207: dbUnitConnection = new DatabaseConnection(connection);
208: }
209:
210: // Check if the jdbc driver supports the getPrimaryKeys call
211: // If if does't, the import will fail, and we need to define a void filter for primary keys
212: DatabaseConfig config = dbUnitConnection.getConfig();
213: if (namesAreQualified) {
214: config.setFeature(
215: DatabaseConfig.FEATURE_QUALIFIED_TABLE_NAMES, true);
216: }
217: boolean limitedDriver = false;
218: try {
219: metadata.getPrimaryKeys(null, null, "");
220: } catch (SQLException e) {
221: limitedDriver = true;
222: // If it doesn't, instruct it to not use the getPrimaryKeys(), define a void filter
223: config.setProperty(
224: DatabaseConfig.PROPERTY_PRIMARY_KEY_FILTER,
225: new MyPrimaryKeyFilter());
226: }
227:
228: // This won't work, complaining about only one iterator allowed
229: InputSource source = new InputSource(new File(fileName).toURL()
230: .toString());
231: IDataSetProducer producer = new FlatXmlProducer(source);
232: IDataSet insertDataSet = new StreamingDataSet(producer);
233:
234: //FileInputStream stream = new FileInputStream(fileName);
235: //IDataSet dataSet = new FlatXmlDataSet(stream);
236: if (deletePreviousContent) {
237: IDataSet deleteDataSet = new StreamingDataSet(producer);
238: DatabaseOperation.DELETE_ALL.execute(dbUnitConnection,
239: deleteDataSet);
240: DatabaseOperation.INSERT.execute(dbUnitConnection,
241: insertDataSet);
242: } else {
243: // To do a proper REFRESH, we need primary keys
244: if (limitedDriver)
245: DatabaseOperation.REFRESH.execute(dbUnitConnection,
246: insertDataSet);
247: else
248: DatabaseOperation.REFRESH.execute(dbUnitConnection,
249: insertDataSet);
250: }
251: }
252: }
|