# HG changeset patch # Parent b217c2e86a3354ea4f66f84023a343c4820d02c5 # User Matthias Bläsing Improve EDT handling - add assertions about EDT expectations - fix unittests and adjust to expectations - move EDT relevant actions into the EDT (-> updates to the datamodel et. all.) diff --git a/db.dataview/src/org/netbeans/modules/db/dataview/output/DataView.java b/db.dataview/src/org/netbeans/modules/db/dataview/output/DataView.java --- a/db.dataview/src/org/netbeans/modules/db/dataview/output/DataView.java +++ b/db.dataview/src/org/netbeans/modules/db/dataview/output/DataView.java @@ -218,10 +218,17 @@ return dataViewUI.get(0).getEditButtons(); } - public synchronized void setEditable(boolean editable) { - for (DataViewPageContext pageContext : dataPage) { - pageContext.getModel().setEditable(editable); - } + public synchronized void setEditable(final boolean editable) { + Mutex.EVENT.writeAccess(new Mutex.Action() { + @Override + public Void run() { + for (DataViewPageContext pageContext : dataPage) { + pageContext.getModel().setEditable(editable); + } + return null; + } + }); + } // Used by org.netbeans.modules.db.dataview.api.DataViewPageContext#getPageSize @@ -242,11 +249,17 @@ return this.dataPage.get(i); } - DataViewPageContext addPageContext(DataViewDBTable table) { - DataViewPageContext pageContext = new DataViewPageContext(initialPageSize); + DataViewPageContext addPageContext(final DataViewDBTable table) { + final DataViewPageContext pageContext = new DataViewPageContext(initialPageSize); this.dataPage.add(pageContext); - pageContext.setTableMetaData(table); - pageContext.getModel().setColumns(table.getColumns().toArray(new DBColumn[0])); + Mutex.EVENT.writeAccess(new Mutex.Action() { + @Override + public Void run() { + pageContext.setTableMetaData(table); + pageContext.getModel().setColumns(table.getColumns().toArray(new DBColumn[0])); + return null; + } + }); return pageContext; } @@ -273,20 +286,30 @@ } public void resetEditable() { - for(DataViewPageContext pageContext: dataPage) { - pageContext.resetEditableState(); - } + Mutex.EVENT.readAccess(new Runnable() { + @Override + public void run() { + for (DataViewPageContext pageContext : dataPage) { + pageContext.resetEditableState(); + } + } + }); } public boolean isEditable() { if(dataPage.isEmpty()) { return false; } else { - boolean editable = true; - for(DataViewPageContext pageContext: dataPage) { - editable &= pageContext.getModel().isEditable(); - } - return editable; + return Mutex.EVENT.readAccess(new Mutex.Action() { + @Override + public Boolean run() { + boolean editable = true; + for (DataViewPageContext pageContext : dataPage) { + editable &= pageContext.getModel().isEditable(); + } + return editable; + } + }); } } diff --git a/db.dataview/src/org/netbeans/modules/db/dataview/output/DataViewActionHandler.java b/db.dataview/src/org/netbeans/modules/db/dataview/output/DataViewActionHandler.java --- a/db.dataview/src/org/netbeans/modules/db/dataview/output/DataViewActionHandler.java +++ b/db.dataview/src/org/netbeans/modules/db/dataview/output/DataViewActionHandler.java @@ -112,35 +112,35 @@ .setStoredPageSize(pageSize); dataPage.first(); dataPage.setTotalRows(-1); // force total row refresh - execHelper.executeQuery(); + execHelper.executeQueryOffEDT(); } } void firstActionPerformed() { if (rejectModifications()) { dataPage.first(); - execHelper.executeQuery(); + execHelper.executeQueryOffEDT(); } } void previousActionPerformed() { if (rejectModifications()) { dataPage.previous(); - execHelper.executeQuery(); + execHelper.executeQueryOffEDT(); } } void nextActionPerformed() { if (rejectModifications()) { dataPage.next(); - execHelper.executeQuery(); + execHelper.executeQueryOffEDT(); } } void lastActionPerformed() { if (rejectModifications()) { dataPage.last(); - execHelper.executeQuery(); + execHelper.executeQueryOffEDT(); } } @@ -189,7 +189,7 @@ void refreshActionPerformed() { dataPage.setTotalRows(-1); // force total row refresh - execHelper.executeQuery(); + execHelper.executeQueryOffEDT(); } private static Object showYesAllDialog(Object msg, String title) { diff --git a/db.dataview/src/org/netbeans/modules/db/dataview/output/DataViewPageContext.java b/db.dataview/src/org/netbeans/modules/db/dataview/output/DataViewPageContext.java --- a/db.dataview/src/org/netbeans/modules/db/dataview/output/DataViewPageContext.java +++ b/db.dataview/src/org/netbeans/modules/db/dataview/output/DataViewPageContext.java @@ -173,10 +173,6 @@ return (isLastPage() && model.getRowCount() <= pageSize); } - boolean hasDataRows() { - return model.getRowCount() > 0; - } - String pageOf() { String curPage = NbBundle.getMessage(DataViewUI.class, "LBL_not_available"); String totalPages = NbBundle.getMessage(DataViewUI.class, "LBL_not_available"); diff --git a/db.dataview/src/org/netbeans/modules/db/dataview/output/DataViewTableUI.java b/db.dataview/src/org/netbeans/modules/db/dataview/output/DataViewTableUI.java --- a/db.dataview/src/org/netbeans/modules/db/dataview/output/DataViewTableUI.java +++ b/db.dataview/src/org/netbeans/modules/db/dataview/output/DataViewTableUI.java @@ -146,9 +146,7 @@ @Override public TableCellRenderer getCellRenderer(int row, int column) { - if (row < getModel().getRowCount() - && column < getModel().getColumnCount() - && getModel().hasUpdates( + if (getModel().hasUpdates( convertRowIndexToModel(row), convertColumnIndexToModel(column))) { return new UpdatedResultSetCellRenderer(); diff --git a/db.dataview/src/org/netbeans/modules/db/dataview/output/DataViewTableUIModel.java b/db.dataview/src/org/netbeans/modules/db/dataview/output/DataViewTableUIModel.java --- a/db.dataview/src/org/netbeans/modules/db/dataview/output/DataViewTableUIModel.java +++ b/db.dataview/src/org/netbeans/modules/db/dataview/output/DataViewTableUIModel.java @@ -47,6 +47,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import javax.swing.SwingUtilities; import org.netbeans.modules.db.dataview.meta.DBColumn; import org.netbeans.modules.db.dataview.table.ResultSetTableModel; @@ -68,6 +69,7 @@ @Override public void setValueAt(Object value, int row, int col) { + assert SwingUtilities.isEventDispatchThread() : "Not on EDT"; Object oldval = getValueAt(row, col); if (noUpdateRequired(oldval, value)) { return; @@ -77,6 +79,7 @@ } public Object getOriginalValueAt(int row, int col) { + assert SwingUtilities.isEventDispatchThread() : "Not on EDT"; if(hasUpdates(row, col)) { return oldData.get(row).get(col); } else { @@ -86,23 +89,27 @@ @Override public void setData(List data) { + assert SwingUtilities.isEventDispatchThread() : "Not on EDT"; super.setData(data); oldData.clear(); } @Override public void removeRow(int row) { + assert SwingUtilities.isEventDispatchThread() : "Not on EDT"; super.removeRow(row); oldData.remove(row); } @Override public void clear() { + assert SwingUtilities.isEventDispatchThread() : "Not on EDT"; super.clear(); oldData.clear(); } private void addUpdates(int row, int col, Object value) { + assert SwingUtilities.isEventDispatchThread() : "Not on EDT"; Map rowMap = oldData.get(row); if (rowMap == null) { rowMap = new LinkedHashMap(); @@ -115,6 +122,7 @@ } public void removeAllUpdates(boolean discardNewValue) { + assert SwingUtilities.isEventDispatchThread() : "Not on EDT"; for(Integer rowIndex: new HashSet(oldData.keySet())) { Map oldRow = oldData.remove(rowIndex); if (discardNewValue) { @@ -127,6 +135,7 @@ } public void removeUpdateForSelectedRow(int row, boolean discardNewValue) { + assert SwingUtilities.isEventDispatchThread() : "Not on EDT"; if (oldData.containsKey(row)) { Map oldRow = oldData.remove(row); if (discardNewValue) { @@ -139,6 +148,7 @@ } public void removeUpdate(int row, int col, boolean discardNewValue) { + assert SwingUtilities.isEventDispatchThread() : "Not on EDT"; if (oldData.containsKey(row)) { Map oldRow = oldData.get(row); if (oldRow.containsKey(col)) { @@ -155,10 +165,12 @@ } public Set getUpdateKeys() { + assert SwingUtilities.isEventDispatchThread() : "Not on EDT"; return oldData.keySet(); } public Map getChangedData(int row) { + assert SwingUtilities.isEventDispatchThread() : "Not on EDT"; Set changedColumns = oldData.get(row).keySet(); Map result = new HashMap(); for(Integer column: changedColumns) { @@ -168,10 +180,12 @@ } boolean hasUpdates() { + assert SwingUtilities.isEventDispatchThread() : "Not on EDT"; return oldData.size() > 0; } boolean hasUpdates(int row, int col) { + assert SwingUtilities.isEventDispatchThread() : "Not on EDT"; Map rowMap = oldData.get(new Integer(row)); return rowMap != null && rowMap.containsKey(new Integer(col)); } diff --git a/db.dataview/src/org/netbeans/modules/db/dataview/output/InsertRecordDialog.java b/db.dataview/src/org/netbeans/modules/db/dataview/output/InsertRecordDialog.java --- a/db.dataview/src/org/netbeans/modules/db/dataview/output/InsertRecordDialog.java +++ b/db.dataview/src/org/netbeans/modules/db/dataview/output/InsertRecordDialog.java @@ -61,6 +61,7 @@ import java.util.Arrays; import java.util.List; import java.util.StringTokenizer; +import java.util.concurrent.ExecutionException; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.AbstractAction; @@ -73,6 +74,7 @@ import javax.swing.KeyStroke; import javax.swing.SwingConstants; import javax.swing.SwingUtilities; +import javax.swing.SwingWorker; import javax.swing.border.EmptyBorder; import javax.swing.event.TableModelEvent; import javax.swing.event.TableModelListener; @@ -98,6 +100,8 @@ * */ class InsertRecordDialog extends javax.swing.JDialog { + private static final Logger LOG = Logger.getLogger(InsertRecordDialog.class.getName()); + private final ResultSetTableModel insertDataModel; private final DBTable insertTable; private final DataView dataView; @@ -374,41 +378,70 @@ if (insertRecordTableUI.isEditing()) { insertRecordTableUI.getCellEditor().stopCellEditing(); } + + final int rows = insertRecordTableUI.getRowCount(); + final Object[][] insertedRows = new Object[rows][insertTable.getColumnList().size()]; + + try { + for (int i = 0; i < rows; i++) { + insertedRows[i] = getInsertValues(i); + } + } catch (DBException ex) { + LOG.log(Level.INFO, ex.getLocalizedMessage(), ex); + DialogDisplayer.getDefault().notifyLater( + new NotifyDescriptor.Message(ex.getLocalizedMessage())); + return; + } + // Get out of AWT thread because SQLExecutionHelper does calls to AWT // and we need to wait here to show possible exceptions. - new Thread("Inserting values") { //NOI18N + new SwingWorker() { @Override - public void run() { - String insertSQL = null; + protected Integer doInBackground() throws Exception { SQLStatementGenerator stmtBldr = dataView.getSQLStatementGenerator(); SQLExecutionHelper execHelper = dataView.getSQLExecutionHelper(); - for (int i = 0; i < insertRecordTableUI.getRowCount(); i++) { - boolean wasException = false; + for (int i = 0; i < rows; i++) { + boolean wasException; try { - Object[] insertedRow = getInsertValues(i); - insertSQL = stmtBldr.generateInsertStatement(insertTable, insertedRow); + Object[] insertedRow = insertedRows[i]; + String insertSQL = stmtBldr.generateInsertStatement(insertTable, insertedRow); RequestProcessor.Task task = execHelper.executeInsertRow(pageContext, insertTable, insertSQL, insertedRow); task.waitFinished(); wasException = dataView.hasExceptions(); } catch (DBException ex) { - Logger.getLogger(InsertRecordDialog.class.getName()).log(Level.INFO, ex.getLocalizedMessage(), ex); + LOG.log(Level.INFO, ex.getLocalizedMessage(), ex); DialogDisplayer.getDefault().notifyLater(new NotifyDescriptor.Message(ex.getLocalizedMessage())); wasException = true; } if (wasException) { + return i; + } + } + return null; + } + + @Override + protected void done() { + Integer brokeOn; + try { + brokeOn = get(); + + if (brokeOn == null) { + dispose(); + } else { // remove i already inserted - for (int j = 0; j < i; j++) { + for (int j = 0; j < brokeOn; j++) { insertRecordTableUI.getModel().removeRow(0); } - // return without closing - return; } + } catch (InterruptedException ex) { + throw new RuntimeException(ex); + } catch (ExecutionException ex) { + throw new RuntimeException(ex); } - // close dialog - dispose(); } - }.start(); + }.execute(); } private void previewBtnActionPerformed(java.awt.event.ActionEvent evt) { @@ -607,7 +640,7 @@ } } } catch (Exception ex) { - java.util.logging.Logger.getLogger(InsertRecordDialog.class.getName()).info("Failed to paste the contents " + ex); + LOG.log(Level.INFO, "Failed to paste the contents ", ex); } } diff --git a/db.dataview/src/org/netbeans/modules/db/dataview/output/SQLExecutionHelper.java b/db.dataview/src/org/netbeans/modules/db/dataview/output/SQLExecutionHelper.java --- a/db.dataview/src/org/netbeans/modules/db/dataview/output/SQLExecutionHelper.java +++ b/db.dataview/src/org/netbeans/modules/db/dataview/output/SQLExecutionHelper.java @@ -60,6 +60,7 @@ import java.util.concurrent.Future; import java.util.logging.Level; import java.util.logging.Logger; +import javax.swing.SwingUtilities; import org.netbeans.modules.db.dataview.meta.DBColumn; import org.netbeans.modules.db.dataview.meta.DBConnectionFactory; import org.netbeans.modules.db.dataview.meta.DBException; @@ -70,6 +71,7 @@ import org.openide.DialogDisplayer; import org.openide.NotifyDescriptor; import org.openide.util.Cancellable; +import org.openide.util.Mutex; import org.openide.util.NbBundle; import org.openide.util.RequestProcessor; @@ -92,7 +94,8 @@ } void initialDataLoad() throws SQLException { - + assert (! SwingUtilities.isEventDispatchThread()) : "Must be called of the EDT!"; + /** * Wrap initializing the SQL result into a runnable. This makes it * possible to wait for the result in the main thread and cancel the @@ -295,6 +298,8 @@ final DBTable table, final String insertSQL, final Object[] insertedRow) { + dataView.setEditable(false); + String title = NbBundle.getMessage(SQLExecutionHelper.class, "LBL_sql_insert"); SQLStatementExecutor executor = new SQLStatementExecutor(dataView, title, "") { @@ -337,17 +342,28 @@ @Override protected void executeOnSucess() { - if (pageContext.getTotalRows() < 0) { - pageContext.setTotalRows(0); - pageContext.first(); - } - pageContext.incrementRowSize(1); + // refresh when required + Boolean needRequery = Mutex.EVENT.readAccess(new Mutex.Action() { + @Override + public Boolean run() { + if (pageContext.getTotalRows() < 0) { + pageContext.setTotalRows(0); + pageContext.first(); + } + pageContext.incrementRowSize(1); - // refresh when required - if (pageContext.refreshRequiredOnInsert()) { + return pageContext.refreshRequiredOnInsert(); + }; + }); + if(needRequery) { SQLExecutionHelper.this.executeQuery(); } else { - reinstateToolbar(); + Mutex.EVENT.readAccess(new Runnable() { + @Override + public void run() { + reinstateToolbar(); + } + }); } } }; @@ -358,36 +374,43 @@ } void executeDeleteRow(final DataViewPageContext pageContext, final DBTable table, final DataViewTableUI rsTable) { + dataView.setEditable(false); + + SQLStatementGenerator generator = dataView.getSQLStatementGenerator(); String title = NbBundle.getMessage(SQLExecutionHelper.class, "LBL_sql_delete"); - final int[] rows = rsTable.getSelectedRows(); - for(int i = 0; i < rows.length; i++) { - rows[i] = rsTable.convertRowIndexToModel(rows[i]); + + class DeleteElement { + public List values = new ArrayList(); + public List types = new ArrayList(); + public String sql; } - Arrays.sort(rows); + + final List rows = new ArrayList(); + for(int viewRow: rsTable.getSelectedRows()) { + int modelRow = rsTable.convertRowIndexToModel(viewRow); + DeleteElement de = new DeleteElement(); + de.sql = generator.generateDeleteStatement(table, de.types, de.values, modelRow, rsTable.getModel()); + rows.add(de); + } + SQLStatementExecutor executor = new SQLStatementExecutor(dataView, title, "") { - @Override public void execute() throws SQLException, DBException { dataView.setEditable(false); - for (int j = (rows.length - 1); j >= 0 && !error; j--) { - if (Thread.currentThread().isInterrupted()) { + for (DeleteElement de: rows) { + if (Thread.currentThread().isInterrupted() || error) { break; } - deleteARow(rows[j], rsTable.getModel()); + deleteARow(de); } } - private void deleteARow(int rowNum, DataViewTableUIModel tblModel) throws SQLException, DBException { - final List values = new ArrayList(); - final List types = new ArrayList(); - - SQLStatementGenerator generator = dataView.getSQLStatementGenerator(); - final String deleteStmt = generator.generateDeleteStatement(table, types, values, rowNum, tblModel); - PreparedStatement pstmt = conn.prepareStatement(deleteStmt); + private void deleteARow(DeleteElement deleteRow) throws SQLException, DBException { + PreparedStatement pstmt = conn.prepareStatement(deleteRow.sql); try { int pos = 1; - for (Object val : values) { - DBReadWriteHelper.setAttributeValue(pstmt, pos, types.get(pos - 1), val); + for (Object val : deleteRow.values) { + DBReadWriteHelper.setAttributeValue(pstmt, pos, deleteRow.types.get(pos - 1), val); pos++; } @@ -413,7 +436,7 @@ @Override protected void executeOnSucess() { - pageContext.decrementRowSize(rows.length); + pageContext.decrementRowSize(rows.size()); SQLExecutionHelper.this.executeQuery(); } }; @@ -424,8 +447,44 @@ } void executeUpdateRow(final DBTable table, final DataViewTableUI rsTable, final boolean selectedOnly) { + dataView.setEditable(false); + + SQLStatementGenerator generator = dataView.getSQLStatementGenerator(); final DataViewTableUIModel dataViewTableUIModel = rsTable.getModel(); String title = NbBundle.getMessage(SQLExecutionHelper.class, "LBL_sql_update"); + + class UpdateElement { + public List values = new ArrayList(); + public List types = new ArrayList(); + public String sql; + public Integer key; + } + + final List updateSet = new ArrayList(); + + int[] viewRows = rsTable.getSelectedRows(); + List modelRows = new ArrayList(); + for(Integer viewRow: viewRows) { + modelRows.add(rsTable.convertRowIndexToModel(viewRow)); + } + + for (Integer key : dataViewTableUIModel.getUpdateKeys()) { + if (modelRows.contains(key) || (!selectedOnly)) { + UpdateElement ue = new UpdateElement(); + try { + ue.key = key; + ue.sql = generator.generateUpdateStatement(table, key, + dataViewTableUIModel.getChangedData(key), ue.values, ue.types, + rsTable.getModel()); + updateSet.add(ue); + } catch (DBException ex) { + // The model protects against illegal values, so rethrow + throw new RuntimeException(ex); + } + } + } + + SQLStatementExecutor executor = new SQLStatementExecutor(dataView, title, "") { private PreparedStatement pstmt; @@ -433,47 +492,20 @@ @Override public void execute() throws SQLException, DBException { - dataView.setEditable(false); - if (selectedOnly) { - updateSelected(); - } else { - for (Integer key : dataViewTableUIModel.getUpdateKeys()) { - if (Thread.currentThread().isInterrupted()) { - break; - } else { - updateARow(key); - keysToRemove.add(key); - } + for (UpdateElement ue : updateSet) { + if(Thread.interrupted()) { + break; } + updateARow(ue); + keysToRemove.add(ue.key); } } - private void updateSelected() throws SQLException, DBException { - int[] rows = rsTable.getSelectedRows(); - for (int j = 0; j < rows.length && !error; j++) { - Set keys = dataViewTableUIModel.getUpdateKeys(); - for (Integer key : keys) { - if (Thread.currentThread().isInterrupted()) { - break; - } else if (key == rows[j]) { - updateARow(key); - keysToRemove.add(key); - } - } - } - } - - private void updateARow(Integer key) throws SQLException, DBException { - SQLStatementGenerator generator = dataView.getSQLStatementGenerator(); - - List values = new ArrayList(); - List types = new ArrayList(); - String updateStmt = generator.generateUpdateStatement(table, key, dataViewTableUIModel.getChangedData(key), values, types, rsTable.getModel()); - - pstmt = conn.prepareStatement(updateStmt); + private void updateARow(UpdateElement ue) throws SQLException, DBException { + pstmt = conn.prepareStatement(ue.sql); int pos = 1; - for (Object val : values) { - DBReadWriteHelper.setAttributeValue(pstmt, pos, types.get(pos - 1), val); + for (Object val : ue.values) { + DBReadWriteHelper.setAttributeValue(pstmt, pos, ue.types.get(pos - 1), val); pos++; } @@ -500,11 +532,17 @@ @Override protected void executeOnSucess() { - DataViewTableUIModel tblContext = rsTable.getModel(); - for (Integer key : keysToRemove) { - tblContext.removeUpdateForSelectedRow(key, false); - } - reinstateToolbar(); + Mutex.EVENT.writeAccess(new Runnable() { + @Override + public void run() { + DataViewTableUIModel tblContext = rsTable.getModel(); + for (Integer key : keysToRemove) { + tblContext.removeUpdateForSelectedRow(key, false); + } + + reinstateToolbar(); + } + }); } }; RequestProcessor.Task task = rp.create(executor); @@ -555,8 +593,19 @@ task.schedule(0); } + void executeQueryOffEDT() { + rp.post(new Runnable() { + @Override + public void run() { + executeQuery(); + } + }); + } + // Once Data View is created the it assumes the query never changes. void executeQuery() { + assert (! SwingUtilities.isEventDispatchThread()); + String title = NbBundle.getMessage(SQLExecutionHelper.class, "LBL_sql_executequery"); SQLStatementExecutor executor = new SQLStatementExecutor(dataView, title, dataView.getSQLString()) { @@ -662,7 +711,7 @@ task.schedule(0); } - void loadDataFrom(DataViewPageContext pageContext, ResultSet rs, boolean getTotal) throws SQLException { + private void loadDataFrom(final DataViewPageContext pageContext, ResultSet rs, boolean getTotal) throws SQLException { if (rs == null) { return; } @@ -670,7 +719,7 @@ int pageSize = pageContext.getPageSize(); int startFrom = pageContext.getCurrentPos(); - List rows = new ArrayList(); + final List rows = new ArrayList(); int colCnt = pageContext.getTableMetaData().getColumnCount(); try { boolean hasNext = false; @@ -742,7 +791,13 @@ LOGGER.log(Level.SEVERE, "Failed to set up table model.", e); // NOI18N throw e; } finally { - pageContext.getModel().setData(rows); + Mutex.EVENT.writeAccess(new Mutex.Action() { + @Override + public Void run() { + pageContext.getModel().setData(rows); + return null; + } + }); } } diff --git a/db.dataview/src/org/netbeans/modules/db/dataview/output/SQLStatementGenerator.java b/db.dataview/src/org/netbeans/modules/db/dataview/output/SQLStatementGenerator.java --- a/db.dataview/src/org/netbeans/modules/db/dataview/output/SQLStatementGenerator.java +++ b/db.dataview/src/org/netbeans/modules/db/dataview/output/SQLStatementGenerator.java @@ -54,6 +54,7 @@ import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; +import javax.swing.SwingUtilities; import org.netbeans.modules.db.dataview.meta.DBColumn; import org.netbeans.modules.db.dataview.meta.DBException; import org.netbeans.modules.db.dataview.meta.DBMetaDataFactory; @@ -367,6 +368,8 @@ } void generateWhereCondition(DBTable table, StringBuilder result, List types, List values, int rowNum, DataViewTableUIModel model) { + assert SwingUtilities.isEventDispatchThread() : "Needs to be called on the EDT"; + DBPrimaryKey key = table.getPrimaryKey(); Set columnsSelected = new HashSet(); boolean and = false; @@ -411,6 +414,8 @@ } void generateWhereCondition(DBTable table, StringBuilder sql, int rowNum, DataViewTableUIModel model) { + assert SwingUtilities.isEventDispatchThread() : "Needs to be called on the EDT"; + DBPrimaryKey key = table.getPrimaryKey(); Set columnsSelected = new HashSet(); boolean and = false; diff --git a/db.dataview/src/org/netbeans/modules/db/dataview/table/ResultSetTableModel.java b/db.dataview/src/org/netbeans/modules/db/dataview/table/ResultSetTableModel.java --- a/db.dataview/src/org/netbeans/modules/db/dataview/table/ResultSetTableModel.java +++ b/db.dataview/src/org/netbeans/modules/db/dataview/table/ResultSetTableModel.java @@ -55,6 +55,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import javax.swing.SwingUtilities; import javax.swing.table.AbstractTableModel; import org.netbeans.modules.db.dataview.meta.DBColumn; import org.netbeans.modules.db.dataview.util.DBReadWriteHelper; @@ -72,7 +73,7 @@ private final List data = new ArrayList(); private final PropertyChangeSupport pcs = new PropertyChangeSupport(this); - public static Class getTypeClass(DBColumn col) { + protected static Class getTypeClass(DBColumn col) { int colType = col.getJdbcType(); if (colType == Types.BIT && col.getPrecision() <= 1) { @@ -135,27 +136,32 @@ } public void setColumns(DBColumn[] columns) { + assert SwingUtilities.isEventDispatchThread() : "Not on EDT"; this.data.clear(); this.columns = columns; fireTableStructureChanged(); } public DBColumn[] getColumns() { + assert SwingUtilities.isEventDispatchThread() : "Not on EDT"; return Arrays.copyOf(columns, columns.length); } public void setEditable(boolean editable) { + assert SwingUtilities.isEventDispatchThread() : "Not on EDT"; boolean old = this.editable; this.editable = editable; pcs.firePropertyChange("editable", old, editable); } public boolean isEditable() { + assert SwingUtilities.isEventDispatchThread() : "Not on EDT"; return editable; } @Override public boolean isCellEditable(int row, int column) { + assert SwingUtilities.isEventDispatchThread() : "Not on EDT"; if (!editable) { return false; } @@ -165,6 +171,7 @@ @Override public void setValueAt(Object value, int row, int col) { + assert SwingUtilities.isEventDispatchThread() : "Not on EDT"; Object oldVal = getValueAt(row, col); if (noUpdateRequired(oldVal, value)) { return; @@ -185,6 +192,7 @@ @Override @SuppressWarnings("unchecked") public Class getColumnClass(int columnIndex) { + assert SwingUtilities.isEventDispatchThread() : "Not on EDT"; if (columns[columnIndex] == null) { return super.getColumnClass(columnIndex); } else { @@ -193,20 +201,24 @@ } public DBColumn getColumn(int columnIndex) { + assert SwingUtilities.isEventDispatchThread() : "Not on EDT"; return columns[columnIndex]; } @Override public int getColumnCount() { + assert SwingUtilities.isEventDispatchThread() : "Not on EDT"; return columns.length; } public String getColumnTooltip(int columnIndex) { + assert SwingUtilities.isEventDispatchThread() : "Not on EDT"; return DataViewUtils.getColumnToolTip(columns[columnIndex]); } @Override public String getColumnName(int columnIndex) { + assert SwingUtilities.isEventDispatchThread() : "Not on EDT"; String displayName = columns[columnIndex].getDisplayName(); return displayName != null ? displayName : "COL_" + columnIndex; } @@ -222,21 +234,25 @@ @Override public int getRowCount() { + assert SwingUtilities.isEventDispatchThread() : "Not on EDT"; return data.size(); } @Override public Object getValueAt(int rowIndex, int columnIndex) { + assert SwingUtilities.isEventDispatchThread() : "Not on EDT"; Object[] dataRow = data.get(rowIndex); return dataRow[columnIndex]; } public Object[] getRowData(int rowIndex) { + assert SwingUtilities.isEventDispatchThread() : "Not on EDT"; Object[] dataRow = data.get(rowIndex); return Arrays.copyOf(dataRow, dataRow.length); } public void setData(List data) { + assert SwingUtilities.isEventDispatchThread() : "Not on EDT"; this.data.clear(); for (Object[] dataRow : data) { this.data.add(Arrays.copyOf(dataRow, dataRow.length)); @@ -245,6 +261,7 @@ } public List getData() { + assert SwingUtilities.isEventDispatchThread() : "Not on EDT"; ArrayList result = new ArrayList(); for (Object[] dataRow : this.data) { result.add(Arrays.copyOf(dataRow, dataRow.length)); @@ -253,17 +270,20 @@ } public void addRow(Object[] dataRow) { + assert SwingUtilities.isEventDispatchThread() : "Not on EDT"; int addedRowIndex = this.data.size(); this.data.add(Arrays.copyOf(dataRow, dataRow.length)); fireTableRowsInserted(addedRowIndex, addedRowIndex); } public void removeRow(int row) { + assert SwingUtilities.isEventDispatchThread() : "Not on EDT"; this.data.remove(row); fireTableRowsDeleted(row, row); } public void clear() { + assert SwingUtilities.isEventDispatchThread() : "Not on EDT"; this.data.clear(); fireTableDataChanged(); } diff --git a/db.dataview/test/unit/src/org/netbeans/modules/db/dataview/output/DataViewTest.java b/db.dataview/test/unit/src/org/netbeans/modules/db/dataview/output/DataViewTest.java --- a/db.dataview/test/unit/src/org/netbeans/modules/db/dataview/output/DataViewTest.java +++ b/db.dataview/test/unit/src/org/netbeans/modules/db/dataview/output/DataViewTest.java @@ -42,6 +42,7 @@ package org.netbeans.modules.db.dataview.output; +import java.lang.reflect.InvocationTargetException; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; @@ -56,6 +57,7 @@ import org.netbeans.modules.db.dataview.util.DbUtil; import org.netbeans.modules.db.dataview.util.TestCaseContext; import org.openide.util.Exceptions; +import org.openide.util.Mutex; /** * @@ -78,7 +80,7 @@ @Override public boolean runInEQ () { - return true; + return false; } @Override @@ -171,9 +173,14 @@ String sqlStr =context.getSqlSelect(); int pageSize = 4; DataView instance = DataView.create(dbconn, sqlStr, pageSize); - DataViewPageContext result = instance.getPageContext(0); + final DataViewPageContext result = instance.getPageContext(0); assertEquals(1, result.getTotalRows()); - assertTrue(result.hasDataRows()); + assertTrue(Mutex.EVENT.writeAccess(new Mutex.Action() { + @Override + public Boolean run() { + return result.hasRows(); + } + })); } public void testGetDatabaseConnection() { diff --git a/db.dataview/test/unit/src/org/netbeans/modules/db/dataview/output/InsertRecordTableUITest.java b/db.dataview/test/unit/src/org/netbeans/modules/db/dataview/output/InsertRecordTableUITest.java --- a/db.dataview/test/unit/src/org/netbeans/modules/db/dataview/output/InsertRecordTableUITest.java +++ b/db.dataview/test/unit/src/org/netbeans/modules/db/dataview/output/InsertRecordTableUITest.java @@ -53,6 +53,7 @@ import org.netbeans.modules.db.dataview.util.DBTestUtil; import org.netbeans.modules.db.dataview.util.DbUtil; import org.netbeans.modules.db.dataview.util.TestCaseContext; +import org.openide.util.Mutex; /** * Test for InsertRecordTableUI @@ -69,7 +70,7 @@ @Override public boolean runInEQ() { - return true; + return false; } @Override @@ -94,26 +95,33 @@ //--------------------- Test Case --------------------- public void testCreate() { String sqlString = context.getSqlSelect(); - DataView dv = DataView.create(dbconn, sqlString, 5); - dv.createComponents(); + final DataView dv = DataView.create(dbconn, sqlString, 5); - DataViewPageContext pageContext = dv.getPageContext(0); - DBTable table = pageContext.getTableMetaData().getTable(0); + Mutex.EVENT.writeAccess(new Mutex.Action() { + @Override + public Void run() { + dv.createComponents(); - InsertRecordDialog ird = new InsertRecordDialog(dv, pageContext, table); + DataViewPageContext pageContext = dv.getPageContext(0); + DBTable table = pageContext.getTableMetaData().getTable(0); - ResultSetTableModel model = ird.insertRecordTableUI.getModel(); - ird.insertRecordTableUI.appendEmptyRow(); - ird.insertRecordTableUI.appendEmptyRow(); + InsertRecordDialog ird = new InsertRecordDialog(dv, pageContext, table); - // Column 5 is the date column => Insert a "real" Date - // => creates conflict with String inserted by "createNewRow" - ird.insertRecordTableUI.setValueAt( - new Date(new java.util.Date().getTime()), 1, 5); - try { - ird.insertRecordTableUI.setSortOrder(5, SortOrder.ASCENDING); - } catch (ClassCastException ex) { - assert false : "Bug 219011 - should not be reached!"; - } + ResultSetTableModel model = ird.insertRecordTableUI.getModel(); + ird.insertRecordTableUI.appendEmptyRow(); + ird.insertRecordTableUI.appendEmptyRow(); + + // Column 5 is the date column => Insert a "real" Date + // => creates conflict with String inserted by "createNewRow" + ird.insertRecordTableUI.setValueAt( + new Date(new java.util.Date().getTime()), 1, 5); + try { + ird.insertRecordTableUI.setSortOrder(5, SortOrder.ASCENDING); + } catch (ClassCastException ex) { + assert false : "Bug 219011 - should not be reached!"; + } + return null; + } + }); } } diff --git a/db.dataview/test/unit/src/org/netbeans/modules/db/dataview/output/SQLExecutionHelperTest.java b/db.dataview/test/unit/src/org/netbeans/modules/db/dataview/output/SQLExecutionHelperTest.java --- a/db.dataview/test/unit/src/org/netbeans/modules/db/dataview/output/SQLExecutionHelperTest.java +++ b/db.dataview/test/unit/src/org/netbeans/modules/db/dataview/output/SQLExecutionHelperTest.java @@ -69,7 +69,7 @@ org.netbeans.junit.NbTestSuite suite = new org.netbeans.junit.NbTestSuite(SQLExecutionHelperTest.class); return suite; } - + @Override protected void setUp() throws Exception { super.setUp(); @@ -89,6 +89,11 @@ dbconn = null; } + @Override + protected boolean runInEQ() { + return false; + } + //------------Test Case ---------------- public void testInitialDataLoad() throws Exception { diff --git a/db.dataview/test/unit/src/org/netbeans/modules/db/dataview/output/SQLStatementGeneratorTest.java b/db.dataview/test/unit/src/org/netbeans/modules/db/dataview/output/SQLStatementGeneratorTest.java --- a/db.dataview/test/unit/src/org/netbeans/modules/db/dataview/output/SQLStatementGeneratorTest.java +++ b/db.dataview/test/unit/src/org/netbeans/modules/db/dataview/output/SQLStatementGeneratorTest.java @@ -68,7 +68,7 @@ * @author jawed */ public class SQLStatementGeneratorTest extends NbTestCase { - + TestCaseContext context; DatabaseConnection dbconn; Connection conn; @@ -98,6 +98,11 @@ DbUtil.dropTable(); } + @Override + protected boolean runInEQ() { + return true; + } + public void testGenerateWhereConditionWithPK() throws SQLException { DBMetaDataFactory dbMeta = new DBMetaDataFactory(conn); Statement s = conn.createStatement();