• 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
  • Liutauras Vilda
  • Jeanne Boyarsky
  • paul wheaton
Sheriffs:
  • Ron McLeod
  • Devaka Cooray
  • Henry Wong
Saloon Keepers:
  • Tim Holloway
  • Stephan van Hulst
  • Carey Brown
  • Tim Moores
  • Mikalai Zaikin
Bartenders:
  • Frits Walraven

URLyBird 1.1.3 design questions

 
Ranch Hand
Posts: 36
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi all,

I've been reading many threads past and present, specifically around 2-tier vs 3-tier and locking. I have a design which I feel is justifiable and would like some feedback from you all.

I am using RMI and have decided not to expose the methods in the DB interface to the client, but to have an intermediate interface, ClientInterface, with find() and book() methods defined. My reasons for this are as follows:

1) The Data class that implements DB is a generic class solely responsible for data access. It is driven by the schema description section but knows nothing about the data in the database. This means that the file can be changed to alter the number of fields and their names without the class requiring alteration. The ClientInterface then exposes business transactions to the client, and will minimise the client server interaction. For example searching requires a single call to the server, rather than a call to find() followed by multiple calls to read() (one for each index returned).
2) The DB interface does not extend Remote and none of the methods throw RemoteException. You would therefore need to create another interface with similar methods to expose it via RMI (since changing the DB interface would probably result in a failure), with an wrapper to convert between the new interface and DB. My design allows for a single interface to be used in the client, regardless of whether the client is running alone or connecting to the server.
3) I debated the issues of locking, including deadlocking and orphaned locks. It appears from reading this forum that the locking mechanism does not HAVE to take these situations into account. My design further justifies this, since when running in networked mode a call to book() will perform:
lock()
read()
update()
unlock()
in a single transaction on the client. Having the unlock() call in a finally block will ensure locks are not left in place if a client disconnects - even if the disconnect happens before the server is finished the book() call. Not exposing lock() and unlock() to the client also removes the possibility of deadlocks since a client can only have a single lock at a time. This makes the locking code much simpler since there is no need for the Unreferenced or WeakHashMap approach for detecting locks whose clients have died, nor is there any need for deadlock detection.

I have read many threads on these subjects, including the "Should lock methods be callable by the client" thread. It seems to me that providing you are not breaking any of the "must" rules and you can fully justify your choices in your choices.txt document this sort of approach should be fine. However I would appreciate any feedback, particularly on any holes in my
argument or from people who have passed with similar approaches.

Thanks in advance for any feedback.
 
Ranch Hand
Posts: 113
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Ok I haven’t passed yet but here is my two cents and also a question.

Originally posted by Jonathan Moore:

I am using RMI and have decided not to expose the methods in the DB interface to the client, but to have an intermediate interface, ClientInterface, with find() and book() methods defined. My reasons for this are as follows:



I have done something similar with book() and find() methods in my Controller class. Makes sense to me and nothing I have seen in this forum would suggest otherwise


Originally posted by Jonathan Moore:

2) The DB interface does not extend Remote and none of the methods throw RemoteException. You would therefore need to create another interface with similar methods to expose it via RMI (since changing the DB interface would probably result in a failure), with an wrapper to convert between the new interface and DB. My design allows for a single interface to be used in the client, regardless of whether the client is running alone or connecting to the server.



You say that your design allows for a single interface to be used in the client.
Does this mean then that the interface through which you access the DB is the same in both local and networked mode ?
If so then the methods in this interface would throw RemoteExceptions.
And so might belong in your remote package.
Therefore you are accessing your DB using a class in your remote package even in local mode ?

The following thread is dealing with this issue and I would be interested to hear your answers to the questions above:

https://coderanch.com/t/187619/java-developer-SCJD/certification/Design
 
Jonathan Moore
Ranch Hand
Posts: 36
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thanks for the reply Alan - you've raised a good point. I've been working from Alain Trottier's Exam Cram examples, and was planning on having a single interface used by the client in both local and networked mode, and was going to use the Remote extension for this. As you point out though, this would mean having code to catch RemoteExceptions in local mode, which is not a good design. I'm not sure that the Exam Cram book is up to much...

I think I was on the right lines but had oversimplified my design - the class structure in the link you sent makes more sense.

