Win a copy of The Little Book of Impediments (e-book only) this week in the Agile and Other Processes forum!
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

RMI question

 
Hugh Johns
Ranch Hand
Posts: 36
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi
I am having a problem implementing RMI in my system, I am using a similiar method to Max Habibi's book, but am getting an error.
the main interface is as supplied by sun i.e.

this is then implemented in the Data class (main DB access class)for local access.
For remote access the following interface extends Remote and DBAccess

then this is implemented in the main remote class

This appears to be similiar to the book, but I am getting the compile error
suncertify/remote/DBDatabaseImpl.java:48: updateRecord(long,java.lang.String[],long) in suncertify.remote.DBDatabaseImpl cannot implement updateRecord(long,java.lang.String[],long) in suncertify.db.DBAccess; overridden method does not throw java.rmi.RemoteException
I cannot change the sun supplied interface DBAccess, therefore what am I doing different from the book?
Regards
Hugh
 
Leo Tien
Ranch Hand
Posts: 156
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Hugh:
Your remote interface DBDatabaseRemote shouldn't extends DBAccess. Should you want to expose these methods to client??
So in your remote interface, there are only methods you exposed to client, like search, book, etc.
In my design, like this:
I have one interface named RecordAccess, it's have two methods: search and book, both these methods throw Exception.
Another two interface extends it, RecordAccessLocal and RecordAccessRemote, the second one extends Remote interface simultaneity, so the methods in it will throw RemoteException.
In remote model, execution like this:
client call --> RecordAccessFactory --> ConnectionFactory --> RecordAccessRemote
Both RecordAccessLocalImpl and RecordAccessRemoteImpl wrap Data class.
Make sense??
 
George Marinkovich
Ranch Hand
Posts: 619
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Hugh,
Max's project works because his local interface has methods that throw IOException. If those methods threw anything other than IOException, then Max would have experienced the same problem you're having.
Leo is pointing you toward a 3-tier solution. It is one way of solving this problem. It's a good way, but it's not the only way.
There is another alternative if you wish to have a 2-tier solution. You can simply create your own interface (nearly identical to DBMain) wherein the methods throw IOExecption. Then you can create your remote interface in the same way Max did. In addition, you must then adapt your new interface to the DBMain interface (for example, by using the object adapter design pattern).
Whether 3-tier or 2-tier is better has been debated endlessly on this forum. You can search for the threads that discuss this to help you make up your mind if you want.
Hope this helps,
George
 
Hugh Johns
Ranch Hand
Posts: 36
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Leo / George
Thank you for your replies.
A final question on this, I have implemented a 2 tier system, using a second interface DBRemoteMap. This is exactly the same as the DBAccess interface except it extends java.rmi.Remote and each DBAccess method throws an extra exception (RemoteException).
I have then used this interface to implement the RMI side in DBDatabaseImpl.java (wraps Data methods)
Only problem is I wanted to implement a connection factory that returns a single type object to hide local/network choice there..
ie.. public DBAccess getDatabase()
How do I work it so I have only one interface ?
 
George Marinkovich
Ranch Hand
Posts: 619
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Hugh,
This is one way. Copy the DBAccess interface into a new interface called DBAccessCommon. The difference between DBAccess and DBAccessCommon is that DBAccessCommon throws IOException for each method instead of the original exceptions thrown in DBAccess. Then using the object adapter design pattern you create a DBAccessCommonImplementation that wraps calls to a member Data object. Now you have your DBRemoteMap interface extend the DBAccessCommon and Remote interfaces. So, your connection factory returns an object of the DBAccessCommon interface. In the case of a local database it returns a DBAccessCommonImplementation object; in the case of a remote object it returns a DBRemoteMapImpl object. In either case it returns an object that implements the DBAccessCommon interface. Make sense?
This strategy makes use of a trick that I first saw used by Max in his SCJD Exam book. Basically the trick relies on the fact that your common (for local and remote access) interface, here DBAccessCommon, throws IOException for each method. IOException just happens to be a superclass of RemoteException. So when you extend DBAccessCommon and Remote to get your remote interface there are no problems. The only reason we have to make use of this trick is because Sun didn't do us a favor when they created the interface they supplied to us. If they had made the methods in the DBAccess interface throw IOException then we wouldn't have needed the DBAccessCommon inteface and the DBAccessCommonImplementation adapter class. But then, where would the fun be?
Hope this helps,
George
 
Hugh Johns
Ranch Hand
Posts: 36
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
George
Thank you again for your kind reply.
However I have another question...
In creating the interface DBAccessCommon I have copied the original DBAccess interface, but each method in the DBAccessCommon interface only throws an IOException (instead of any other exception ), as per above post.
Problem is when I implement DBAccessCommon in DBAccessCommonImplementation (local) and DBRemoteMapImpl (remote), both wrap calls to a member Data object, which in turn (since it implements DBAccess by requirements) throws specific sun specified exceptions (RecordNotFoundException etc).
Therefore in wrapping the data methods in each class I have to catch those specific exceptions and either deal with them there or chain them into an IOException (the only exception the DBAccessCommon interface allows).
Problems
1. IOException does not support exception chaining, so cannot chain the cause exceptions to a higher level.
2. I am not sure if handling these sun specified exception at this level (DBAccessCommonImplementation, DBRemoteMapImpl ), is right.
Any advice on this?

Thank you for your help in this.
Regards
Hugh
 
George Marinkovich
Ranch Hand
Posts: 619
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Hugh,

B. Wrap it in an unchecked exception, that is, a RuntimeException or a derived subclass thereof. You can use exception chaining with RuntimeExceptions. For example,

Because it is a RuntimeException (that is, an unchecked exception) being thrown out of the method it is not necessary to identify this exception in the throws list. You should mention it with a @throws clause in the method's javadoc comment though.
There are pros and cons for the A and B techniques.
Pros for A:
Since IOException is a checked exception you know that any clients of this method will have to handle the possibility of an IOException being thrown or the compiler will bite them.
Cons for A:
Does RecordNotFoundException really belong in an IOException? You have to convince yourself one way or the other.
Pros for B:
You don't have to believe that RecordNotFoundException really belongs in an IOException. You can subclass the RuntimeException to reflect more accurately what's going on (for instance, RecordProblemException extends RuntimeException).
Cons for B:
Because RuntimeException is not a checked exception you don't force any of the method's clients to handle the exception, they should but you can't get the compiler to bite them if they don't.
Should the Sun-specified exceptions be handled at this level? Well, if a record can't be found at the database level you're going to have to send some sort of message to client so the client can inform the user why his database operation failed. Propogating the exception is a good way to inform the client about what went wrong with the database operation.
Hope this helps,
George
[ February 17, 2004: Message edited by: George Marinkovich ]
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic