Java ResultSetTableModel resultset is closed - java

Reworded this question as it wasn't very clear. My issue is that whenever the generateReport method trys to use model.getColumnCount() its returning zero and giving a ResultSet is Closed error.
However if I remove that finally block, everything works as expected. How do I do this correctly with closing off the connection?
Am I right in thinking that the model only lives within the createTable method as I've used
model = new ResultSetTableModel(rs);
Even though I declared the model as a class variable?
Method that creates the JTable
private void createTable() {
databaseName = (txtQueryDatabase.getText());
String sql = txtQueryString.getText();
openDatabase();
try {
ResultSet rs = stmt.executeQuery(sql);
model = new ResultSetTableModel(rs);
tblEmployee.setModel(model);
txtQueryCount.setText(Integer.toString(model.getRowCount()));
} catch (SQLException e) {
errorMessage(e);
} catch (Exception e) {
errorMessage(e);
} finally {
closeDatabase();
}
The method that writes the file
private void generateReport(File file) throws IOException {
file.createNewFile();
BufferedWriter bfw = new BufferedWriter(new FileWriter(file));
for (int i = 0; i < model.getColumnCount(); i++) {
bfw.write(model.getColumnName(i));
bfw.write(" | ");
}
for (int i = 0; i < model.getRowCount(); i++) {
bfw.newLine();
for (int j = 0; j < model.getColumnCount(); j++) {
bfw.write(model.getValueAt(i, j).toString());
bfw.write(" | ");
}
}
bfw.close();
}
ResultSetTableModel class
public ResultSetTableModel(ResultSet aResultSet) {
try {
rs = aResultSet;
rsmd = rs.getMetaData();
data = new ArrayList<Object>();
while (rs.next()) {
Object[] row = new Object[rsmd.getColumnCount()];
for (int i = 0; i < row.length; i++) {
row[i] = rs.getObject(i + 1);
}
data.add(row);
}
} catch (SQLException e) {
message.errorMessage(e);
}
}
#Override
public Object getValueAt(int row, int col) {
if (row < data.size()) {
return ((Object[]) data.get(row))[col];
} else {
return null;
}
}
#Override
public int getRowCount() {
return data.size();
}
#Override
public String getColumnName(int count) {
try {
return rsmd.getColumnName(++count);
} catch (SQLException e) {
message.errorMessage(e);
return "";
}
}
#Override
public int getColumnCount() {
try {
return rsmd.getColumnCount();
} catch (SQLException e) {
message.errorMessage(e);
return 0;
}
}
}

Related

Updating dynamically JTable(s)

