• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Tim Cooke
  • Ron McLeod
  • paul wheaton
  • Jeanne Boyarsky
Sheriffs:
  • Paul Clapham
  • Devaka Cooray
Saloon Keepers:
  • Tim Holloway
  • Roland Mueller
  • Himai Minh
Bartenders:

My design...getting cloudier

 
Greenhorn
Posts: 17
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi!

I am working on the B&S assignment and I thought that I had made a clean design...until i started to change things..now I think I need to consult on what is a recommended java approach to the design.

I have a Database interface that is the interface to the database. There are 4 methods.

book
findByName
findByCity
listAll

I have a RemoteDatabase inteface that is the interface to the database using a remote client. It has exactly the same signature as Database, except for that all methods throw RemoteException.

book throws RemoteException
findByName throws RemoteException
findByCity throws RemoteException
listAll throws RemoteException

Then I have a Client interface that is the common client interface for the Controller to use (my model in mvc). Implementing classes of Client are RemoteClient and DirectClient, and client has also the exact signature as Database has. This is good, because the controller only needs to know that its working with a Client, but can be unaware of that it is a Direct or Remote client.

Now... what I earlier did is that the RemoteClient caught the RemoteExceptions and displayed an error to the customer, and did not propagegate them further, since that would break the Client interface (with expections). Then I figured... I think it is more correct to propage these errors all the way to the GUI, wrap them as ControllerExceptions in the Controller and catch and show in the GUI itself.

So... then I need the RemoteClient to actually follow the RemoteDatabase interface exactly...but the DirectClient to follow the Database (without the remoteexceptions). Now Client can no longer be an interface to these two...and I cannot use it nicely in my Controller class anymore.

Also I seem to have so many interfaces and classes that have the same setup of methods...

Client, RemoteClient, DirectClient, Database, RemoteDatabase, DatabaseImpl, RemoteDatabaseImpl.

Maybe I'm not completely off, but I feel a bit like i'm painted in a corner here.

What would be a proper java way of using the interfaces and classes?
 
Sheriff
Posts: 11606
178
Hibernate jQuery Eclipse IDE Spring MySQL Database AngularJS Tomcat Server Chrome Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Mickael,

Sounds to me your design is becoming really complex with a whole nuch of interfaces and classes.

In this thread you'll can find my approach. Maybe it could be of some inspiration.

Kind regards,
Roel
 
Mikael Månsson
Greenhorn
Posts: 17
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Roel, thanks for you blazing fast answer

I see that you are into using only one client for both. I also want to keep it that way.

You had to make both businesservices throw remoteexceptions..even the local one, and your client has to catch them, even though you will never get one from the localbusinessservice. I guess there is no way out of this, if you want to keep your client unaware of what type it is.

May I ask..did you wrap these RemoteExceptions in your client to some other expections and propagated them up to the GUI, or did you handle them in your Client?
 
Roel De Nijs
Sheriff
Posts: 11606
178
Hibernate jQuery Eclipse IDE Spring MySQL Database AngularJS Tomcat Server Chrome Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Mikael,

I guess there is no way out of this, if you want to keep your client unaware of what type it is.

That's true. And that you have to catch the RemoteException is quiet normal, because that's a consequence of not knowing which mode you are running your application in.

Some more info about how I designed my client, you'll can find here.

Kind regards,
Roel
 
Bartender
Posts: 2292
3
Eclipse IDE Spring Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Howdy, Mikael!

Champion, just like you, in my assignment, I created a thick client (which, in my opinion, complicates things a little bit). But right now, I'm writing an article to a brazilian magazine and I'm proposing this approach. It's pretty similar with the approach proposed by Roel, with small variations. For instance, with the methods you listed, here's how you could organize your business layer:



The Services interface offers the methods to be consumed by the presentation layer. These methods are to be used in the TableModel or in ActionListeners, so the class that represents the main window needs to have a constructor that expects the Services interface and pass it to the ActionListeners and to the TableModel, so the services can be consumed there. An instance of your Database interface may be created with the parameters provided in each properties window, when the application is started, according to each property provided by the user. This way, your Services classes have constructor that expect the Database interface, and the main window has a constructor that expects the Services interface. This is dependency injection, and eases the reuse of these components in frameworks that offer this feature, such as Spring.
 
