aspose file tools*
The moose likes Developer Certification (SCJD/OCMJD) and the fly likes URLyBird GUI MVC <-> Business Layer in a Thin Client and HashMap vs. ArrayList Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of EJB 3 in Action this week in the EJB and other Java EE Technologies forum!
JavaRanch » Java Forums » Certification » Developer Certification (SCJD/OCMJD)
Bookmark "URLyBird GUI MVC <-> Business Layer in a Thin Client and HashMap vs. ArrayList" Watch "URLyBird GUI MVC <-> Business Layer in a Thin Client and HashMap vs. ArrayList" New topic
Author

URLyBird GUI MVC <-> Business Layer in a Thin Client and HashMap vs. ArrayList

Carlos Morillo
Ranch Hand

Joined: Jun 06, 2009
Posts: 221

Hello Everybody,


Let's assume you are taking a thin client approach and let's say you have a Business Layer such as:




and that you also have a method getAllRecords() that returns a Map<Integer, Room>.

Reading Andrew Monkhouse's book in his class that extends AbstractTableModel
he uses an ArrayList<String[]> to hold all the DVD instances displayed in his JTable.

In the example of his book there is the advantage that the key for each DVD record the upc is the first element of a String[].

With the search() method above that returns a Map<Integer, Room> instead of an ArrayList<String[]>
and assuming Room is a Value Object wrapping a String[] representing the 7 fields of a Hotel Room Record
I see a challenge in that how do we know which record was selected when the key for each record in URLBird
is the Integer in the Map<Integer, Room>.

I am evaluating and considering what is the cleanest way to get the data from the Room records
into my HotelRoomTableModel that extends AbstractTableModel.

I am thinking perhaps to get the keySet() from the Map<Integer, Room> and create a
Set<Integer> sorter = new TreeSet<Integer>(Map<Integer, Room>.keySet());
and then create a
Integer[] index = sorter.toArray(new Integer[0]);

That way I have sorted all the keys in my Map<Integer, Room> in index and that way I can keep track
of which record has been selected in the JTable in my GUI so it can be booked, etc.

I am thinking to have this operation getting the keySet() from my Map<Integer, Room> to the Integer[] index
in my Controller class and do this everytime I need to refresh the HotelRoomTableModel.

In my HotelRoomTableModel I would also use an ArrayList<String[]> for the data to be displayed
of my Hotel Room records like in Monkhouse's Book example


Does this sound reasonable?
Any feedback and comments are appreciated.


Thanks,


Carlos.



SCSA, OCA, SCJP 5.0, SCJD http://www.linkedin.com/in/carlosamorillo
Roberto Perillo
Bartender

Joined: Dec 28, 2007
Posts: 2246

Howdy, Carlos!

Champion, I think I got your question, which is, how can you find out what is the number of the record that is selected in the JTable, right? Well, here's what I did: when you click on the Book Room button, the ActionListener that listens to this button has a reference to the window, and the window has a method called getSelectedRoom() that retrieves the Room object that is currently selected in the JTable. Here's the trick of the getSelectedRoom() method, in the main window:



So, I ask the table model to give me the record of a given row. One important thing to note is that I do not allow the columns to be sorted, so the Map<Integer, Room> object is always synchronized with the data being displayed, and also, the Map<Integer, Room> obviously does not have deleted records. This means that, the first row in the table certainly corresponds to the first entry in the Map. In the TableModel, in the getRoom() method, I find out what is the number of the record being displayed in that row (by iterating the Map with keySet().iterator()), and just get the Room object in the Map of the TableModel (with recordsMap.get(recordNumber)). This way, in the ActionListener, I call window.getSelectedRoom() and have the Room object currently selected in the JTable.


Cheers, Bob "John Lennon" Perillo
SCJP, SCWCD, SCJD, SCBCD - Daileon: A Tool for Enabling Domain Annotations
Roel De Nijs
Bartender

Joined: Jul 19, 2004
Posts: 4907
    
  10

Hi Carlos,

It seems to me that you are overcomplicating your solution. This is what I have done:
1. created my own custom AbstractTableModel: it keeps a List of Room-objects (containing recNo + all properties) and besides the implementation of the required methods I have added 2 methods: addRoom (simply adds room to the listOfRooms) and getRoom (simply returns the room at the given index).
2. of course my JTable uses an instance of my custom tableModel and with every search a new instance of this tableModel is created, filled with the appropriate rooms and passed to the JTable as its model (making the previous tableModel eligible for garbage collection).
3. when a user clicks on the Book-button I can simply get the selected room by calling
That's it!