I'm working on a Java database application, where the user has one side to insert data and another to show in a JTable (in a JScrollPane) the content of the linked HSQLDB database. Everthing works so far so good, but I searched for a very long time without finding how to update my JTable dynamically when a change is made to the database (add, update or delete) for each instance of my program because several persons can work on it simultaneously.
It actually works by replacing my table model for local update, but for other instances, i have set a Timer which is not very clean.
Could you help me resolving this please ?
Here is my code (I have an Interface.java for "visible" part and a SQL.java to manage my db) :
My timer
JTable table = new JTable(sql.showTable("SELECT * FROM suivi_flotte"));
Timer timer = new Timer(900000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
sql.updateTable();
nbLinesOrRefresh.setText("Actualisation...");
Timer timer2 = new Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
nbLinesOrRefresh.setText("");
}
});
timer2.start();
timer2.setRepeats(false);
}
});
timer.setDelay(900000);
timer.start();
formatTable(table);
My updateTable() method (called each time there is an insert, update or delete)
protected void updateTable() {
Interface.f.table.setModel(showTable("SELECT * FROM suivi_flotte"));
Interface.f.formatTable(Interface.f.table); // a method to custom JTable appearance
}
My showTable(String query) method
protected DefaultTableModel showTable(String query) {
String[] columnsTitles = {"N°", "Propriétaire", "Service", "Grade", "Nom", "Prénom", "Mail", "N° SIM", "N° Tél", "Modèle", "N° Série", "IMEI", "N° Crypto", "Date début", "Date fin", "DS", "Commentaire", "Date de création"};
ArrayList<String> columnNames = new ArrayList<>();
ArrayList<Object> data = new ArrayList<>();
connectDB(); // only to connect to db
try (ResultSet rs = stmt.executeQuery(query)) {
ResultSetMetaData md = rs.getMetaData();
int columns = md.getColumnCount();
for (int i = 1; i <= columns; i++) {
columnNames.add(columnsTitles[i - 1]);
}
while (rs.next()) {
ArrayList<Object> row = new ArrayList<>(columns);
for (int i = 1; i <= columns; i++) {
row.add(rs.getObject(i));
}
data.add(row);
}
shutdownDB(); // to fully disconnect from db
} catch (SQLException e) {
System.out.println(e.getMessage());
}
Vector<Vector<?>> dataVector = new Vector<>();
Vector<String> columnNamesVector = new Vector<>();
for (int i = 0; i < data.size(); i++) {
ArrayList<?> subArray = (ArrayList<?>) data.get(i);
Vector<Object> subVector = new Vector<>();
for (int j = 0; j < subArray.size(); j++) {
subVector.add(subArray.get(j));
}
dataVector.add(subVector);
}
for (int i = 0; i < columnNames.size(); i++) {
columnNamesVector.add(columnNames.get(i));
}
DefaultTableModel tModel = new DefaultTableModel(dataVector, columnNamesVector) {
private static final long serialVersionUID = 1L;
public Class<?> getColumnClass(int column) {
for (int row = 0; row < getRowCount(); row++) {
Object o = getValueAt(row, column);
if (o != null) {
return o.getClass();
}
}
return Object.class;
}
#Override
public boolean isCellEditable(int row, int column) {
return false;
}
};
// tModel.fireTableDataChanged(); // <-- does not work
return tModel;
}
Thank you for your help.
UPDATE 1 :
All my connection/disconnection code :
private void connectDB() {
JFrame op = new JFrame();
op.setAlwaysOnTop(true);
try {
Class.forName("org.hsqldb.jdbcDriver");
co = DriverManager.getConnection("jdbc:hsqldb:file:db;shutdown=true");
stmt = co.createStatement();
} catch (SQLException | ClassNotFoundException e) {
JOptionPane.showMessageDialog(op, "Erreur de connexion à la base de données :\n" + e.getMessage(), Interface.windowTitle, JOptionPane.ERROR_MESSAGE);
}
}
private void openDB() throws IOException {
try {
BufferedReader br = new BufferedReader(new FileReader("db.sql"));
String line;
StringBuffer sb = new StringBuffer();
while ((line = br.readLine()) != null) {
sb.append(line + "\n");
}
br.close();
stmt.executeUpdate(sb.toString());
} catch (SQLException e) {}
}
private void shutdownDB() throws SQLException {
stmt.close();
co.close();
}
UPDATE 2 :
I changed everything in SQL.java to non-static. Each SQL.[...] has been changed to sql.[...] with private SQL sql = new SQL(); on top of the class and public SQL() {} in the class. I also changed it in the above code.

Design Pattern - Which Design Pattern to use in this case

