File APIs for Java Developers
Manipulate DOC, XLS, PPT, PDF and many others from your application.
http://aspose.com/file-tools
The moose likes Developer Certification (SCJD/OCMJD) and the fly likes Local & Remote Data Intefaces 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 "Local & Remote Data Intefaces" Watch "Local & Remote Data Intefaces" New topic
Author

Local & Remote Data Intefaces

Christian Garcia
Ranch Hand

Joined: Jan 29, 2002
Posts: 77
I've come across various approaches for implementing interfaces for Local and Remote data objects. It would seem that since a class that implements an interface can throw fewer exceptions that those defined in the function signature then a single interface containing all of the public methods of the Data class throwing RemoteException (in addition to any predefined exceptions) would be sufficient.
Is this correct or am I missing something?
Thanks.
CG


Christian
Bernhard Woditschka
Ranch Hand

Joined: Sep 16, 2002
Posts: 89
That's how i did it
Of course there is a drawback too - users of this API have to catch RemoteExcption for each method.
Bern
Christian Garcia
Ranch Hand

Joined: Jan 29, 2002
Posts: 77
...users of this API have to catch RemoteExcption for each method

Bernhard,
Isn't that what we want? If the API is implemented in a "Remote" scenario the RemoteException would need to be handled (RMI). Likewise, in a "Local" scenario the RemoteException can be ignored when the methods are implemented.
I don't understand the reason why this would impact the resuse of the API. Can you explain a little more?
Thanks!
Bernhard Woditschka
Ranch Hand

Joined: Sep 16, 2002
Posts: 89
Well for this assignmet there is no impact at all
But wat if another programmer wants to use the database API in local mode only - then hhe is forced to catch Exceptions that can never be thrown.
But I don't see a way around throwing RemoteException anyway.
Bern
Christian Garcia
Ranch Hand

Joined: Jan 29, 2002
Posts: 77
One more question:
I've added the interface reference in the Data class. Now, when I code my ConnectionFactory class I'll be returning instances of the Data class. Given that, does the Data class need to extend UnicastRemoteObject??? If so, did you modify Data directly?
Bernhard Woditschka
Ranch Hand

Joined: Sep 16, 2002
Posts: 89
I took a different path
Besides deprecated methods I left Data alone.
Then I created a Interface 'DataExtentionIfc' that basically has all method signatures of Data plus each method throwing RemoteException (in addition to existing throws) plus criteriafind().
Next I created two classes:
DataExtention extends Data implements DataExtentionIfc.
This changes the lock() and unlock() behaviour and adds criteriafind() behaviour.
and
DataExtentionClient implements DataExtentionIfc.
This is a adapter to the RMI Stub
Bern
Peter den Haan
author
Ranch Hand

Joined: Apr 20, 2000
Posts: 3252
Originally posted by Bernhard Woditschka:
Well for this assignmet there is no impact at all
But wat if another programmer wants to use the database API in local mode only - then hhe is forced to catch Exceptions that can never be thrown.
You may misunderstand the meaning of the interface.
DataInterface is the interface for a Data-like database which can be either local or remote. That is why the user of this interface will have to handle RemoteExceptions; such code will be completely agnostic whether it is working with local or remote databases. If you don't want to be agnostic, you shouldn't be using this interface, full stop.
Many have a RemoteDataInterface extends DataInterface, Remote. This is a remote Data-like database. You can omit this interface and have DataInterface extend Remote, but that implies that Data instanceof Remote which seems less than elegant.
A programmer needing just a local database can simply use Data directly. There's no need to handle RemoteExceptions in that case. If you would like to be implementation-independent, you can introduce a third interface, LocalDataInterface, which would extend DataInterface and strip all RemoteExceptions from the method signatures. LocalDataInterface would be a local Data-like database.
- Peter
[ January 09, 2003: Message edited by: Peter den Haan ]
Christian Garcia
Ranch Hand

Joined: Jan 29, 2002
Posts: 77
Peter,
Given the explanation you provided, would this approach be proper:

I appreciate the help with this.
CG
Peter den Haan
author
Ranch Hand

Joined: Apr 20, 2000
Posts: 3252
Originally posted by Christian Garcia:
Given the explanation you provided, would this approach be proper:[...]
The last line should readBut, frankly, I wouldn't bother with LocalDataInterface. Any code that wanted to be purely local could simply use Data itself; I don't see an immediate need for more than one implementation of LocalDataInterface.
- Peter
Christian Garcia
Ranch Hand

Joined: Jan 29, 2002
Posts: 77
Thanks for the info. I'm finally making progress with my design!
CG
Miguel Roque
Ranch Hand

Joined: Oct 24, 2002
Posts: 126
Hello.
In my design, I only have one interface. I've defined a DataInterface that extends Remote and defines all the public methods of Data ading them the throws RemoteException.
The Data class implements this DataInterface. The method signature of the Data class has not been changed, i.e. doen't throw the RemoteException.
Like this, I only have one interface defined.
Is this design ok?
Thanks,
Miguel
Peter den Haan
author
Ranch Hand

Joined: Apr 20, 2000
Posts: 3252
It probably is. The consequence is that Data instanceof Remote. I couldn't find anything in the RMI spec or javadoc that says that this is wrong, but I still didn't like it, so I added a RemoteDataInterface (just two lines of code anyway). But again it doesn't seem to be strictly necessary.
- Peter
Deedy Dee
Greenhorn

Joined: Mar 20, 2002
Posts: 13
peter:
If I don't want to modify Data Class. reference to what you said. I do some change on it somewhat
How do you think ?
interface DataInterface
interface LocalDataInterface extends DataInterface
interface RemoteDataInterface extends DataInterface Remote
DataExtension implements LocalDataInterface,extends Data
Add the lock(), unlock() and criteriafind() operation to DataExtension.
Is it ok? thanks.
-deedy


-deedy
Nicole Gustavson
Greenhorn

Joined: Jan 06, 2003
Posts: 12
Hiya Christian, Peter, everyone,
I've seen mention of the following interface relationships:

Then the client uses it something like this:

This is fine as long as all possible databases only throw RemoteException and DatabaseException; but it causes problems when you create a different type of database. For an example, take a MonkeyDatabase that uses intelligent monkeys to remember and share data. Each method in MonkeyDatabase throws MonkeyException, which includes such categories as SleepingMonkeyException or DrunkenMonkeyException. If I want my clients to use this database class, I now have to alter the Database interface to have all of its methods throw DatabaseException, RemoteException, and MonkeyException. Worse yet, all of my client code now has to be rewritten to catch MonkeyException.
There are several alternatives that I can think of:
1)
You can have the Database superinterface throw Exception, to cover every type of database you will ever come across. Now all of your client code has to be rewritten to catch Exception. Yech! If you are catching Exception all over the place, you can forget recovering from recoverable Exceptions -- recovery code would have to be added to each client method call.
2)
You can have your clients only make use of one particular type of Database. For instance, Program A knows it's only going to use a RemoteDatabase so it only has to catch RemoteException and DatabaseException. If it wants to use MonkeyDatabase, it will specifically create a MonkeyDatabase and not make use of the Database interface. In this case, is there really any benefit to having a Database superinterface? A bit, in that you know its subclasses are going to implement certain methods. But you can't actually make use of it in your clients.
3)
(It's the last one so you know this is the one I like ) You can create a Database superinterface in which all the methods throw only DatabaseException. All of your clients will use this interface and only have to catch DatabaseException. You then create a MonkeyDatabaseClient that implements Database, delegates all calls to a MonkeyDatabase, and handles all MonkeyExceptions.
Something like this:

You get the idea. The Database interface stands on its own independent of any subclass, clients can enjoy a consistent unchanging interface, and there is a possibility of a consistent error recovery mechanism for each individual database implementation.
There must be a pattern for this -- facade or adapter or something -- help me out? Then the class would be called MonkeyDatabaseAdapter.
You can extrapolate this example to say, a SqlDatabase that throws SqlExceptions or something, but I can't imagine why you would ever need one of those.
- Nicole.
Disclaimer: No animals were harmed or forced to imbibe alcoholic beverages in the making of this post.
[ January 19, 2003: Message edited by: Nicole Gustavson ]
Fixing code and such
[ January 19, 2003: Message edited by: Nicole Gustavson ]
Peter den Haan
author
Ranch Hand

Joined: Apr 20, 2000
Posts: 3252
Originally posted by Zhihui Di:
If I don't want to modify Data Class. reference to what you said. I do some change on it somewhat
Looks fine; I wouldn't bother with LocalDataInterface however. What are your reasons for choosing extension over modification? Can you formulate the reasons in terms of responsibilities (i.e. sthng like: these facilities had to be implemented in a separate class DataExtension because the responsibilities of Data are ??? which clearly do not include lock(), unlock() or criteriaFind()).
This is not a critique. I'm merely curious, and you'll have to argue this for your design decisions document anyway.
- Peter
Peter den Haan
author
Ranch Hand

Joined: Apr 20, 2000
Posts: 3252
Originally posted by Nicole Gustavson:
[...] This is fine as long as all possible databases only throw RemoteException and DatabaseException; but it causes problems when you create a different type of database. For an example, take a MonkeyDatabase that uses intelligent monkeys to remember and share data. Each method in MonkeyDatabase throws MonkeyException [...]
Yes and no. In fact, this has been discussed very occasionally in the past. The solution is obvious but rather easy to miss.
A big hint is given by RemoteException itself. Note that RemoteException extends IOException; the RMI communication protocol is a type of I/O. If you would use a Socket implementation rather than an RMI implementation, your socket I/O routines would throw other subclasses of IOException such as SocketException.
If you would use intelligent monkeys to share data, then those monkeys would, just like RMI or sockets, be a transport subsystem. In other words, MonkeyException should extend IOException.
To make your DataInterface transport-agnostic, all you have to do is use IOException instead of RemoteException.
As you note, you certainly don't want the DataInterface to throw Exception. That would throw away all information on the exception types that can be thrown. IOException is fairly broad but probably a fair compromise. It would not limit clients to any single form of transport as long as the transport threw some flavour of IOException (which is not an outlandish requirement). You don't have to fiddle with adapters.
- Peter
Nicole Gustavson
Greenhorn

Joined: Jan 06, 2003
Posts: 12
Hi Peter,
Thanks for answering my post... it was so verbose I was afraid no one would be able to get through it.
3 questions to you...
1. What do you do if you can't make MonkeyException extend IOException? (SqlException doesn't extend IOException.)
2. What do clients do with the IOException?
3. What if someone comes up with a way they want to recover from all RemoteExceptions, MonkeyExceptions, or IOExceptions, or do some special treatment of one of these? Where would you put the code?
I've already implemented my "adapter" class (it's just the "client-side class that implements the public methods of Data"). I put all my RMI-involved classes, including this one, into a "remotedb" package and no class outside that package knows anything about RMI, including RemoteException or anything. The encapsulation really appeals to me.
Now I'm off to search for the threads you mentioned -- I'm curious to see if anyone has had the same design, and/or the same thoughts.
BTW, what really started me thinking about changing my design (I originally had it much as you mention), was reading a couple of good articles on exceptions:
Designing With Exceptions
and
Does Java Need Checked Exceptions?: the article and subsequent discussion raise a lot of good questions. [for example, I was opposed to the concept of checked exceptions going in, but after reading the discussion I was totally won over to the pro-checked camp.]
Reading about the fundamental purpose of exception handling, which is to handle exceptions (as opposed to work around or somehow ignore them), really convinced me that clients of Database should not have to know about any exceptions but DatabaseExceptions. The client of a Database is simply incapable of handling a RemoteException, IOException, etc. Exception handling is so much more than a try/catch block.
The compromise of having Database throw RemoteExceptions or IOExceptions just seems like a workaround, an avoidance of the real issue, to me.
Thanks again
- Nicole.
Deedy Dee
Greenhorn

Joined: Mar 20, 2002
Posts: 13
Peter:
I think the Data class is not mine. It is writtern by others. I think I should not modify the Data. just like A software update. we should add a software patch instead of modify the software. This is the reason I choose extension instead of modification. I don't think about responsibility from OOP.
Peter den Haan
author
Ranch Hand

Joined: Apr 20, 2000
Posts: 3252
Originally posted by Deedy Dee:
I think the Data class is not mine. It is writtern by others. [...] I don't think about responsibility from OOP.
I do not think that this is the point of view that Sun wants you to take. You are being asked to make modifications to the class (eliminating deprecated methods). As I read them, the instructions imply that you can take (shared) ownership of the class. As in any team development situation, you would not want to make incompatible changes to the class' API if you could help it, but carefully considered compatible changes are perfectly alright. So put your OOP hat on and think about architecture and responsibilities and design decisions. That is what Sun wants you to do, very much so.
- Peter
[ January 24, 2003: Message edited by: Peter den Haan ]
Peter den Haan
author
Ranch Hand

Joined: Apr 20, 2000
Posts: 3252
Originally posted by Nicole Gustavson:
1. What do you do if you can't make MonkeyException extend IOException? (SqlException doesn't extend IOException.)
Wrap the MonkeyException inside some flavour of IOException.This pattern is quite commonly used -- a RemoteException, for example, may well wrap an underlying SocketException or a ClassNotFoundException. An SQLException can be caused by an underlying SocketException, not to mention all the different error conditions inside the database itself.
In fact, this boils down to introducing a wrapper object much like the one you're using now. The difference is, this would happen only when necessary.
2. What do clients do with the IOException?
One possible mode of error recovery -- which is out of scope IMHO -- would be to junk the existing Connection, create a new one, and retry.
3. What if someone comes up with a way they want to recover from all RemoteExceptions, MonkeyExceptions, or IOExceptions, or do some special treatment of one of these? Where would you put the code?
There are a number of ways to go about this. One of the solutions is to introduce a transport-specific wrapper object that handles error recovery and ultimately throws a fixed set of exceptions, perhaps subclasses of DatabaseException. You would still want to give the client a way to broadly distinguish between transport exceptions, logical database exceptions and perhaps physical database exceptions. This approach only makes sense if there any intelligent transport-specific recovery can be done.
This solution may sound familiar to you
Another solution, one which leaves the ultimate decisions about error recovery to the client code, is to use a Strategy: together with your transport-specific Connection implementation, you could create a transport-specific RecoveryStrategy implementation. This strategy would expose methods such as isRecoverable(IOException) or doesItMakeSenseToRetry(IOException) that enable you to decide how to handle exceptions. Again, this is only worth it if meaningful recovery is possible.
I've already implemented my "adapter" class (it's just the "client-side class that implements the public methods of Data").
If that would have been all it's there for, then you could have junked the adapter. The Connection stub class generated by rmic satisfies this requirement in all respects.
I put all my RMI-involved classes, including this one, into a "remotedb" package and no class outside that package knows anything about RMI, including RemoteException or anything. The encapsulation really appeals to me.
You can achieve the same level of genericity by having the interface throw IOException rather than RemoteException. And your adapter would have to re-throw unrecoverable exceptions anyway, probably wrapped in some kind of other exception -- DatabaseTransportException or whatever. The client will still have to handle the buggers. And the user interface will still have to be able to distinguish between the different exception classes: there's a big difference between a transport exception ("Please try again in a few minutes") and a corrupted database ("Call support immediately and quote error U-R-D34D").
Now I'm off to search for the threads you mentioned -- I'm curious to see if anyone has had the same design, and/or the same thoughts.
Personally, I have considered a client-side adapter fully encapsulating all RMI aspects, but decided against it. It's yet another class, yet another complication of the design, and most of the benefits you can get more simply.
As an aside -- using a client-side adapter, you can implement lock() and unlock() as specified without using an RMI Factory! Surprisingly, I've never seen anyone doing this. Anyway, the factory approach is superior.
BTW, what really started me thinking about changing my design [...] was reading a couple of good articles on exceptions:
Introducing an adapter class just to abstract a completely theoretical transport layer that doesn't throw IOException is over-engineering. Besides, when confronted with such a transport you can introduce an adapter for that transport anyway.
There is a lot of merit in your idea that, if there is some smart transport-level error recovery to be done, that is best done in a client-side adapter object. Your example of an SQL Connection throwing SQLExceptions is pretty apt there. But I would contend that in the context of the assignment this, too, is over-engineering. There is no serious error recovery to be done.
If you haven't done so long ago, read any decent article on XP and agile methodologies, and specifically any discussion of the XP mantra "do the simplest thing that can possibly work". In the context of the assignment, your wrapper might be argued to be questionable future-proofing which will merely make change more difficult and maintenance more costly.
[...] The client of a Database is simply incapable of handling a RemoteException, IOException, etc. Exception handling is so much more than a try/catch block.
I agree with the last statement. I do not necessarily agree with the former. As argued above, there is some recovery you can do if you know that the fault is at the transport level. At the same time, it is out of scope for the assignment. That also means that your adapter object doesn't serve a useful purpose in the assignment. With that in mind, I'd argue for doing the simplest thing that could possibly work.
Thanks for the discussion. I see what you're trying to do, and agree that it's a good idea -- just not in this context. But that is a judgment call rather than something which is "wrong" or "right", black or white.
- Peter
[ January 24, 2003: Message edited by: Peter den Haan ]
Nicole Gustavson
Greenhorn

