my dog learned polymorphism*
The moose likes Developer Certification (SCJD/OCMJD) and the fly likes Implementing the Oracle Supplied Interface - Handling Errors Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of Android Security Essentials Live Lessons this week in the Android forum!
JavaRanch » Java Forums » Certification » Developer Certification (SCJD/OCMJD)
Bookmark "Implementing the Oracle Supplied Interface - Handling Errors" Watch "Implementing the Oracle Supplied Interface - Handling Errors" New topic
Author

Implementing the Oracle Supplied Interface - Handling Errors

Glen Iris
Ranch Hand

Joined: Jul 13, 2011
Posts: 164

Hey Guys,

Im trying to treat my Data class (implementation of the Oracle supplied interface) like a public API.

I was wondering, what the best way is to handle the following scenario:

A user passes the delete() method a record number which does not exist (say 35 when there are only 33 records in the database).

As far as I can see, my choices are:

1 - I extend the Oracle supplied interface, to make the delete method throw an ArrayIndexOutOfBoundsException. Then I throw this back to the client to handle.

2 - I catch the ArrayIndexOutOfBoundsException in the delete method and the client never knows of the exception. They happily think they deleted a record which doesnt exist.

I can see the arguments for and against each one. But I would like to hear your opinions on which is the best / standard way to handle this scenario.

Thanks,

G


OCPJP 6, OCMJD
Roel De Nijs
Bartender

Joined: Jul 19, 2004
Posts: 5147
    
  12

That scenario is simply impossible, because you can only delete a successfully locked record. If you try to lock a non-existing record you'll get a RecordNotFoundException. If the API is wrongly used (e.g. deleting a record without locking it first) I would throw an IllegalStateException.


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

Joined: Jul 13, 2011
Posts: 164

hey Roel, thanks for the reply. I hope you're having a nice break

Ok, how about a scenario that is not impossible. Let me describe what is happening when I run Roberto's test class:

Roberto locks a record - success
Roberto attempts to update the record:
In the update method, it is found that if his update succeeds, two entries will exist in the database with an identical primary key. So, the update method throws a DuplicateKeyException. This permeates back to Roberto's test class and ends up in his catch statement. Roberto never gets to call unlock

My thoughts are, if an exception is thrown, anywhere in the update method, that the update method unlocks the record. So lets say I make this happen...

Roberto locks a record - success
Roberto attempts to update the record:
In the update method, it is found that if his update succeeds, two entries will exist in the database with an identical primary key. So, the update method throws a DuplicateKeyException. This permeates back to Roberto's test class and ends up in his catch statement. Roberto, after his bad experience the last time has a finally block, which tries to unlock the record. When he tries to unlock the record, he finds that he does not own it. In this case, should I throw an exception back to Roberto and tell him he cannot unlock what he does not own?

G


Roel De Nijs
Bartender

Joined: Jul 19, 2004
Posts: 5147
    
  12

The unlock-method should always be executed, so the common code for this would be (or something similar of course)


If you succeeded to lock record 1, how can you then not own the lock for that record when unlocking record 1. Because if you didn't have the lock for record 1, you can't update the record
Glen Iris
Ranch Hand

Joined: Jul 13, 2011
Posts: 164

Roel De Nijs wrote:The unlock-method should always be executed, so the common code for this would be (or something similar of course)

try {
lock(1);
update(1, newData);
} catch (SomeException1 e) {
} catch (SomeException2 e) {
} finally {
unlock(1);
}


But I cannot guarantee that Roberto (or any calling client to my public Data class) will place their unlock in a finally block as you have above.
Roel De Nijs wrote:If you succeeded to lock record 1, how can you then not own the lock for that record when unlocking record 1. Because if you didn't have the lock for record 1, you can't update the record

What I was describing here was:
1- I cannot be sure that a client (caller of my public Data API) does not have unlock in a finally block, so the update method unlocks the record if an exception occurs in the update method. This exception is thrown back to the client. This client does have their unlock in a finally block - when they call it, they find that it is no longer locked by them as it was unlocked by the update method when an exception occurred.
Roel De Nijs
Bartender

Joined: Jul 19, 2004
Posts: 5147
    
  12

Relax, that's not a problem at all!

You develop a public API (which is hopefully well documented). If I decide to misuse your API then I have to cope with the consequences. I (as an API user) am responsible for always unlocking the record I locked before. Similar I should always close a file I opened, always release a used connection of a connection pool,... If I don't do that, I will run into troubles.

So this scenario is not something you should worry about. It's not your concern. You just have to develop your API and the developer who uses it to develop his application has to make sure he uses it appropriately.
Glen Iris
Ranch Hand

Joined: Jul 13, 2011
Posts: 164

Thanks Roel!

EDIT: Actually, I have another question.

OK, so like the scenario above:

Roberto locks a record
Roberto attempts to update the method, the update method throws a DuplicateKeyException back to the update method in public Data class. The update method is the implementation of Oracles supplied update method and cannot throw a DuplicateKeyException back to the client/Roberto.

So - Should I make it so that the public update method can throw this exception? or throw an IllegalStateException instead (which would mean I dont need to change the overridden method signature)

G
Roel De Nijs
Bartender

Joined: Jul 19, 2004
Posts: 5147
    
  12

I assume you use some kind of combination of fields to make a key.

I don't think it's a good thing to be able to update a primary key. So it makes sense that a create-method throws such an exception, but it's a bad thing if your update-method can update primary key fields. In my assignment (URLyBird) there was no unique combination of primary key fields (a hotel can have many rooms with exact the same properties), but maybe in the B&S assignment you can use some combination of fields to create some kind of (unique) key. But if it's primary key, it's a very bad idea to change it.

Good luck!
Glen Iris
Ranch Hand

Joined: Jul 13, 2011
Posts: 164

I dont think I explained very clearly -

I never allow my primary key to be changed, even in my update method.

Essentially my question boils down to:

How can I inform a client that their attempted update failed when Oracles supplied Update method has a void return type?
Roel De Nijs
Bartender

Joined: Jul 19, 2004
Posts: 5147
    
  12

Glen Iris wrote:How can I inform a client that their attempted update failed when Oracles supplied Update method has a void type?

I had a look at my assignment, because it's almost 2.5 years ago since I passed My method also has a void return type and throws nothing but a RecordNotFoundException (which makes no sense, because like discussed in another thread this exception should be thrown by lock-method). I used a record cache, so updates always succeed. I guess you use direct file access and you are looking for a way to handle these IOExceptions

When an error occured (like I/O) while I'm writing back all my records to the file I throw a runtime DatabaseException. You can't do anything else, because it can't be a checked exception (breaks your interface method signature), so it has to be a runtime exception. And if you decide to use IllegalStateException or some kind of custom DatabaseException that's up to you. If you decide to use a custom exception, make sure to make it generic, so you don't know if the database behind the application is a RDBMS or a flat file. That makes it a lot easier to change your FileAccess class (throwing nothing but IOExceptions) with a SqlAccess class (nothing but SQLExceptions are thrown), because you need only to change the Data class: just wrap the SQLException (instead of IOException) into a DatabaseException and your program will keep running!
Glen Iris
Ranch Hand

Joined: Jul 13, 2011
Posts: 164

Thanks Roel.

What are your thoughts on just throwing a RuntimeException with the String message passed to it by the underlying IOExceptions / DuplicateKeyExceptions / InterruptedException?

G
Roel De Nijs
Bartender

Joined: Jul 19, 2004
Posts: 5147
    
  12

Glen Iris wrote:What are your thoughts on just throwing a RuntimeException with the String message passed to it by the underlying IOExceptions / DuplicateKeyExceptions / InterruptedException?

First of all I would create my own custom runtime exception (it's easier to catch than the RuntimeException, because NullPointerException, IllegalArgumentException,... will all be caught when catching RuntimeException). Secondly I would always provide a (simple) message of my own (e.g. "reading record[recNo] failed due to I/O error") instead of reusing some message provided by the exception that causes the problem.

Just my 2 cents. Now it's time for
Glen Iris
Ranch Hand

Joined: Jul 13, 2011
Posts: 164

Thank you. You've been a great help as always. Goodnight Sir
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: Implementing the Oracle Supplied Interface - Handling Errors
 
Similar Threads
Locking & Synchronization on Bodgitt & Scarper
Why throw an RecordNotFoundException in your unlock method?
Locking strategy URLyBird 1.1.1 with ReentrantLock
Entity Bean -- Few Questions
B&S 2.1.1: lock(), delete() and unlock() confusion