Win a copy of Spark in Action this week in the Open Source Projects forum!

Jason Then

+ Follow
since Jun 26, 2010
Cows and Likes
Total received
In last 30 days
Total given
Total received
Received in last 30 days
Total given
Given in last 30 days
Forums and Threads
Scavenger Hunt
expand Ranch Hand Scavenger Hunt
expand Greenhorn Scavenger Hunt

Recent posts by Jason Then

Hey ranchers,
Just thought I'd let you all know I passed - yay!
I'd like to thank the great people who contribute to this board, probably wouldn't have made it without the valuable amount of information contained here
In particular I'd like to thank first and foremost both Roel De Nijs and Roberto Perillo for their dedication and commitment to answering questions on this board - it must get so repetitive hearing the same things all the time but it helps!
I'd also like to thank others on this board, like Michael Grossenbacher, Alecsandru Cocarla and Pedro Kowalski for their contributions.

So a few details about my project:
- I had URLybird (not sure which version).
- Started around 12/06/2010, submitted on 09/11/2010. It actually took me while to get into the swing of things, initially, but I eventually found motivation
- 58 Java Classes total
- Used a modified version of Roel's ant script to compile, run pre-build tests, assemble and run post-build tests
- Used TestNG for unit tests
- Used Windowlicker for Swing GUI tests.
- Used Mockito for mocking and stubbing of Objects.
- 3000+ Unit tests (most of them were parallel tests on the Data class).
- Used a three-tier architecture.
- Only produced plain-text documentation (no HTML) for user guide.
- Avoided statics and singletons where possible - relied on dependency injection for testable code - see here.

Data layer
- Used a record cache (so much easier than an IO based solution)
- Used Immutable Room objects to model the data.
- Statically defined the database schema
- Implemented logging in this layer.
- Did NOT synchronize all methods of the Data class - used Thread safe data structures in java.util.concurrent.
- Created my own Thread-safe LockableRecord class which stores lock cookie, lock state and acts as a monitor.

Service layer
- Used RMI
- Only defined two methods - bookRoom and findByCriteria
- Used Factory pattern to control how Services are constructed for the Presentation layer
- Did NOT use any singletons

- Kept it really simple and minimalistic
- Validated input where possible - e.g. no letters allowed for the port number field, or customer id dialog.
- Tooltips and Mnemonics everywhere.
- No icons.
- No contextual help.
- No GUI when running in Server mode.
- Encapsulated long running tasks within a modal, task running dialog - so as to not block the GUI.

And that's about all I can really think of. I'll post up my Data layer tests if people are interested - let me know by posting comments if you'd like to see them or not ;)

9 years ago
Roel, where does the data layer search specify case-insensitive?
I think it specifies String.startsWith() behaviour, but not case-insensitive.

For example, "Fred" matches "Fred" or "Freddy"...
But "fred" does not match "Fred" or "Freddy".

Yes, the GUI should match on exact matches only.

As for your other questions Pedro...

1. Yes, I popup an error in this case. The client will need to restart, or reconnect to the server via options.

2. Yes, I used tooltips where possible.

3. Yes, mine also deadlocks in this scenario. It's a programmer error, rather than an application fault, so I think this is ok. I talked about it in choices.txt.

4. I only put the details in the user manual.

5. I use System.nanoTime().

6. I don't throw DuplicateKeyException - the primary key is the record number and this is not held within the data.

7. Me neither.

Re: SimpleDateFormat, yeah I realised this - it can bite you if you store one of these in a final static field. So now I only store the format string, and create a new instance everytime

Ok so, this is like a continuation of my last post, as after a bit of User testing of my application, turns out I ran into a few minor issues.

I'm trying to decide what the best implementation might be with regards to what the program should do if the and database files do/don't exist.

At the moment, if isn't there, the application just uses default values. The client/standalone modes persist properties when the Options Dialog is successfully closed.

If the database file isn't there, the server won't start - it outputs an error message. Alternatively, an empty database could be started - but this seems like it could mislead the User...
In standalone mode, the application is started in an "Invalid state" - until the User specifies the correct file in the Options Dialog.
Obviously in client mode, the application doesn't use the db file, but if it can't connect to the server then the application is equally started in the invalid state.

What do your applications do in the event of a missing properties/db file??
Is this sensible behaviour for my application? I am just worried about the markers trying to start the server, failing to do so because there's no db file, and then failing my assignment
Ok, good thing I checked haha

Thanks Roberto!
Howdy Pedro,

1. If you're returning a List, then I presume that your Room object holds the record number?

2. What methods would you provide on your SearchCriteria class?
Another question, my assignment has Sun branding all over it - i.e. in the headers i've got

"Sun Certified Developer for Java 2 Platform, Standard Edition
Programming Assignment (CX-310-252A)"

