Christian
...users of this API have to catch RemoteExcption for each method
Christian
Christian
You may misunderstand the meaning of the interface.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.
Peter den Haan | peterdenhaan.com | quantum computing specialist, Objectivity Ltd
Christian
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.Originally posted by Christian Garcia:
Given the explanation you provided, would this approach be proper:[...]
Peter den Haan | peterdenhaan.com | quantum computing specialist, Objectivity Ltd
Christian
Peter den Haan | peterdenhaan.com | quantum computing specialist, Objectivity Ltd
-deedy
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()).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
Peter den Haan | peterdenhaan.com | quantum computing specialist, Objectivity Ltd
Yes and no. In fact, this has been discussed very occasionally in the past. The solution is obvious but rather easy to miss.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 [...]
Peter den Haan | peterdenhaan.com | quantum computing specialist, Objectivity Ltd
-deedy
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.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.
Peter den Haan | peterdenhaan.com | quantum computing specialist, Objectivity Ltd
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.Originally posted by Nicole Gustavson:
1. What do you do if you can't make MonkeyException extend IOException? (SqlException doesn't extend 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.2. What do clients do with the IOException?
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.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?
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've already implemented my "adapter" class (it's just the "client-side class that implements the public methods of Data").
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").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.
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.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.
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.BTW, what really started me thinking about changing my design [...] was reading a couple of good articles on exceptions:
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.[...] 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.
Peter den Haan | peterdenhaan.com | quantum computing specialist, Objectivity Ltd
The difference is, this would happen only when necessary.
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.
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.
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.
As an aside -- using a client-side adapter, you can implement lock() and unlock() as specified without using an RMI Factory!
Introducing an adapter class just to abstract a completely theoretical transport layer that doesn't throw IOException is over-engineering.
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.
Thank you.Thanks for the discussion.
When exceptions need wrapping, e.g. when a transport throws exceptions other than IOExceptions, or when it would facilitate better error handling.Originally posted by Nicole Gustavson:
When's that [necessary]?
It would be business object / facade that handles the nitty-gritty behind the search and bookFlight methods.Where would you put this [error recovery] code?
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.Would this be simpler or more maintainable than a one-class adapter?
The rmic-generated stub for Connection is one. Your adapter is one.Also, what is a "transport-specific Connection implementation", and how do you use it?
Yes. It's a plain old Java class. It lives on the client.Can the stub of a server-side remote class be accurately described as a client-side class?
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.In my mind, a stub is an RMI implementation artifact, big time.
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.How [implement lock() and unlock() as specified without using an RMI Factory]? (Just curious.)
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.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?
Peter den Haan | peterdenhaan.com | quantum computing specialist, Objectivity Ltd
Did you see how Paul cut 87% off of his electric heat bill with 82 watts of micro heaters? |