I am using 2 Tables (JTable) with their DefaultTableModels.
The first table is already populated.
The second table is populated for each row of the first table (using an SQL Query).
My purpose is to export every line of the first table with it's respective lines of the second in an Excel File.
I am doing it with a for (for each line of 1st table), in which I write a line of the 1st table in the Excel File, then I populate the 2nd table (for this line of 1st Table), I get every line from the Table (from it's Model actually) and put it in the Excel File under the current line of 1st table.
This means that if I have n lines in first table I will clear and populate again the second table n times.
All this code is called in a seperate thread.
THE PROBLEM IS:
Everything works perfectly fine ecxept that I am getting some exceptions.
The strange thing is that I'm not getting anything false in my result.
The Excel file is perfect.
Some of the lines of the exceptions are:
Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 0 >= 0
at java.util.Vector.elementAt(Vector.java:427)
at javax.swing.table.DefaultTableModel.getValueAt(DefaultTableModel.java:632)
at javax.swing.JComponent.paint(JComponent.java:1017)
at javax.swing.RepaintManager.paint(RepaintManager.java:1220)
at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:803)
I am assuming that the problem lies in the fact that the second table needs some more time to be populated before I try to get any data from it. That's why I see RepaintManager and paintDirtyRegions in my exceptions.
Another thing I did is that I ran my program in debug mode and I put a breakpoint after each population of the 2nd table. Then I pressed F5 to continue for each population of 2nd table and no exception appeared. The program came to it's end without any exceptions.
This is another important fact that tells me that maybe in this case I gave the table enough time to be populated.
Of course you will ask me:
If your program works fine, why do you care about the exceptions?
I care for avoiding any future problems and I care to have a better understanding of Java and Java GUI and threads.
Why do you depend on a GUI component (and it's model) to get your information and why don't you recreate the resultset that populates your tables using an SQL Query and get your info from the resultset?
That would be the best and the right way. The fact is that I have the tables code ready and it was easier for me to just get the info from them. But the right way would be to get everything direct from database. Anyway what I did brought out my question, and answering it would help me understand more things about java. So I posted it.
The Swing API is not thread-safe except for a few method calls: repaint, revalidate, and invalidate. All other calls unless otherwise noted for a specific class must be made on the Event Dispatch Thread.
Transferring such call processing from a spawned background/worker thread can be done via SwingUtilities.invokeLater() or SwingUtilities.invokeAndWait().
There is also some specific discussion regarding both JTable and any TableModel that has been attached to an instance of it in the javax.swing package summary javadocs. Neither is thread-safe, so any calls accessing data from them must be performed on the Event Dispatch Thread.
This is the most probable cause of the exceptions you are encountering, and the different behavior that you experience when running in a debugger is a classic sign of a race condition. There is also no reliable way to hack around this via introducing your own locks, etc. Such practices invariably lead to trouble (such as deadlocks with the Event Dispatch Queue lock deep inside the Swing library) in the long run since Swing really, truly was not designed to be thread-safe.
The exception is happening because one of the table models is returning null for a getValueAt(int row,int column) call. The reason for this is probably an internal issue in swing or the data model due to the fact that you are using a secondary thread to access the data models. The swing api specifically states that you can not use a secondary thread in the way you described.
The following article provides further details on the single thread rule in swing.
http://java.sun.com/products/jfc/tsc/articles/threads/threads3.html
Related
So I'm porting my Swing Java database application to Java FX (still a beginner here, I recently just learned the basics of FXML and the MVC pattern, so please bear with me).
I intend to load the data from my existing database to the "students" ObservableList so I can show it on a TableView, but on my original Swing code, I have a search TextField, and when the user clicks on a button or presses Enter, the program:
Executes an SQLite command that searches for specific records, and retrieves the RecordSet.
Creates a DefaultTableModel based on the RecordSet contents
And throws that TableModel to the JTable.
However, Java FX is a completely different beast (or at least it seems so to me--don't get me wrong, I love Java FX :D ) so I'm not sure what to do.
So, my question is, do I have to load ALL the students in the database, then use some Java code to filter out students that don't fit the search criteria (and display all students when the search text is blank), or do I still use SQLite in filtering and retrieving records (which means I need to clear the list then add students every time a search is performed, and maybe it will also mess up with the bindings? Maybe there will be a speed penalty on this method also? Besides that, it will also reset the currently selected record because I clear the list--basically, bad UI design and will negatively impact the usability)
Depending on the right approach, there is also a follow-up question (sorry, I really can't find the answer to these even after Googling):
If I get ALL students from database and implement a search feature in Java, won't it use up more RAM than it should, because I am storing ALL the database data in RAM, instead of just the ones searched for? I mean, sure, even my lowly laptop has 4GB RAM, but the feeling of using more memory than I should makes me feel somewhat guilty LOL
If I choose to just update the contents of the ObservableList every time a new search has been performed, will it mess up with the bindings? Do I have to set up bindings again? How do I clear the contents of the ObservableList before adding the new contents?
I also have the idea of just setting the selected table item to the first record that matches the search string but I think it will be difficult to use, since only one record can be highlighted per search. Even if we highlight multiple rows, it'd be difficult to browse all selected items.
Please give me the proper way, not the "easy" way. This is my first time implementing a pattern (MVC or am I actually doing MVP, I don't know) and I realized how unmaintainable and ugly my previous programs are because I used my own style. This is a relatively big project that I need to support and improve for several years so having clean code and doing stuff the right way should help in maintaining the functionality of this program.
Thank you very much in advance for your help, and I hope I don't come off as a "dumb person who can't even Google" in asking these questions. Please bear with me here.
Basic design tradeoffs
You can, of course, do this either of the ways you describe. The basic tradeoffs are:
If you load everything from the database, and filter the table in Java, you use more memory (though not as much as you might think, as explained below)
If you filter from the database and reload every time the user changes the filter, there will be a bigger latency (delay) in displaying the data, as a new query will be executed on the database, with (usually) network communication between the database and the application being the biggest bottleneck (though there are others).
Database access and concurrency
In general, you should perform database queries on a background thread (see Using threads to make database requests); if you are frequently making database queries (i.e. filtering via the database), this gets complex and involves frequently disabling controls in the UI while a background task is running.
TableView design and memory management
The JavaFX TableView is a virtualized control. This means that the visual components (cells) are created only for visible elements (plus, perhaps, a small amount of caching). These cells are then reused as the user scrolls around, displaying different "items" as required. The visual components are typically quite memory-consumptive (they have hundreds of properties - colors, font properties, dimensions, layout properties, etc etc - most of which have CSS representations), so limiting the number created saves a lot of memory, and the memory consumption of the visible part of the table view is essentially constant, no matter how many items are in the table's backing list.
General memory consumption computations
The items observable list that forms the table's backing list contains only the data: it is not hard to ballpark-estimate the amount of memory consumed by a list of a given size. Strings use 2 bytes per character, plus a small fixed overhead, doubles use 8 bytes, ints use 4 bytes, etc. If you wrap the fields in JavaFX properties (which is recommended), there will be a few bytes overhead for each; each object has an overhead of ~16 bytes, and references themselves typically use up to 8 bytes. So a typical Student object that stores a few string fields will usually consume of the order of a few hundred bytes in memory. (Of course, if each has an image associated with it, for example, it could be a lot more.) Thus if you load, say 100,000 students from a database, you would use up of the order of 10-100MB of RAM, which is pretty manageable on most personal computer systems.
Rough general guidelines
So normally, for the kind of application you describe, I would recommend loading what's in your database and filtering it in memory. In my usual field of work (genomics), where we sometimes need 10s or 100s of millions of entities, this can't be done. (If your database contains, say, all registered students in public schools in the USA, you may run into similar issues.)
As a general rule of thumb, though, for a "normal" object (i.e. one that doesn't have large data objects such as images associated with it), your table size will be prohibitively large for the user to comfortably manage (even with filtering) before you seriously stretch the memory capacity of the user's machine.
Filtering a table in Java (all objects in memory)
Filtering in code is pretty straightforward. In brief, you load everything into an ObservableList, and wrap the ObservableList in a FilteredList. A FilteredList wraps a source list and a Predicate, which returns true is an item should pass the filter (be included) or false if it is excluded.
So the code snippets you would use might look like:
ObservableList<Student> allStudents = loadStudentsFromDatabase();
FilteredList<Student> filteredStudents = new FilteredList<>(allStudents);
studentTable.setItems(filteredStudents);
And then you can modify the predicate based on a text field with code like:
filterTextField.textProperty().addListener((obs, oldText, newText) -> {
if (newText.isEmpty()) {
// no filtering:
filteredStudents.setPredicate(student -> true);
} else {
filteredStudents.setPredicate(student ->
// whatever logic you need:
student.getFirstName().contains(newText) || student.getLastName().contains(newText));
}
});
This tutorial has a more thorough treatment of filtering (and sorting) tables.
Comments on implementing "filtering via queries"
If you don't want to load everything from the database, then you skip the filtered list entirely. Querying the database will almost certainly not work fast enough to filter (using a new database query) as the user types, so you would need an "Update" button (or action listener on the text field) which recomputed the new filtered data. You would probably need to do this in a background thread too. You would not need to set new cellValueFactorys (or cellFactorys) on the table's columns, or reload the columns; you would just call studentTable.setItems(newListOfStudents); when the database query finished.
There is a usability issue when you have a JTable with a huge number of rows in conjunction with the normal TableRowSorter. Sorting on any column will fetch all the values for that column. This is all done on the EDT, which freezes the application for potentially a very long time. It's doubly-bad because it also does the sorting on the EDT even though it doesn't have to.
So I'm wondering whether there is a right way to do this.
I already have a thread-safe TableModel which is safe to call on a background thread. Is there an elegant way to have it fetch the values on another thread instead of doing it on the EDT?
But really, eventually I would like to do the sort at the backend, so perhaps there is an elegant way to hook the table's row sorter up to changing the actual query being used to fetch the data? It's something that I thought was being worked on in some jdesktop project in the past, but I don't think I ever saw what came from that.
In both these situations, there is an associated usability issue of indicating that a sort has been specified but hasn't completed yet, which I'm not entirely sure the JTable look and feel will display, but who knows, maybe it will.
I have an Oracle DB with a lot of tables ... How can I write something which listens to the Oracle DB and if any changes are made to the DB, it calls another program which does some processing
It would be asnync
I just need to trigger a java program if there is any kind of DML happening .. I dont want details about which table or what rows or new/old values ...
If there is a DML on any table in a DB call a java program thats it
http://docs.oracle.com/cd/B14117_01/win.101/b10118/o4o00118.htm
OracleDB has some events. Just try to use them; For example, when the db is updated - And to call another java program:
Runtime.getRuntime().exec(/Here the argument/);
I fear you're setting yourself up for failure here. I suggest a related, but slightly different course of action.
Rather than trigging your processing on every data change, consider instead having your processing run every X minutes/hours/whatever using something like Cron or Quartz.
If you're worried about having it run when no changes have been made, you can add triggers to your tables to update a "last updated" table and you can abort if no changes have been made since the last run.
This avoids the biggest concern you would have with an "on-update-processor", namely what do you do if there's an update, which triggers a process, and while that process is running another update happens. Do you trigger another process? What if they conflict? I think you'll find it better to allow there to be a slight delay between the update and the synchronization process.
That's a pretty tall order for a question.
For starters, you are going to need a way to detect that a DML operation (INSERT, UPDATE, DELETE) has occurred.
For auditing on individual tables, we can use TRIGGERS.
CREATE TRIGGER [BEFORE|AFTER] [INSERT][UPDATE][DELETE] ... [FOR EACH ROW]
The normative action is to record information about the information (whatever is needed later) in an "audit log" table. You have to make a decision whether the operations you need to perform are synchronous (should happen before the DML completes) or whether those operations can be asynchronous (can happen anytime after the DML completes).
Normally, synchronous processing is done in PL/SQL, but Oracle does provide a mechanism for calling external procedures (EXTPROC), though you wouldn't want to do that from a TRIGGER.
Oracle also provides "fine grained auditing". The information gathered by FGA is not at a "row by row" level, like we can get with a FOR EACH ROW trigger.
So, it really depends on what you are trying to achieve.
The next step is figuring out how you are going to get this information to your external process. Is that process going to periodically poll table (or set of tables), are you going to use AQ Advanced Queueing, or some other queue mechanism.
My program uses Swing table to display data stored in MySQL, while the data is dynamic. I use a thread to repeatedly fetch data from database and refresh the table. I wonder if there are other much wiser methods to do this. Thanks for any suggestion.
as you said, using a single thread to query database and update the UI
is appropriate, am I right?
not, couldn't be true, or yes, everything depends of latency and accessibily of data source(s)
be sure that you'll update only visible Rectangle, cell in the JViewport, on periodical bases, other changes only to notify separatelly (JLabel, ToolTip, SystemTray e.g. ....)
example about JTable and Performance, called as ChristmastTree (lost somwhere after Oracle cleanup Suns tutorial and codesources in last year), bases on standard Workers Thread (before SwingWorker...)
I wonder if there are other much wiser methods to do this.
as I already commnented there are Database notifiers thata firing event when add/ delete/ change is triggered in DB Engine, never tried, can't suggest if use that or not
This a variant for the classic "wait rpc call problem" in GWT.
I have done a complete CRUD screen in GWT, calling RPC to atack an Oracle database. It has one panel for the search criteria and the results table, and other for the detail fields. I swap the visiblity of both as i need to.
The results table is a CellTable and i call the "setVisibleRangeAndClearData" method to get the table populated, which that takes care for paging, column sort and so on (for example when i come back from an update RPC call i keep the range i came from).
I use to make the "synchro" by putting the "after code" in the "onSuccess" block of the RPC call (i.e. swaping the panels), but when calling "setVisibleRangeAndClearData", the cellTable by itself launches another RPC call to get new data which is out of my control. So, what happens is that i swap the panels (wich is immediate) and after that, the user sees the table data update, which is ugly.
So the question is: How can i control that? How can i wait or get called when the "setVisibleRangeAndClearData" is finisehd?
Thanks in advance,
David
Showing the table right away and then populating it with data is not ugly - in fact, it's the right solution from a UI perspective. Users expect immediate result of their actions, and showing them a loading indicator immediately after they press the button is the right approach.
CellTable has two methods you may find useful:
setLoadingIndicator() - your table should display it until the data arrives;
onLoadingStatusChange().