This wouldn't be an issue would it?? I mean the package name is suncertify after all... and the properties file is
Hi Roberto and Michael,

When my server starts, there's no GUI. And yes I start the application in a two step process - I explicitly run rmiregistry.exe before starting my server (I specified in the documentation that you needed to do this).
I didn't know about the LocateRegistry.createRegistry lol... but that is probably a better solution and I'll change that now.

There's no requirement to have a GUI for the server is there? I think it might be better to not have one - just use Ctrl+C to stop.

Hi folks,

I have almost completed the assignment, and wanted to get an idea of some last minute checks that some of you who are certified performed before submitting your assignment.

This is what I have done so far to ensure its validity:
- The application is built using a modified version of Roel's cool ant script, which performs ~3400 pre-build tests using TestNG.
- I have written my own parallel tests (using the @Test annotation) for my Data class, and have also incorporated both Alecsandru Cocarla's and Roberto Perillo's modified test code into my suite.
- I am also performing automated User Interface testing using windowlicker.
- The ant script also performs some post-build tests using the class supplied by Roel.
- As far as manually testing the application goes, I can successfully start up an RMI registry (with runme.jar on the classpath). I can then start up a server instance to connect to it, and then start up multiple client instances to connect to the server locally.
- I haven't tested the application across multiple boxes yet, is this necessary?

My choices.txt document is about 550 lines (at 80 char column width), and userguide.txt is around 300 lines.

Is there anything that you did to ensure you didn't get automatically failed? What is the most common source of automatic failure? Is there anyone who has experienced such a thing on this forum and can provide some advice?
It's a little scary submitting something I've put quite a bit of effort into... and I'm worried that I might have missed one little thing...

Any tips for the essay exam too?? I guess it's kinda different now, because you have to complete the essay first before submitting your assignment..


Raf - yes it changes the behaviour, so it's all good

I have opted away from using a Map to store locks for records.
Instead, I use a List of the actual records and the records themselves are lockable.

I also cache deleted record numbers in a Queue for O(1) creation which reuses deleted records.
Raf - yes I am using a ReadWriteLock per Record.

But given the results of this discussion I might change the locking mechanism to wait on a dedicated object instead - so that I don't get that pesky IllegalMonitorStateException when another Thread tries to unlock it.

Locking a single record doesn't lock the whole database - what would be the point in that? Threads are synchronized on individual records, rather than on the Data object, so don't worry. I will figure something out

I agree though, it is unfortunate that this certification has been undervalued by Oracle. And it really sucks that they don't give you a numeric score - just a pass/fail grade
Hi yall,

Just wondering, does the Thread which locks a particular record need to be the same Thread which then unlocks that record?

After running Alecsandru Cocarla's Data Test, I found that my Data class throws an IllegalMonitorStateException because of this reason - i.e. a different Thread which knows the lock cookie value is unlocking the record.
My class passes Roberto Perillo's Data Test, however

So am I incorrect in this assumption that the same Thread which locks a record, needs to be the same Thread which unlocks that record?
It seems to me that there would be significant work in implementing a locking mechanism which allows any other Thread to unlock that record.

(Edit: Ok so I've now realized that there isn't *significant* work in implementing this locking mechanism.
Previously I was just delegating to a Reentrant lock, but to allow a different Thread to unlock a record you can just use the wait(), notify() paradigm.
Delegation to a Reentrant lock is still nicer in my opinion.
I am also considering the possibility of using a ReadWriteLock to implement 2-phase record-level locking, which would require that the same Thread which locks a record, unlocks it.)


throwing an IllegalArgumentException is much better than a NullPointerException

As mentioned in one of my previous posts (, I think that throwing a NullPointerException is acceptable and preferred to throwing an IllegalArgumentException.

The Java API says:

Applications should throw instances of this class to indicate other illegal uses of the null object.

So this is more suited to cases where a caller has passed in a null argument.
Hi ranchers,

In a previous post ( Roel says that update, unlock and delete shouldnt throw RNFE.
I just wanted to expand on this a little further.

So Roel's reasoning is that the client should have first locked the record to do an update, unlock or delete.

I agree that unlock shouldn't throw RNFE - because a client may have locked, then deleted a record.

However, what about the case where we have a *dumb* client.
What if the client which owns the lock decides to delete a record, then tries to delete the record again or update it after deleting it? Shouldn't these cases throw RNFE?

So Roel, would you or wouldn't you recommend making Data abstract. Do you think I could get away with it by documenting it in choices.txt?

a default constructor which will open the provided database from the current directory

Hmmm I disagree with this... The spec says nothing about the need for a default constructor, and having such a constructor would be bad for testability and general bad coding practice as the constructor is doing too much work (see

Still not sure about the non-abstract Data class - in the link in my first post, Roel seems to have done it successfully??