Wow, I did not expect to receive a perfect score on my SCJD assignment! While I was working on my solution I know that I looked at the results of others here to see what they did right, what improvements could have been made, etc. so it is now my turn to give back to the community here. I spent about seven days designing and developing the application and then three days reviewing it, adding to my choices.txt file, writing the manual, and making sure that I had all my files in the correct location. Be sure to read the requirements carefully!
The resources I used were this forum (most helpful) and I remember reading through the CD included with the SCJP book by Sierra and Bates. It took six weeks to get results.
Design I chose a three-tier design with a database layer, a business logic layer, and a GUI layer. The database layer had an interface to interact with the raw flatfile format and abstract it in terms of records. The class that implemented that interface made it specific for the URLyBird record format I was given. Higher up in the database layer, I had classes that implemented my DBMain interface (provided by Sun) and a RemoteDBMain interface (defined by me - it was basically a copy of DBMain but its methods threw RemoteExceptions). There was also a lock management class here that maintained the integrity of the database with respect to concurrency concerns. 1300 lines.
The business logic layer had a ReservationManager interface that exposed the methods that I would use in the GUI. The implementing classes where LocalReservationManager and RemoteReservationManager, which used a DBMain and RemoteDBMain as data accessors, respectively. The notion of records was also abstracted into Reservations. 950 lines.
At the top, the GUI layer had an abstract frame that displayed most of the information. It had two subclasses - one for local mode and one for remote mode. These would create the appropriate ReservationManager type and also do a little bit of customization (e.g. the remote mode frame would display the server host and port). 1400 lines (Swing sucks).
More about the GUI It seems that people have typically received scores of 32/40 on the GUI so I'll elaborate on this point. My GUI was very simple. I had a JMenuBar that had only an Exit option, my JTable was very simple and did not allow for reordering of columns (however, since it was very easy to enable row-sorting, I turned that on). In fact my code for the JTable was super simple - every time I got new data from the database, I would create a completely new table model, populate it with the new data, and swap the JTable's models, leaving the old one to be GC'd.
I really didn't have anything fancy. The nicest features I had were that I loaded the native LAF and instead of clicking Search to execute a query, you could press Enter inside of my search fields. No progress bars, connection states, etc. I did remember to save the server IP, server port, and database file location within the suncertify.properties file. (Some of these properties wouldn't be changed, depending on the context.) The Properties class was great for this.
In a nutshell, be sure to handle all of the error cases, and try to have just a few features that are easy to use.
Locking and thread-safety I thought that this part was easy but I had done some OS kernel work a few months before working on my SCJD project, which probably helped. In short, there are two levels where concurrency can bite you. The first is at the data storage level. If two concurrent requests to write to the database end up writing to the same location you're going to be in trouble. (On a side note, I did reuse record numbers of deleted records. Think of record slots like slots in a CPU cache, page table, database buffer, etc.) A higher level problem exists with the reservation management. This is why the DBMain interface provides locking and unlocking methods. Again, this is similar to recurring themes in computer science, like pinning.
My user's manual was a simple HTML document which let me link to other parts within the document from a table of contents. Some CSS made it look nice.
I JavaDoc'd every method and class, even if they were private. My comments were solid, for lack of a better word. There weren't too many one-sentence comments, and I also made sure to fill in all the @param, @return, and @throws tags. This is probably why my line count is high.
In my JavaDoc I included a UML class diagram (basically a bunch of boxes representing my classes and their relationships). I spent about an hour with NetBeans reverse-engineering my final source into a UML diagram and then fiddling with it to hide all of the class methods and clean things up into a decent-sized image.
I was thorough during my written exam. I feel that writing concisely and with clear English (I took my exam in the US) would only make it easier for the reader to understand my points. This applies to the JavaDoc comments, choices.txt, and user's manual as well.
wow, perfect , Congratulations this will help us a lot.
Joined: Jun 18, 2007
K. Tsang wrote:congrats on your perfect score.
I would like to ask how you implemented updating network clients' table view when one client books a record?
I assume you're asking about a scenario in which clients A and B start the GUI, and then client A books some reservation. Simply put, I didn't update client B's view. What I did do was display an error message if B then tried to book the same record. From what I remember, the program flow was like this:
A books the record - the database is atomically updated.
B tries to book the record.
The database sees that the record is booked, and an exception is thrown.
The exception propagates up to the client GUI.
The GUI displays the error message to the user, and then refreshes the JTable (this step was implemented naively - if the user had performed some search, the refresh-operation would ignore that and just retrieve and display all of records.)
My code only threw an InterruptedException in four places. Three were in the main method where I launch the GUI so I just display an error message in a JOptionPane and exit the application.
The other InterruptedException is when I wait() for a database record to be unlocked. In this case, I just log the message (I wrote a small error-logging utility that wraps the Java API's logger - the output of the logger is never printed anywhere but presumably it could be used for debugging.) and that's that.
The reason why it doesn't matter is because whenever you have a call to wait(), it should most likely be wrapped within a while-loop. Read up on Mesa vs. Hoare monitor locks if you're not sure why (Java uses Mesa-style locks). So, even if the exception is thrown and the error is logged, the while-loop will continue to make the thread wait until the desired condition (i.e. the condition for the while-loop to terminate) is satisfied.