And as a final remark: I didn't switch to String[] in the GUI, because simply it is a lot easier (and less error-prone) to work with a Room-object than with a String[]. The only place I use the String[] is in the Data class and in my business service. In the business service the String[] is converted to a Room-object. So why change back in your gui to a String[]? I think working with String[] has no added value at all. In fact when you use the Room-object (and you stored the smoking-attribute in a Boolean) you will get a specific rendition for the smoking-column (with a checked/unchecked checkbox) in the jtable (if you override getColumnClass method in your custom AbstractTableModel).

Just my 2 cents! Hopefully they will be of any help for you.
Kind regards,
Roel


SCJA, SCJP (1.4 | 5.0 | 6.0), SCJD
http://www.javaroe.be/
Carlos Morillo
Ranch Hand

Joined: Jun 06, 2009
Posts: 221

Hi Roberto and Roel,


Roberto,

Roberto Perillo writes:
I think I got your question, which is, how can you find out what is the number of the record that is selected in the JTable, right?

Yes, that is correct. Perhaps I described with too many details the context of the challenge.

I am assuming the Map<Integer, Room> will only have existing records and obviously regardless I am going to display all the Hotel Room records
or records result of Search using some criteria, there might perfectly exists gaps in the record numbers sequence to be displayed, I mean
you might have a situation where you have in your map record 0, 1, 2, 3, 4, 5, 6, 7, 8 and 9 (Size is 10, starting with a zero "0" index)
and records 3, 5, and 7 have been deleted, therefore in the JTable you will display records 0, 1, 2, 4, 6, 8, 9, so just 7 records will be displayed.

This means that, the first row in the table certainly corresponds to the first entry in the Map.

I am making the same assumption.

When you

I find out what is the number of the record being displayed in that row (by iterating the Map with keySet().iterator())


Do you also have the Record Number (Key of Map<Integer, Room>) being displayed in the JTable?



Roel,


Roel De Nijs writes:
1. created my own custom AbstractTableModel: it keeps a List of Room-objects (containing recNo + all properties)

Do you display the Record Number in the JTable?

If I understand you correctly it seems to me you have in your model an ArrayList that each element is the recNo (Integer of the Map<Integer, Room>) plus the String[] contained
in the Room, correct?
I guess in the Model methods getValueAt() and setValueAt() you add or substract 1 from the column if you don't display the Record Number?


Thanks,


Carlos.
Roel De Nijs
Bartender

Joined: Jul 19, 2004
Posts: 4907
    
  10

Hi Carlos,

Do you display the Record Number in the JTable?
No, because recNo has no meaning to a CSR. He won't care if it is record 225 or 5. It would maybe more meaningful if the recNo was some kind of room number (then I would probably show it in the table).

If I understand you correctly it seems to me you have in your model an ArrayList that each element is the recNo (Integer of the Map<Integer, Room>) plus the String[] contained in the Room, correct?
My Room-object contains all the fields from the database file (name, location, smoking, date available,...) and the appropriate record number. It does not contain a String[] at all. Each field is just represented in the Room-object as a String or Integer or Boolean. So I have 2 conversion methods to convert an object to array and an array to object. And like you already thought of yourself: the index in the List has nothing to do with the recNo of a room, so recNo 15 can easily have index 0 in the List (the index in the List is the row of that Room-object in the JTable).

I guess in the Model methods getValueAt() and setValueAt() you add or substract 1 from the column if you don't display the Record Number?
I didn't implement the setValueAt() method because my table is a read-only one, so no need to change values. And the getValueAt() method looks like this:So no adding or subtracting 1 from the column value at all

Kind regards,
Roel
Carlos Morillo
Ranch Hand

Joined: Jun 06, 2009
Posts: 221

Hi Roel,


Interesting ...
So far my Room object has been a Value Object containing a String[] with getters and setters methods
for every field represented by each record[i] where record[i] is an element of the String[] contained in the Room object
and a method that would return the entire String[], that I wonder know if it is an elegant solution?


Didn't think that having an actual Room object with Smoking as a boolean and the number of people as
an int could have a potential advantage. Looks like the JTable is pretty cool and smart and automatically does
an special rendering for primitive types in the case of a boolean like you were saying that it's displayed as a JCheckBox.

I never thought either of also keeping the Record Number itself inside the Room object.
I can see now the way you used it it does come handy and helpful to make your code pretty simple.

Thanks and Best Regards,


Carlos.
Roel De Nijs
Bartender

Joined: Jul 19, 2004
Posts: 4907
    
  10

Hi Carlos,

..., that I wonder know if it is an elegant solution?
I think your approach is better than just working with a plain String[], but I believe it is not the best (most elegant) solution possible.