Ranch Hand
Posts: 73
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi, Roberto!

Thank you for your clear example of how to make remote services.

My question is about this piece of code:



In this example your RMIRemoteServices extends DefaultServices, not UnicastRemoteObject, as it is recommended in Andrew's book.
If I understand correctly, you are using UnicastRemoteObject.exportObject() method instead of inheritance?
 
Roel De Nijs
Sheriff
Posts: 11606
178
Hibernate jQuery Eclipse IDE Spring MySQL Database AngularJS Tomcat Server Chrome Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Andriy Pererva wrote:If I understand correctly, you are using UnicastRemoteObject.exportObject() method instead of inheritance?

I'm not Roberto, but I also didn't extend from UnicastRemoteObject (I even didn't extend from anything, just an implements) and just used the exportObject-method.

Kind regards,
Roel
 
Roberto Perillo
Bartender
Posts: 2292
3
Eclipse IDE Spring Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Roel De Nijs wrote:...and just used the exportObject-method.



That's the trick, Andriy! Just so you can have an idea, the implementation of the method startServer(int) could have the following lines:



This method is called when the application starts in server mode, and binds the RMIRemoteServices object to the Registry, so it can receive requests on the port passed as parameter to the method.
 
Mikael Månsson
Greenhorn
Posts: 17
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thank you for all your help. I think I've cleaned it up just a little.
 
Greenhorn
Posts: 9
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Roberto,

Do you really think that is a good idea handle actions like start server inside the RemoteServiceImpl that should provide only business related actions like search and book contractors? I'm a little bit worried about the cohesion of that.

I created a class ServerManager that provides a method called startServer that create the registry and bind the RemoteService using a factory.

[]s
 
Roel De Nijs
Sheriff
Posts: 11606
178
Hibernate jQuery Eclipse IDE Spring MySQL Database AngularJS Tomcat Server Chrome Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Rodrigo,

I also had a seperate class for creating the registry and binding the implementation of the RemoteService. I think this is the better approach (high cohesion).

Kind regards,
Roel
 
Roberto Perillo
Bartender
Posts: 2292
3
Eclipse IDE Spring Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hum... I guess this is one point where there is no right or wrong. At the same time I think it is OK to have a separate class to start the server, for instance, I also think that it is ok to have this logic in the class that implements the business logic. So, whatever you choose, it's ok. But, to keep it simple, I would prefer to have everything in the same class, just like the design I proposed above.
 
Greenhorn
Posts: 21
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I am working on my RMI connection code similar to this:

Roberto Perillo wrote:Howdy, Mikael!




I am ultimately wanting to eliminate duplicate code for both the RMI implementation and Local implementation. From my understanding, the DefaultServices IS the local implementation of Services and each method in the DefaultServices class throws the same exceptions as in the Services methods (ServiceException and RemoteException). However, is it okay that the DefaultServices methods throw RemoteException even though for a Local-connection, the RemoteExceptions will never be used?

 
Roberto Perillo
Bartender
Posts: 2292
3
Eclipse IDE Spring Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Howdy, Kenneth! In the name of the JavaRanch family, I'd like to give you a warm welcome!

I am ultimately wanting to eliminate duplicate code for both the RMI implementation and Local implementation. From my understanding, the DefaultServices IS the local implementation of Services and each method in the DefaultServices class throws the same exceptions as in the Services methods (ServiceException and RemoteException).



Well champ, there is a little trick there. The thing is that the DefaultServices can be used either locally or remotelly, so the DefaultServices class can be either local or remote, depending on the way the application is executed. This is an efficient way to avoid duplication of code. The way I proposed also promotes abstraction, since the window that receives the Services object does not know whether the application is being executed locally or remotelly.

However, is it okay that the DefaultServices methods throw RemoteException even though for a Local-connection, the RemoteExceptions will never be used?



Well champ, when executed locally, the RemoteException will never happen. This is just for us to be able to successfully implement an interface that extends Remote. Note that if the exception is in a method's signature in an interface, it doesn't mean that the concrete method has to throw it, but that it can throw that exception.
 
Kenneth Logan
Greenhorn
Posts: 21
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thank you for the warm welcome! You're right, just because it declares that it throws an exception, does not mean that it necessarily "has" to. And the DefaultServices is being used directly when in local mode (that is the concrete class) and then indirectly using the RMI-connection (because RemoteServices just inherits all of DefaultServices' methods). So this makes sense and I totally like this design.

