Likely my last question before I wrap up the assignment.
The instructions state that in the non-networked mode, the network code shouldn't be accessed at all. What I really don't like is having my interface extend remote and having all the methods throw the base IOException. If one abstracts away whether or not they are using sockets or RMI, then having the interface extend an RMI interface kind of defeats the purpose right?
So what I have done is made an interface for a "Server" class which the following methods
Underneath the implementation, hidden to the caller, is the RMI interface. There are three main classes.
1.) A dedicated RMI interface, call it RMIExecutor
2.) A dedicated Client Endpoint
3.) A dedicated Server Endpoint
Each time a caller wishes to make an object "remote" the underlying server implementation wraps that implementation in a Server Endpoint, which is a UnicastRemoteObject and implements the RMI interface (all standard RMI stuff...). It binds it to the name of the interface class type provided for later retrieval.
When a caller wishes to retrieve a particular object from the server, they do so by class type, and since it's an interface. I find the Server Endpoint under the class name. Here's the tricky part - since the retreival is based on a class type, which will be an interface, I create a java.lang.reflect.Proxy class for the interface, and use the client endpoint as the invocation handler. Then any invocation to the remote object goes to the invocation handler, which contacts the server endpoint through the RMI interface.
Theres definitely some benefits to doing it this way
1.) One central location for all remote interaction (through dedicated RMI interface)
2.) No need for an interface to extend or a class to implement any RMI interfaces.
1.) Its not exactly straight forward.
2.) Exceptions can still be lost so my interface still has to through the an IOException otherwise the Remote exceptions will fall back to my fault barrier (an uncaught exception handler for all Threads).
So Im wondering trade offs. Have my interface extend Remote and then have a dependency which would kind of make my Server interface a moot point, or have something thats somewhat complicated and explain it in my choices. I guess I just liked having the actual server implementation under the hood but it looks like most people don't care about that in terms of their projects.
Like you already indicated, people don't care, so I didn't care too The methods in my business interface have a "throws RemoteException" clause. Some people created, besides the remote interface, also a local interface without this throws clause (which I didn't).
My main idea of the assignment was to keep everything as simple as possible and I don't think it can't get any simpler than the one I described above. Keeping your code as simple as possible has many advantages (less errors, easier to maintain,...) + for this assignment an easy approach understandable to a junior programmer is preferred above a more complex, but performant one.
Although I like your points, I wouldn't follow the approach you described above. I think it is too advanced for a junior programmer, and one of the goals of this certification is to create an application that can be easily maintained by a junior programmer. And just a curiosity. the Proxy class is also used to deal with dynamic proxies.
Now, here's a suggestion of how you can design your server interface. This suggestion applies to a thin client.
Joined: Nov 06, 2008
So basically your service interface extends Remote and throws all RemoteExceptions? And because in the "nonnetworked" mode you don't use the RMI object that's OK even though your service it directly coupled to RMI?
You'll find a lot of threads where I described my approach, this is one of them.
Joined: Nov 06, 2008
Thanks again for your support!
The post states that you don't have to extend the UnicastRemoteObject because in java 5+ it generates them for you, using the static UnicastRemoteObject.exportObject(Remote) method. But then the javadoc states.
"The static method UnicastRemoteObject.exportObject(Remote) is declared to return java.rmi.server.RemoteStub and therefore cannot be used to export a remote object to use a dynamically generated stub class for its stub. An instance of a dynamically generated stub class is a java.lang.reflect.Proxy instance which is not assignable to RemoteStub. "
So how does the class get automatically generated then?
What I did as kind of a middle ground was refactor my server code to delegate the creation of the client and server endpoints. In a child class I have it doing what you guys suggested. But I was only able to do this if I created a class that extends UnicastRemoteObject and the server endpoint. This works - but I don't like that I'd have to update a separate class if my interface were to change.
Joined: Nov 06, 2008
Thats the one I'm supposed to use I think!
Joined: Nov 06, 2008
One final question.
In the approach you did - since your main GUI client only knows about the local service and not the remote service - what happens when you have a connection exception? Does it just not get caught?
I think I'll have my service through general IOExceptions which Ive seen some people done here. That way the GUI client doesnt know about the RMI remote exception but at least can pick up on service problems.
1/ I created my stub with final Remote stub = UnicastRemoteObject.exportObject(myRemoteServiceImpl, 0); and then I simply bind this stub to the registry (which is created at the given port).
2/ That's the beauty of my GUI: it's completely unaware of the mode in which it is running. So I have 1 client application which can run in 2 different modes, but the code is exactly the same. So my controller will invoke the find-method for example and will catch several exceptions (no records found, network error,...). Of course the network errors (RemoteException) will only occur when the client is running in network mode, in local mode only business exceptions will occur