I can see now the way you used it it does come handy and helpful to make your code pretty simple.
You will end up with less code (don't have getters nor setters in my room-object), your code will also be easy to understand and less error prone (because array indexes are only used in the 2 conversion methods).

I'm glad my remarks made you doubt and question your approach. I think the scjd assignment is all about making decisions, questioning them, thinking about alternative solutions and pick (+ implement) the best one (for your situation). This forum was also for me a great help when working on my assignment, had a lot of interesting and valuable discussions with other ranchers. And if you question every line of code you develop, you stick to the requirements and you keep everything as simple as possible, you'll end up close to the perfect score!

Kind regards,
Roel
Carlos Morillo
Ranch Hand

Joined: Jun 06, 2009
Posts: 221

Hi Roel,


I am able to get all the Hotel Rooms information loaded in the JTable's Model
and to display it in my GUI.


Using a Room object where smoking is a boolean, so far smoking is displayed as "true" or "false",
so I don't see any JCheckbox in that column.


I checked the Java 6 API and found the JTable protected method createDefaultRenderers() which
was the closest thing related to this.

Did you do anything special to get the smoking boolean member variable displayed as a JCheckbox?
Thanks,


Carlos.

Roel De Nijs
Bartender

Joined: Jul 19, 2004
Posts: 4907
    
  10

Hi Carlos,

I am able to get all the Hotel Rooms information loaded in the JTable's Model and to display it in my GUI.
Great job!
Did you do anything special to get the smoking boolean member variable displayed as a JCheckbox?
No, I didn't. Here is a hint

Kind regards,
Roel
Harry Henriques
Ranch Hand

Joined: Jun 17, 2009
Posts: 206
Hi Carlos,

I used an ArrayList<Record> to transfer data from my Business Layer to my GUI. The thing that makes this possible is the packaging of the recNo in the Record object. When you extract a String[] record from the database, you also know the recNo.

Best regards,
Harry
Carlos Morillo
Ranch Hand

Joined: Jun 06, 2009
Posts: 221

Hi Roel,


Trying to follow your hint but so far I still get the literals true and false in my JTable with this code:

I guess I am still missing something.
Do I need to call this from my Client Window code?


Thanks,
Carlos.
Roel De Nijs
Bartender

Joined: Jul 19, 2004
Posts: 4907
    
  10

Hi Carlos,

I don't know why you are returning JCheckBox class Check the javadoc of this method: you need to pass the object type of the cell values for that column, so that would be Boolean class.

You don't have to call this method yourself, it will be called for you

Kind regards,
Roel
Carlos Morillo
Ranch Hand

Joined: Jun 06, 2009
Posts: 221

Hi Roel,

I got it to work!

That's exactly what I was missing.
I was also able to use it for the size field which is an int and it nicely right justifies it.

Thanks once again for your help!



Best Regards,


Carlos.
Roel De Nijs
Bartender

Joined: Jul 19, 2004
Posts: 4907
    
  10

Carlos Morillo wrote:I got it to work!

I was also able to use it for the size field which is an int and it nicely right justifies it.
Excellent job!

Glad I could help.
Kind regards,
Roel
Carlos Morillo
Ranch Hand

Joined: Jun 06, 2009
Posts: 221

Hi Roel,


I've added some minor functionality to my GUI like disabling the Book Room button
when a Room has been already booked and I did find very useful the JTable tutorial examples.


Thanks,


Carlos.

Roel De Nijs
Bartender

Joined: Jul 19, 2004
Posts: 4907
    
  10

Carlos Morillo wrote:I've added some minor functionality to my GUI like disabling the Book Room button
when a Room has been already booked
I did that too
Georgiana Lungu
Ranch Hand

Joined: May 17, 2010
Posts: 34
Hi,

I was thinking whether it is a wrong approach to actually not pass the record number from the GUI, but use find method for retrieving it and then using it for update(atomic under logical lock, of course). The reason that made me consider it is that the original record might nolonger be at the record number at which it was when the GUI was loaded, might have been deleted, or modified, but meanwhile another record exactly as this one might have been added to the database at another record number. Since the GUI does not load any record number, I am wondering if I should really consider the original record number. Am I wrong?
And if I am wrong, I guess a validation that the record passed by the GUI for update still matches the record existing in the database at the original record number is still needed, right?
Georgiana Lungu
Ranch Hand

Joined: May 17, 2010
Posts: 34
Well, it doesn't make sense for using logical lock of the original record for find since it might as well retrieve another record number, but still, except this thing, my question still stands
Roel De Nijs
Bartender

Joined: Jul 19, 2004
Posts: 4907
    
  10

Hi Georgiana,

That's a topic which I did not consider. Records simply can't be deleted or updated, just booked (which is a minimal update). I even did not mention it in choices.txt if I remember correctly. These kind of questions should be tackled and handled when updating other fields and/or deleting+creating records (with record number reuse) is added to the application.

Kind regards,
Roel
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: URLyBird GUI MVC <-> Business Layer in a Thin Client and HashMap vs. ArrayList
 
Similar Threads
Work with Map in JTable?
Preserving previous selection in JTable
JTable
Business Layer, Factory and and Business Layer Search method
Gaps in JTable for deleted records?