I've created a Dataset class used to store and manipulate a dataset. A different class, called Dataset Iris, extends Dataset because Dataset is Principal class where every different datasets (iris and so on) extends it because they have a their feature and a different methods to load it(I can load from a file .txt, .data or database and so on...).
My actually code is this and run, but my teacher tells to me that I should apply "Decorator" design pattern to solve it, but looking the Decorator UML I don't think it because I haven't the "Concrete component" (I can create . What do you think about it? Is a Decorator design pattern or other (like template methods)?
Dataset
public class Dataset
{
private int nFeature;
private int nRecord;
private ArrayList<Integer> featureUsed;
private String nomeDataset;
//public double Mat [][];
private ArrayList<ArrayList<Double>> Mat;
public double Distanza(int i, ArrayList<Double> centroide)
{
double Sum=0;
for(int j=0; j<nFeature; j++)
Sum+=Math.pow((centroide.get(j) - Mat.get(j).get(i)), 2);
return Math.sqrt(Sum);
}
public double getCell(int i, int j)
{
return Mat.get(j).get(i);
}
public void initMat()
{
Mat = new ArrayList<ArrayList<Double>>();
featureUsed = new ArrayList<Integer>();
for(int i=0; i< nFeature; i++)
{
Mat.add(new ArrayList<Double>());
featureUsed.add(i);
}
}
public void writeDataset()
{
for(int i=0; i< nRecord; i++)
{
for(int j=0; j < nFeature; j++)
{
System.out.print( Mat.get(j).get(i)+ " ");
}
System.out.println("\n");
}
}
public ArrayList<Double> getRecord(int i_r)
{
ArrayList<Double> record = new ArrayList<Double>();
for(int i=0; i<nFeature; i++)
record.add( Mat.get(i).get(i_r));
return record;
}
public Dataset(int nFeature, String Nome)
{
setnFeature(4);
setNomeDataset(Nome);
initMat();
}
public Dataset(ArrayList<ArrayList<Double>> MatInput, ArrayList<Integer> featureSelected, int nRecord)
{
Mat = new ArrayList<ArrayList<Double>>();
this.featureUsate = new ArrayList<Integer>(featureSelected);
this.nRecord = nRecord;
this.setnFeature(featureSelected.size());
for(int i=0; i<featureSelected.size(); i++)
setCol( MatInput.get( featureSelected.get(i)));
}
public Dataset() {
// TODO Auto-generated constructor stub
}
public void setCol( ArrayList<Double> colVal)
{
this.Mat.add(colVal);
}
public ArrayList<ArrayList<Double>> getMat()
{
return this.Mat;
}
public int getnFeature() {
return this.nFeature;
}
public int getnRecord() {
return this.nRecord;
}
public void setnFeature(int nFeature)
{
this.nFeature = nFeature;
return;
}
public void setnRecord(int nRecord) {
this.nRecord=nRecord;
return;
}
public void setTable(int Colonna, Double Valore)
{
Mat.get(Colonna).add(Valore);
}
public String getNomeDataset() {
return this.nomeDataset;
}
public void setNomeDataset(String nomeDataset) {
this.nomeDataset = new String(nomeDataset);
}
public double[][] toMatrix()
{
double[][] matrix = new double[this.getnRecord()][this.getnFeature()];
for(int i=0; i< nRecord; i++)
{
for(int j=0; j < nFeature; j++)
{
matrix[i][j] = Mat.get(j).get(i);
}
}
return matrix;
}
public ArrayList<Integer> getFeatureUsed()
{return this.featureUsed;}
}
DatasetIris
public class DatasetIris extends Dataset
{
private String[] nomiFeature = {"Petal Length",
"Petal Width",
"Sepal Length",
"Sepal Width"
};
public DatasetIris(String NomeFile) throws IOException
{
super(4,NomeFile);
super.setnRecord( CaricaDataset(NomeFile) );
}
// Other DatasetIris with their load (database or other type of files)?
protected int loadDataset(String pathFile) throws IOException
{
int iRecord = 0;
BufferedReader bufferLetto = null;
String line = "";
String cvsSplitBy = ",";
try {
bufferLetto = new BufferedReader(new FileReader(pathFile));
while ((line = bufferLetto.readLine()) != null)
{
if (line.length() > 0)
{
String[] cell = line.split(cvsSplitBy);
this.addRow(cell);
iRecord++;
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (bufferLetto != null) {
try {
bufferLetto.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return iRecord;
}
// New File.data to Mat
public void addRow(Object cell[])
{
for(int i=0; i<getnFeature(); i++)
super.setTable(i, Double.parseDouble(cell[i].toString()));
}
}

Invalid range error in Jtable when i use TableRowSorter

When I use TableRowSorter on my table I get an invalid range error, but when I delete jTableWells.setRowSorter(rowSorter), all it works successfully.
this.rowSorter = new TableRowSorter(jTableWells.getModel());
jTableWells.setRowSorter(rowSorter);
searchTextField.getDocument().addDocumentListener(new DocumentListener(){
#Override
public void insertUpdate(DocumentEvent e) {
String text = searchTextField.getText();
if (text.trim().length() == 0) {
rowSorter.setRowFilter(null);
} else {
rowSorter.setRowFilter(RowFilter.regexFilter("(?i)" + text));
}
}
#Override
public void removeUpdate(DocumentEvent e) {
String text = searchTextField.getText();
if (text.trim().length() == 0) {
rowSorter.setRowFilter(null);
} else {
rowSorter.setRowFilter(RowFilter.regexFilter("(?i)" + text));
}
}
});
When I try to update the table with displayTableWells() after adding a new row, I got the error of Invalid range:
private int addNewRecord() {
try{
...
st.executeUpdate(sql,Statement.RETURN_GENERATED_KEYS);
rs = st.getGeneratedKeys();
if ( rs.next() ) {
...
JOptionPane.showMessageDialog(this, "Saved ");
}
displayTableWells();// for update the table
}
}
...
}
private void displayTableWells() {
int i;
int count;
String a[];
String header[] = {"col1","col2","col3"};
count = header.length;
DefaultTableModel tm = new DefaultTableModel();
//First set the Table header
for(i = 0; i < count; i++)
{
tm.addColumn(header[i]);
}
a = new String[count];
try
{
st = conn.createStatement();
rs = st.executeQuery("SELECT col1,col2,col3 from table ORDER
BY createdon DESC");
while (rs.next())
{
for(i = 0; i < count; i++)
{
a[i] = rs.getString(i+1);
}
tm.addRow(a); //Adding the row in table model
jTableWells.setModel(tm);
}
}
catch (SQLException se) {
...
}
}
The error as bellow :
Exception in thread "AWT-EventQueue-0"
java.lang.IndexOutOfBoundsException: Invalid range
at javax.swing.DefaultRowSorter.rowsInserted(DefaultRowSorter.java:864)
at javax.swing.JTable.notifySorter(JTable.java:4270) at
javax.swing.JTable.sortedTableChanged(JTable.java:4118) at
javax.swing.JTable.tableChanged(JTable.java:4395) at
javax.swing.table.AbstractTableModel.fireTableChanged(AbstractTableModel.java:296)
at
javax.swing.table.AbstractTableModel.fireTableRowsInserted(AbstractTableModel.java:231)
at
javax.swing.table.DefaultTableModel.insertRow(DefaultTableModel.java:376)
at
javax.swing.table.DefaultTableModel.addRow(DefaultTableModel.java:350)
at
javax.swing.table.DefaultTableModel.addRow(DefaultTableModel.java:361)
at
org.geotools.geophysicsdbmaven.NewWell.displayTableWells(NewWell.java:474)

Why Jtable Does not refresh from other class

I have the following cod!
when i call the fruitsTable() from refreshButton() it refreshes the JTable! but when i call it from another class it does not refresh the Table! bellow is the simplified code
public ResultSet sqlCommand(String sqlStatement) throws SQLException
{
this.sqlStatement = sqlStatement;
ConnectingToMysql fruitsConnection = new ConnectingToMysql();
Connection myConnection = fruitsConnection.ConnectingToMysql();
Statement st = myConnection.createStatement();
ResultSet result = st.executeQuery(sqlStatement);
return result;
}
public Vector<String> getColumnData() throws SQLException
{
ResultSetMetaData metaData = sqlCommand(sqlStatement).getMetaData();
int columnCount = metaData.getColumnCount();
Vector<String> allColumn = new Vector<String>();
for(int i = 1; i <= columnCount; i++)
{
allColumn.add(metaData.getColumnName(i));
}
return allColumn;
}
public Vector<Vector<String>> getData() throws SQLException
{
ResultSet result = sqlCommand(sqlStatement);
ResultSetMetaData metaData = result.getMetaData();
int columnCount = metaData.getColumnCount();
Vector<Vector<String>> allRow = new Vector<Vector<String>>(columnCount);
while(result.next())
{
Vector<String> eachRow = new Vector<String>();
for(int i = 1; i <= columnCount; i++)
{
eachRow.add(result.getString(i));
}
allRow.add(eachRow);
}
return allRow;
}
public JScrollPane fruitsTable() throws SQLException
{
Vector<String> columnData = getColumnData();
Vector<Vector<String>> rowData = getData();
fruitsTableModel.setDataVector(rowData,columnData);
Font font = new Font("Courier", Font.PLAIN,16);
fruitsTable = new JTable();
fruitsTable.setModel(fruitsTableModel);
fruitsTable.setPreferredScrollableViewportSize(new Dimension(850,310));
fruitsTable.setRowHeight(30);
fruitsTable.setFont(font);
JScrollPane fruitsScrollPane = new JScrollPane(fruitsTable);
dataValue();
return fruitsScrollPane;
}
private JButton refreshButton() throws SQLException
{
JButton refreshButton = new JButton("Refresh Record");
refreshButton.setPreferredSize(new Dimension(100,40));
refreshButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
try
{
fruitsTable();
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
});
return refreshButton;
}
and this is the only code from the other class that calls the fruitsTable().
saveButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
try
{
String number = numberTextField.getText();
int ID = Integer.parseInt(number);
String fruit = fruitTextField.getText();
String color = colorTextField.getText();
String taste = tasteTextField.getText();
System.out.println("The value is: " + number + " " + fruit + " " + color + " " + taste);
String sqlText = "Insert into fruits(ID,Fruit,Color,Tast) values(?,?,?,?)";
ConnectingToMysql connectingToMysql = new ConnectingToMysql();
Connection makeConnection = connectingToMysql.ConnectingToMysql();
PreparedStatement pdt = makeConnection.prepareStatement(sqlText);
pdt.setInt(1,ID);
if(fruit.isEmpty())
{
pdt.setNull(2,java.sql.Types.VARCHAR);
}
else
{
pdt.setString(2,fruit);
}
if(color.isEmpty())
{
pdt.setNull(3,java.sql.Types.VARCHAR);
}
else
{
pdt.setString(3,color);
}
if(taste.isEmpty())
{
pdt.setNull(4,java.sql.Types.VARCHAR);
}
else
{
pdt.setString(4,taste);
}
pdt.executeUpdate();
GetFruits getFruits = new GetFruits();
getFruits.fruitsTable();
}
catch(SQLIntegrityConstraintViolationException e)
{
JOptionPane.showMessageDialog(null, "The 'Number' you entered already exist!", "Error", JOptionPane.ERROR_MESSAGE);
System.out.println(e);
}
GetFruits getFruits = new GetFruits();
getFruits.fruitsTable();
You're creating a new GetFruits object and refreshing it's table instead of updating the existing one. Try creating a class variable of GetFruits so you're using the same instance instead of creating a new one each time. Just guessing since I can't see all the code that contains the action listener.

JTable getValueAt method cast to Integer exception

I use this code to get my ID number of my JTable,
But "AWT-EventQueue-0" java.lang.ClassCastException occur,
public void actionPerformed(ActionEvent e) {
if (e.getSource() == dellButton) {
try {
int rowToDelete = 0;
int rowToModel = 0;
if (table.getSelectedRow() > -1) {
rowToDelete = table.getSelectedRow();
rowToModel = table.convertRowIndexToModel(rowToDelete);
tableModel.removeRow(rowToModel);
}
} catch (SQLException sqle) {
sqle.printStackTrace();
}
}
}
My TableModel.removeRow() method:
...
public void removeRow(int rowNumber) throws SQLException {
String removeQuery = "delete from mytable where id=?";
PreparedStatement pStatement = con.prepareStatement(removeQuery);
pStatement.setInt(1, rowNumber);
int rowsAffected = pStatement.executeUpdate();
}
...
int rowID = (int) table.getValueAt(selectedRowIndex, 0); is useless code line,
code line tableModel.removeRow(rowID, rowIndex); has wrong paramaters
test if any row is selected, otherwise selected row returns -1
everything could be only
#Override
public void actionPerformed(ActionEvent e) {
int rowToDelete = 0;
int rowToModel = 0;
if (table.getSelectedRow() > -1) {
rowToDelete = table.getSelectedRow();
rowToModel = table.convertRowIndexToModel(rowToDelete);
model.removeRow(rowToModel);
}
}
be sure that your SelectionMode will be, otherwise you would need to loop inside arrays of selected rows,
table.getSelectionModel().setSelectionMode(
ListSelectionModel.SINGLE_SELECTION);

Categories