Another question - my only reference to my Data class is in the ServiceImpl class (RemoteServiceImpl is an adapter for ServiceImpl). The book() method does the following:
lock
find record
check validity
update
unlock
This means that locking and unlocking is done even when running in local mode. I've thought of a couple of ways round this, but feel it overcomplicates things, and the overhead of locking and unlocking is very small. I think this is justifiable, since the instructions state that a clear design will be prefered to a more complex one, even if the complex one is a little more efficient. Does this seem reasonable?

Cheers
Jon
 
Alan Morgan
Ranch Hand
Posts: 113
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Thanks for the reply Alan - you've raised a good point. I've been working from Alain Trottier's Exam Cram examples, and was planning on having a single interface used by the client in both local and networked mode, and was going to use the Remote extension for this. As you point out though, this would mean having code to catch RemoteExceptions in local mode, which is not a good design. I'm not sure that the Exam Cram book is up to much...

I think I was on the right lines but had oversimplified my design - the class structure in the link you sent makes more sense.



Jon � which class structure exactly are you talking about ?
As you can see from my last post in that thread I haven�t quite gotten my head around how to avoid the problems outlined above.





Another question - my only reference to my Data class is in the ServiceImpl class (RemoteServiceImpl is an adapter for ServiceImpl). The book() method does the following:
lock
find record
check validity
update
unlock
This means that locking and unlocking is done even when running in local mode. I've thought of a couple of ways round this, but feel it overcomplicates things, and the overhead of locking and unlocking is very small. I think this is justifiable, since the instructions state that a clear design will be prefered to a more complex one, even if the complex one is a little more efficient. Does this seem reasonable?



Firstly less complex is the way to go I reckon � in other words locking even in local mode sounds ok.

Then I was thinking is there a way that even in local mode you need locking.
What about if you were running a server on the machine as well pointing to the same DB ? (might be stretching here )
 
Jonathan Moore
Ranch Hand
Posts: 36
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
The way I've got it now is:

- interface Service, defines find() and book() methods
- class ServiceImpl, implements Service
- interface RemoteService, extends Remote and has same methods as Service but with RemoteExceptions thrown
- class RemoteServiceImpl, extends UnicastRemoteObject, implements RemoteService. This is an adapter for a ServiceImpl object
class RemoteServiceWrapper, implements Service. This wraps a RemoteServiceImpl object (retrieved by Naming.lookup) and strips out RemoteExceptions. I figure a RemoteException is probably fatal so can be converted to another exception, possibly a subclass of Error or RuntimeException since these are unchecked.

e.g.


This way the client either uses a RemoteServiceWrapper (in networked mode) or a ServiceImpl (in local mode), both of which implement Service.

Regarding locking, I agree less complex is better. However you can ignore the possibility of a local and a networked app accessing the db at the same time - my instructions say "You may assume that at any moment, at most one program is accessing the database file".

Thanks for your responses - hope my reply helps you.

cheers
Jon
 
Alan Morgan
Ranch Hand
Posts: 113
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Jon,

Your reply certainly has helped.


Just to be clear that I understand...

In your DataConnector (class where you call getLocal/getRemote)
both getLocal and getRemote return Service.

In the case of getLocal you return a ServiceImpl

In the case of getRemote your Naming.lookup returns a RemoteServiceImpl.
You then create a RemoteServiceWrapper passing this in.
A call to book() on RemoteServiceWrapper passes call to RemoteServiceImpl and if any RemoteExceptions are caught then we throw a ServicesException (or equivalent)

Am I close ?


My case is a little different in that my "Service" layer is on the client so I would have to have RemoteData have methods like create(), delete, update() etc.
But I reckon the principle still holds.
I wrap a RemoteDataImpl and strip any RemoteExceptions.


It's gonna take some rework on my part but I guess it is better than having a RemoteException in the interface I will be dealing with even in local mode.

Thanks for your responses, they are really helping me to think things through.

cheers,
Alan.
[ November 10, 2005: Message edited by: Alan Morgan ]
 
Jonathan Moore
Ranch Hand
Posts: 36
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Alan,

Yes your description matches the class structure I have - just hope it's acceptable to the examiner!

Good luck

Jon
 
Poop goes in a willow feeder. Wipe with this tiny ad:
Gift giving made easy with the permaculture playing cards
https://coderanch.com/t/777758/Gift-giving-easy-permaculture-playing
reply
    Bookmark Topic Watch Topic
  • New Topic