Now, are there any tests that I can use to verify that my RMI connection works? I ran my server on my laptop, and the client on a desktop machine and did a few tests.
Test 1: Connect client to server using valid IP and valid Port number - seems as if it works fine (Client Window appears and JTable is populated).
Test 2: Connect client to server using invalid IP address, but valid Port number - "Failed to connect to the database" appears as expected.
Test 3: Connect client to server using vaild IP but invalid port number. - Client Window does NOT appear and the program is still running. Not what I expected-- I was expecting a "Failed to connect" message as in test case #2.

 
Roberto Perillo
Bartender
Posts: 2292
3
Eclipse IDE Spring Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Howdy, Kenneth!

Now, are there any tests that I can use to verify that my RMI connection works? I ran my server on my laptop, and the client on a desktop machine and did a few tests.
Test 1: Connect client to server using valid IP and valid Port number - seems as if it works fine (Client Window appears and JTable is populated).
Test 2: Connect client to server using invalid IP address, but valid Port number - "Failed to connect to the database" appears as expected.
Test 3: Connect client to server using vaild IP but invalid port number. - Client Window does NOT appear and the program is still running. Not what I expected-- I was expecting a "Failed to connect" message as in test case #2.



Well champ, the good thing is that if a client that is in the same LAN is able to connect to your server, then that's pretty much it. But how did you run these tests? How did you connect to your server with an invalid IP address? I think that you could do just one simple test that, if it passes, then everything is fine. It follows the design proposed a few posts above:



The essence of this test is to verify only if the server is started and if you are able to get it from the registry. If it passes, then I'd say that it is pretty much it (regarding server connection). Eventually, if you have some code in your server that stops it, then you can include the code that stops it in an @After method.
 
Kenneth Logan
Greenhorn
Posts: 21
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Roberto Perillo wrote:Howdy, Kenneth!

How did you connect to your server with an invalid IP address?



Er, I was NOT able to connect with an INVALID IP address (this is my intended behavior). I just wanted to make sure entering an invalid ip address would pop up a message to the user saying something along the lines of it "failing the connection."

Thanks for the test case! I will try this soon!
 
Ranch Hand
Posts: 74
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Roberto Perillo wrote:



Hum, I've a different implementation of the RMIRemoteServices. Indeed, here you extend DefaultServices, which then requires its content to be serializable. It's quite a pity though because it's not strictly required so: indeed, from what I understood from RMI, the stub will be created through a proxy and only the proxy will be given away. This proxy then delegates, after transport, to the actual instance.

As such, in the proxy, carrying a proper Database object and all its content is a bit too much IMHO (requires Database to be serializable and potentially carries around way too much).

What about such an implementation:


As such, the Database isn't required to be Serializable and won't be transported around when a proxy is made. Sounds all good isn't it ? Maybe I'm missing something, but up to now I don't see that.

Side note: on my side I made this RMIRemoteServices extending UnicastRemoteObject, since one instance can be used through all clients. And on top of that I've no factory or the like: just the instance is put in the RMI registry, the clients directly go at it.

Roberto Perillo wrote:
The Services interface offers the methods to be consumed by the presentation layer. These methods are to be used in the TableModel or in ActionListeners



Isn't it rather the controller which should use them ?

EDIT: side question: what do you do if/when the configuration isn't proper. Error message and then stop or something cleverer with a new edit dialog being displayed as long as config wasn't good?
 
