0

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.

Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
Arainty
  • 91
  • 9
  • What kind of database, and how are the programs connected to the database? – Hovercraft Full Of Eels Dec 08 '19 at 15:43
  • Side note: you appear to be using static way too much suggesting poor program design. I recommend that you get most all of that code out of the static world and into the instance world. – Hovercraft Full Of Eels Dec 08 '19 at 15:44
  • I added my connection code. Yes, all my SQL.java code is static as i dont see why it shouldn't be (I do not imagined writing `SQL sql1 = new SQL();` then `sql1.updateTable();`), does it change something ? Should I do like that ? Why ? Thank you – Arainty Dec 08 '19 at 17:12
  • **Everything** seems to be static. Surely you already know why this is a bad thing. – Hovercraft Full Of Eels Dec 08 '19 at 17:20
  • Does it cause problems with multi instances? – Arainty Dec 08 '19 at 17:34
  • I already ran it in my work team and it didn't seem to cause problems, the only issue is this refresh problem. – Arainty Dec 08 '19 at 17:37
  • I was referring to general issues by not using Java's OOP model -- you geometrically increase the risk of bugs caused by increasing cyclomatic complexity as the size of the project increases. You will want to use OOP practices to help reduce this. It also makes debugging, enhancing, mocking much easier. As for your main problem, it looks like you're looking for some sort of listener added to the database so that users can be notified when it is updated, so that they can update their visual representation of it. This is why I asked which database you are using and how users are connected to it – Hovercraft Full Of Eels Dec 08 '19 at 17:41
  • Ok I understand, then what should I do ? Change everything to non-static ? Then should I use a constructor and with what inside ? – Arainty Dec 08 '19 at 17:46
  • And yes, the idea of listener is exactly what I'm looking for. P.S.: what does OOP mean ? – Arainty Dec 08 '19 at 17:47
  • Yes, make all non-static, and it's up to you how to structure this, but it's good practice to avoid static use except for the main method and "utility" type classes, such as Java's own Math library. As for listener, you may need to check your dtabase's documentation to see if they have this sort of thing. As for OOP, that means "object oriented programming" – Hovercraft Full Of Eels Dec 08 '19 at 17:49
  • Here are some [similar questions on this site](https://www.google.com/search?q=java+listen+for+database+changes+site:stackoverflow.com) about listening for database changes. It's not something that is generally within my own expertise, while Swing *is*. – Hovercraft Full Of Eels Dec 08 '19 at 17:50
  • OK I'll do that, trying to not break everything I made xD. Then you mean to try to use an HSQLDB's listener, but is it not possible and better to do it in Java directly ? – Arainty Dec 08 '19 at 17:57
  • @HovercraftFullOfEels any other idea ? Do you know people that can help me ? – Arainty Dec 15 '19 at 13:07
  • You've done various things when catching exceptions, the worst being `} catch (SQLException e) {}`. Change that to `} catch (SQLException e) { e.printStackTrace(); }` and add the stack trace call to every `catch`. General tip: For better help sooner, [edit] to add a [MCVE] or [Short, Self Contained, Correct Example](http://www.sscce.org/). Hard code data to replace the DB. – Andrew Thompson Jan 01 '20 at 00:57

0 Answers0