Checked exceptions design question

Hi,

I'm writing an RMI replacement which has similar semantics and I have the following design problem:

- A client invokes server.method(myList)

- myList is of type List and is actually a Remote object which resides on the client code. So when the server method uses this list, it is actually communicating back with the client and sending resulting back and forth.

- The server code is defined as

public Server

{

publicvoid method(List myList)

{

// A network error occurs while trying to access myList

}

}

Ideally I'd like to throw RemoteException from the list in case of a network error, but I can't do that because RemoteException is a checked exception and cannot be added to the List interface (it would break its contract). So I was thinking maybe that the list should throw a custom Error if an I/O occurs and then my framework would catch it at the end of the method and throw RemoteException back on the client-end of things. I am uncomfortable throwing and catching an Error but I don't want the server-code to try to catch the thrown exception either. As far as I can tell, if a RemoteException occurs from inside the list, there is absolutely no way for the server code to recover. It can't request a new method argument from the client and therefore it must always simply rethrow the exception. What do you think? Do you have a better idea?

Thanks,

Gili

[1701 byte] By [cowwoca] at [2007-11-26 16:08:43]
# 1

You been hanging too much with those ORM guys. Come back to the OO side and do yourself a favor. Catch the checked exception.

If the method is not designed to take a list that throws exceptions, then you need to pass it a different type of list, or create a different method that will accept your type of list.

Don't bang a square peg into a round hole.

If you give a remote object to some object that can not deal with the fact that it is remote, then you are asking for trouble. Perhaps you want to wrap that object with some other object that _can_ deal with the fact that it is remote, and also exposes itself as an ordinary List.

_dnoyeBa at 2007-7-8 22:31:02 > top of Java-index,Core,Core APIs...
# 2

_dnoyeB,

Good catch about the ORM use-case, how'd you know? :)

I don't think there is any nice way to wrap the List with some adapter that supports Remote. It seems like a lot of work because you'd have to write such an adapter once per type of object you plan on wrapping.

Alternatively, I was thinking that instead of throwing an Error from the List proxy, I'd throw an unchecked exception. It cleans up having to catch an Error and still functions the same way. I know what you mean about forcing Remote on a class that wasn't designed for it, but can you honestly think of a use-case where the server *can* recover once its argument throws RemoteException?

Gili

cowwoca at 2007-7-8 22:31:02 > top of Java-index,Core,Core APIs...
# 3

Bad idea. Especially in remote computing. You WILL see RemoteExceptions. But these are not serious fatal exception. Yes, they can and should be recovered from. All of my remote objects are handled by classes that can deal with the inevitable loss of connectivity without harassing the user. Yes its work, but once you get a nice architecture to handle it, then its just repeating the same for each new object. Remote objects should not be treated like they are not remote objects. I assumed you were from ORM because its the ORM culture that wants to mask exceptions all the time. They want to claim their ORM objects are POJOs. They meet this claim by showing you and object that appears to not throw exceptions. But of course it throws tons of exceptions and can happen anywhere in your program and shut the whole thing down. If you can't handle it, don't catch it, I agree. But...

I have a piece of software I use called StateMate, also another piece I use called TeamCenter. If you unplug the network cable, both shut down and could care less what you were doing at the time. This is unacceptable to me.

Now if you want to hotwire it by making a custom runtime exception you throw, and immediately catch from outside of the user of that List, then sometimes you gotta do it just to move forward and tackle that problem later.

I am accessing through RMI a server that is using Hibernate. It works well. Yesterday morning I realized that I had to deal with RemoteExceptions and need to reconnect without crashing. It took me a day to retrofit all my classes.

_dnoyeBa at 2007-7-8 22:31:02 > top of Java-index,Core,Core APIs...
# 4

I have a feeling I am not explaining myself correctly :)

Yes, I fully understand that you want to catch RemoteException and recover if a client invokes server-side code using RMI. This isn't what I am refering to. I am refering to the fact that if the *server* invokes a method and the argument for that method is some Remote object exported by the client then I see absolutely no way for the server to recover from that failure because it makes no sense for the server to try locating an alternate client holding that object nor does it make sense for the server to ask for the client for a new copy of that object. I think the failure is always going to be fatal. So the server method fails which means that the client method gets a RemoteException and then that client *can* go back and try to recover by retrying the method against the same server or trying it against some other server. Any remote argument passed into a server method that throws a RemoteException would then be said to be "invalidated". That is, if you passed in a list from the client to the server and invoked a method on it and that method failed then you may not reuse that List on the client end past that point. Does that make more sense now? :)

I'm curious about your Hibernate test-case. What do you mean you reconnect without crashing? Do you mean you go back to the same server, establish a new Session and re-issue the same command? Or do you mean you somehow re-establish connection to the same Session somehow?

Thanks,

Gili

cowwoca at 2007-7-8 22:31:02 > top of Java-index,Core,Core APIs...
# 5

I just realized a problem with my design. If I try representing your use-case (client retrieve a List that is Remote from the server) then there is no way for me to cause that List to throw a checked exception. ****! :)

I could still throw an unchecked exception but as you rightly pointed out giving a List which throws unchecked exceptions to code which doesn't expect that code to throw exceptions is problematic (could cause the entire program to crash). I will give this some more thought :(

I'm still interested in how you solved this use-case though.

Gili

cowwoca at 2007-7-8 22:31:02 > top of Java-index,Core,Core APIs...
# 6

The term client and server is relative. Whoever is hosting the remove object I consider to be the server for that object. So if the client exports an object and sends it to the server, then in this case, the client is the host or "server" for that object.

So in this case the receiver of the object is the one that has to deal with the exception. However, the receiver can pass the exception back to the caller if it chooses. I don't see any reason for your "server" to fail because it could not successfully invoke a method on an object from your "client." If your client requests the server to do something, and the server could not, the server just tosses an exception back to the client. I may be missing your problem!?

For hibernate, handling hibernate failures is a bit different from handling remote failures. In either case, I let the client deal with it. My remote interfaces look like so

public interface INamedObject extends Remote {

public String getName() throws RemoteException;

public DSID getIdentifier() throws RemoteException;

public void setName(String name) throws RemoteException, ServerException;

public Set<? extends IPropertyType> getPropertyKeys() throws RemoteException, ServerException ;

public Map<? extends IPropertyType,? extends String> getProperties() throws RemoteException, ServerException ;

public String getProperty(IPropertyType key) throws RemoteException, ServerException ;

public String setProperty(IPropertyType key, String value) throws RemoteException, ServerException;

public String removeProperty(IPropertyType key) throws RemoteException, ServerException ;

}

The methods that do not require any hibernate activity generally just throw RemoteExceptions. However, the ones that do hibernate stuff also throw ServerException which is my own custom exception. Its just a serializable class. When the client gets a ServerException it knows that its not a connection problem, but a problem with the server itself. Such as the db crashed or some other thing.

Note that my objects have identifiers. So if you make a call on a remote object, and it fails, you reestablish the connection to the server, then re-request that remote object using the identifier, then try the request on it again. For distributed computing you need to be able to handle this IMHO.

_dnoyeBa at 2007-7-8 22:31:02 > top of Java-index,Core,Core APIs...
# 7

Note: do not wrap and forward the hibernate exception. Just dump a stack trace, then create your own exception and pass it along. If you wrap the hibernate exception, then the client will want to know where the definition of that exception is. Which means the hibernate jar will need to be in your codebase. Not to mention that sometimes exceptions are thrown by support classes of hibernate which will mean they also need to be in the codebase. So don't forward server exceptions...

_dnoyeBa at 2007-7-8 22:31:02 > top of Java-index,Core,Core APIs...