Joined: Jan 06, 2003
Posts: 12
The difference is, this would happen only when necessary.

When's that?
One possible mode of error recovery -- which is out of scope IMHO -- would be to junk the existing Connection, create a new one, and retry.

Where would you put this code?
Another solution, one which leaves the ultimate decisions about error recovery to the client code, is to use a Strategy: together with your transport-specific Connection implementation, you could create a transport-specific RecoveryStrategy implementation.

Would this be simpler or more maintainable than a one-class adapter? Also, what is a "transport-specific Connection implementation", and how do you use it?
If that would have been all it's there for, then you could have junked the adapter. The Connection stub class generated by rmic satisfies this requirement in all respects.

Can the stub of a server-side remote class be accurately described as a client-side class? I have never heard that before. In my mind, a stub is an RMI implementation artifact, big time.
Consider the following requirements:
  • "There are three key parts: [...] a client-side database client part that handles the networking [not business logic] on behalf of the user interface"
  • "The remote client [not server] code that you write must provide all the public methods of the suncertify.db.Data class"
  • Under the Writing Data Client heading: "...you should create a client program. This implementation should include a class that implements the same public methods as the suncertify.db.Data class..."

  • I believe you are questionably reinterpreting a repeatedly-mentioned, reasonably specific requirement.
    As an aside -- using a client-side adapter, you can implement lock() and unlock() as specified without using an RMI Factory!

    How? (Just curious.)
    Introducing an adapter class just to abstract a completely theoretical transport layer that doesn't throw IOException is over-engineering.

    Them's fightin' words, Pete! But seriously, I do appreciate the thought-provoking things you have to say.
    At the same time, it is out of scope for the assignment. That also means that your adapter object doesn't serve a useful purpose in the assignment.

    Points to consider:
  • Is good OO design out of scope for this project?
  • Is the encapsulation of application layers (i.e. shielding each layer from the implementation details of the other layers) a part of good OO design?
  • Is appropriate exception propagation a part of the proper encapsulation of application layers?


  • Thanks for the discussion.
    Thank you.
    - Nicole.
    Peter den Haan
    author
    Ranch Hand

    Joined: Apr 20, 2000
    Posts: 3252
    Originally posted by Nicole Gustavson:
    When's that [necessary]?
    When exceptions need wrapping, e.g. when a transport throws exceptions other than IOExceptions, or when it would facilitate better error handling.
    Where would you put this [error recovery] code?
    It would be business object / facade that handles the nitty-gritty behind the search and bookFlight methods.
    Would this be simpler or more maintainable than a one-class adapter?
    It depends on the problem you're solving (we're getting very academic here). In simple cases, the adapter is simpler. If you have to support many different transports and your recovery options are complicated, or if recovery is very much tied up with client code, a strategy will help eliminate duplicated code. It's hard to think of an example that isn't completely artificial, though. And it's got nothing to do anymore with the FBN project.
    Also, what is a "transport-specific Connection implementation", and how do you use it?
    The rmic-generated stub for Connection is one. Your adapter is one.
    Can the stub of a server-side remote class be accurately described as a client-side class?
    Yes. It's a plain old Java class. It lives on the client.
    In my mind, a stub is an RMI implementation artifact, big time.
    No it isn't -- in the sense that every transport that uses Java method-call semantics will need a class like that (although these days you'd use dynamic proxies). If you would have gone for the Sockets option, you would have naturally coded this stub yourself.
    "There are three key parts: [...] a client-side database client part that handles the networking [not business logic] on behalf of the user interface" -- check, that's exactly what the stub does. "The remote client [not server] code that you write must provide all the public methods of the suncertify.db.Data class" -- my client provided all of that. I do not read in this a requirement that requires me to write every line of the client-side class that implements DataInterface. "...you should create a client program. This implementation should include a class that implements the same public methods as the suncertify.db.Data class..." -- check, that class is definitely included, the stub.
    I do not believe that I'm reinterpreting the letter of these requirements, or even going against the spirit of the requirements. I also disagree that these requirements are particularly specific. In fact, if you would want to mandate the presence of some client-side class implementing the Data interface in such a way as to leave the option open for the developer to use an RMI stub, but at the same time formulate the requirement ambiguously enough not to give the idea away, this is more or less what you'd come up with.
    Three points.
    First, what is this requirement doing here? Simple; it is there to force you into the direction of a classic thick-client client/server architecture. Yes, this is just an interpretation on my part.
    Second, it works as an architecture. It is the simplest thing that can possibly work -- and the instructions are very explicit in encouraging simplicity.
    Third, and most importantly, my assessor had no problems whatsoever with this approach. I have been present in this group for years, and moderated it for some of that time, but have not seen any evidence of points being deducted for this approach. Even if it is not exactly what Sun had in mind when drafting the requirements, it is apparently regarded as a reasonable interpretation.
    How [implement lock() and unlock() as specified without using an RMI Factory]? (Just curious.)
    In a client-side adapter, you can keep track of the locks held by the client and prevent "illegal" calls to lock() and unlock() from propagating to the server. That way, you need only a single server-side class that is used by all clients. No, I don't think that'd be a particularly good architecture.
  • Is good OO design out of scope for this project?
  • Is the encapsulation of application layers (i.e. shielding each layer from the implementation details of the other layers) a part of good OO design?
  • Is appropriate exception propagation a part of the proper encapsulation of application layers?
  • Now them's fightin' words, Nic! If you've read a couple of my posts, you know full well that I completely agree on all counts. But at the same time I do of course resent the implication that my suggestions compromise "good OO design". Truth is, an important part of solid OO design is choosing how much abstraction, decoupling, generalisation and layering is required to adequately and elegantly solve the problem at hand. Err on the light side, and you get a messy, badly performing, hard to maintain, inflexible application. Err on the heavy side, and you get a bloated, badly performing, over-engineered application -- that is, if your project doesn't get cancelled halfway through.
    The FBN problem is very simple. It asks for a very simple design; the simplest thing that can possibly work, and no simpler. There is no question that an adapter layer can usefully absorb some transport-specific concerns. Great. But here, there aren't any transport-specific concerns to speak of. There isn't any error handling to speak of. You don't need it.
    - Peter
    [ February 06, 2003: Message edited by: Peter den Haan ]
    [ February 06, 2003: Message edited by: Peter den Haan ]
     
    I agree. Here's the link: http://aspose.com/file-tools
     
    subject: Local & Remote Data Intefaces
     
    Similar Threads
    Exception stratigy in scjd???
    design issue: throwing generic exceptions? why?
    Basic Design
    my design choice
    Final design