Roel De Nijs
Sheriff
Posts: 11606
178
Hibernate jQuery Eclipse IDE Spring MySQL Database AngularJS Tomcat Server Chrome Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
My remote service implementation also has a reference to the Data class. This reference is not marked transient, nor does my Data class implement the Serializable interface. Simply because RMI works with stubs and skeletons, so not with the actual classes, the MyRemoteServiceImpl instance is not transported to the client.

When I take a look at the source code of the stub generated by rmic, I see a class which implements my remote service interface (2 methods implemented), but no reference at all of the Data class. Each method in this stub has a lot of hard-to-read code (we are fortunate that we don't have to write this code ourselves). Just do the same like me and generate the stub and skeleton classes (and keep the sources, use "-keep" option of rmic) and convince yourself

Norbert Lebenthal wrote:Isn't it rather the controller which should use them ?


Of course! Your controller will invoke the methods on your Services instance. The presentation layer will have a reference to the controller.
 
Roberto Perillo
Bartender
Posts: 2292
3
Eclipse IDE Spring Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Norbert Lebenthal wrote:Hum, I've a different implementation of the RMIRemoteServices. Indeed, here you extend DefaultServices, which then requires its content to be serializable. It's quite a pity though because it's not strictly required so: indeed, from what I understood from RMI, the stub will be created through a proxy and only the proxy will be given away. This proxy then delegates, after transport, to the actual instance.



Champion, only the objects that are transferred over the network have to be serializable. For the approach I proposed above, the Data class does not have to be Serializable, since it won't be transffered over the network. In this case, only the objects that are parameters or return types of the methods of your remote interface have to be Serializable. You don't have to mark the Data object in your Services class to be transient.

Norbert Lebenthal wrote:Side note: on my side I made this RMIRemoteServices extending UnicastRemoteObject, since one instance can be used through all clients. And on top of that I've no factory or the like: just the instance is put in the RMI registry, the clients directly go at it.



Well, it would also work this way if you didn't extend UnicastRemoteObject and did something like this.

Norbert Lebenthal wrote:Isn't it rather the controller which should use them ?


Well, today I'd say that a more appropriate approach would be to provide to the TableModel only the data that is displayed on the JTable, and not provide the Services object to it, just like I've shown in this other thread (which was started by you). Other than that, an ActionListener is a Controller. So, it can have a reference to the Services object. For instance, the listener of the Book Room button can have a reference to the Services object and, after verifying the data provided by the user, invoke the bookRoom method from the Services object.

Norbert Lebenthal wrote:EDIT: side question: what do you do if/when the configuration isn't proper. Error message and then stop or something cleverer with a new edit dialog being displayed as long as config wasn't good?



Well, you can just show a message saying what is wrong about the configuration and keep the dialog open for the user to provide the configuration data again...
 
Norbert Lebenthal
Ranch Hand
Posts: 74
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I hope I wasn't appearing presumptuous :$

Back to the topic. In fact on the way to "explore" RMI I had exception due to my Service class not being serializable. Thanks to your post I've realized that it wasn't needed anymore.

I hadn't seen this bit:


thanks for the tip. However, I feel it a bit magic, esp. if the class remoted is called RemoteService (since I would look into it to figure out its usage). But that's quite personal I guess.


Well, today I'd say that a more appropriate approach would be to provide to the TableModel only the data that is displayed on the JTable, and not provide the Services object to it, just like I've shown in this other thread (which was started by you). Other than that, an ActionListener is a Controller. So, it can have a reference to the Services object. For instance, the listener of the Book Room button can have a reference to the Services object and, after verifying the data provided by the user, invoke the bookRoom method from the Services object.



Well, I wasn't aware that one could consider an ActionListener a Controller. Up to reading you I was under the impression that the controller should be a well defined class lol (which Roel looks like agreeing). Anyway, no big deal, thanks again for your interaction.

best
norbert
 
Consider Paul's rocket mass heater.
reply
    Bookmark Topic Watch Topic
  • New Topic