This week's giveaway is in the EJB and other Java EE Technologies forum.
We're giving away four copies of EJB 3 in Action and have Debu Panda, Reza Rahman, Ryan Cuprak, and Michael Remijan on-line!
See this thread for details.
The moose likes Developer Certification (SCJD/OCMJD) and the fly likes Networking : RMI Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of EJB 3 in Action this week in the EJB and other Java EE Technologies forum!
JavaRanch » Java Forums » Certification » Developer Certification (SCJD/OCMJD)
Bookmark "Networking : RMI" Watch "Networking : RMI" New topic
Author

Networking : RMI

Nandini Sriram
Ranch Hand

Joined: Jul 04, 2003
Posts: 132
Hello,
I have decided to use RMI, and I have a few questions about my implementation.
1. Define an interface, DataServices that has all the public methods of the Data class.
2. DataImpl extends Data implements DataServices - lock(), unlock(), criteriaFind() defined in this subclass.
Qn: Do I have to cut and paste the code from Data.java to DataImpl?
3. Define another interface, FBNS that has methods getFlightInfo()and bookFlight().
4. Make 2 classes implement this FBNS, one for local (FBNS_Local)and another for remote(FBNS_Remote) access (throwing RemoteException).
Based on the choice (local or remote), I plan to divert it to the appropriate class for handling.
Qn: I need to introduce a reference to the DataImpl object in these 2 classes. So does it make my Data class useless? I mean, then I am not really using that class at all.
Another thought..
1. I do not need lock() and unlock() in my remote access, so I modify the Data class to implement DataServices and define the criteriaFind() alone here (can be used for local access).
2. Create another class (server-side) extending UnicastRemoteObject. Can I have a Data object inside this class and pass the method calls to the Data class? But then I am stuck up with
lock() and unlock() here. Where are they to be taken care of?
Please give your suggestions.
Thanks
Nandini


Discipline, Dedication and Determination define Destiny.
Andrew Monkhouse
author and jackaroo
Marshal Commander

Joined: Mar 28, 2003
Posts: 11278
    
  59

Hi Nandini,
Qn: Do I have to cut and paste the code from Data.java to DataImpl?

No - you said that DataImpl extends Data. Therefore it inherits all the methods from Data - you do not need to copy code.
Qn: I need to introduce a reference to the DataImpl object in these 2 classes. So does it make my Data class useless? I mean, then I am not really using that class at all.

See my earlier comment: since DataImpl is extending Data, you do not have to copy code from Data into DataImpl. In this case, the methods of Data are being used.
1. I do not need lock() and unlock() in my remote access

Check for the instruction: The remote client code that you write must provide all the public methods of the suncertify.db.Data class.. If you have this, then you are going to need to provide RMI implementations of lock() and unlock().
so I modify the Data class to implement DataServices

My gut feeling is that modifying Data class in this manner is wrong. But I accept that this is open to interpretation. My interpretation is based on the instruction: "Three classes are in this package: Data, DataInfo, and FieldInfo. With the exception of (the criteriaFind(String), lock(int) and unlock(int)) methods, noted below, these classes are complete". That complete to me implies that we should not make any changes that are not directly needed to implement the three named methods.
Create another class (server-side) extending UnicastRemoteObject. Can I have a Data object inside this class and pass the method calls to the Data class?

Yes, this is what I did.
But then I am stuck up with lock() and unlock() here. Where are they to be taken care of?

See my earlier comment about the requirements: you need to be able to call lock and unlock from the client side. Whether you do or not is up to you, but the ability has to be there. Personally I do not see the point in writing code that allows you to call lock and unlock remotely and then additionally writing code that bypasses it. I cannot see any reason why your bookFlight() method could not be a method within the client code.
Regards, Andrew


The Sun Certified Java Developer Exam with J2SE 5: paper version from Amazon, PDF from Apress, Online reference: Books 24x7 Personal blog
Nandini Sriram
Ranch Hand

Joined: Jul 04, 2003
Posts: 132
Hai Andrew,
Thank you very much for your reply.
1.I made a mistake - I intended to say "lock() and unlock() are not needed in local access" (am I right?).
2. When I make DataImpl extend Data, its private methods are not inherited (for example, readRecord()). And so I need to re-define all those methods and some variables in my subclass also??
Let me say..
1. Define FBNS (interface)with getFlightInfo() and book().
2. class MyData extends UnicastRemoteObject (have a Data object inside for reference; define lock() and unlock()ALONE here).
3. Define FBNS_local and FBNS_remote, both implementing FBNS (the latter alone throwing RemoteException)
4. Have a call to Data object inside the FBNS_local and call to myData object inside FBNS_remote.Is this what u meant by additional coding.??
Qn. So I can have the book() inside my client class and allow it to make a call to MyData class (that in turn has the Data object) and reach the database?
Qn. Please point out the flaws in this design. Can I call it Remote Access just by making it throw RemoteException or do I need to make it implement a remote interface?
Thanks
Nandini
[ July 20, 2003: Message edited by: Nandini Sriram ]
[ July 20, 2003: Message edited by: Nandini Sriram ]
Andrew Monkhouse
author and jackaroo
Marshal Commander

Joined: Mar 28, 2003
Posts: 11278
    
  59

Hi Nandini
"lock() and unlock() are not needed in local access"

True. Your decision then has to be whether you have different code being called for local compared to remote access. Personally I chose to have the client code call the same methods (so: lock, verify, modify, unlock) regardless of whether it was in local or remote mode: less chance of a bug slipping through that only appears in one mode.
When I make DataImpl extend Data, its private methods are not inherited (for example, readRecord()). And so I need to re-define all those methods and some variables in my subclass also??

There may be a reason for doing this, but so far you have not mentioned any. I am not sure if there is something that you want to do that I am missing, or if you are missing part of the picture regarding how extending a class works.
In case it is the latter, here is some code that we can use in our discussions. (In case this is all obvious to you, then I appologise).
First a class with some private variables and methods:
Now a class that extends ClassOne, but does not use any of the code from ClassOne:
Try that code - you will see that it works, even though I have not copied anything from ClassOne into ClassTwo. Then if you are confused about how part of it works, ask a question relating to this code.
Let me say..
1. Define FBNS (interface)with getFlightInfo() and book().
2. class MyData extends UnicastRemoteObject (have a Data object inside for reference; define lock() and unlock()ALONE here).
3. Define FBNS_local and FBNS_remote, both implementing FBNS (the latter alone throwing RemoteException)
4. Have a call to Data object inside the FBNS_local and call to myData object inside FBNS_remote.Is this what u meant by additional coding.??
Qn. So I can have the book() inside my client class and allow it to make a call to MyData class (that in turn has the Data object) and reach the database?

OK. This looks good. (I'll come back to the lock() and unlock() later)
My comment about additional coding was because I was unclear about your design. So you can ignore it (and the rest of this paragraph if you like). I thought you were suggesting that FBNS_remote was the class extending UnicastRemoteObject, so your client was only calling a remote method "bookFlight()" that did the "lock(), verify(), modify(), and unlock()" all on the server. There are a lot of people doing this for the new assignments because they can. But for FBNS I think it results in additional coding, because you have to write RMI methods for lock(), modify(), unlock() .... and bookFlight().
Now back to the concept of having lock() and unlock() only in the class MyData. While I think this would work, I don't think it meets the requirement where Sun told us to implement lock() and unlock() in Data class or in a class that extends Data class.
Can I call it Remote Access just by making it throw RemoteException or do I need to make it implement a remote interface?

You will need to implement an interface.
When your client code looks up your remote code, it does not get an instance of MyData. What it gets is an instance of the stub that was generated. So you cannot code your client as though it is getting a copy of MyData - you have to code to some interface that both MyData implements and the stub implements: and this will be the interface that you have created.
Regards, Andrew
Andrew Monkhouse
author and jackaroo
Marshal Commander

Joined: Mar 28, 2003
Posts: 11278
    
  59

Hi Nandini
One more thing, you still have to ensure that a connection can not unlock any record that it did not lock. It is not obvious in your descriptions of code whether you are handling this or not. I suspect that you are not yet at the stage where you are considering this. I think we can safely leave that discussion until after you are happy with what has been discussed above.
Regards, Andrew
Nandini Sriram
Ranch Hand

Joined: Jul 04, 2003
Posts: 132
Andrew, thanks a lot for coming forward to make me understand. Actually, I thought of defining the criteriaFind() in a subclass of Data. I had to call the readRecord() method like, String[] s = readRecord())and some private variables directly inside my method. And I got those compilation errors saying they all had private access. And that's why that question!!! I am clear about the code examples u gave, and thanks again.
Qn. If lock() and unlock() are not needed for local access, do they also have to be by-passed entirely during local access???
1. interface FBNS with getFlightInfo() and book()
2. interface FBNS_RemoteIF extends Remote AND
FBNS :same methods but throwing RemoteExcpn.
3. class MyData extends UnicastRemoteObject implements FBNS_RemoteIF {
have a reference to data object inside;
define the getFlight()and book()[with lock() and unlock()];
}
4. class Flight_Svr_Remote{
reference to MyData object inside;
Binding to Registry;
}
5. class Flight_Svr_Local implements FBNS {
have a reference to Data object inside;
getFlight () and book() again defined without considering the lock() and unlock();
}
6. On the client side, if it is a local access, then - new Flight_Svr_Local() handles it, and if remote access, then
set a SecurityManager,
Flight_Svr_Remote fsr = (Flight_Svr_Remote)Naming.lookup(name)and access the methods defined in the MyData class, remotely.
Qn. Again here I have defined the lock, unlock in MyData. Can I define them in Data and not call them in book() definition inside Flight_Svr_Local class?
Here are my lock() and unlock(). Please comment on them too.

Can I use HashMap/WeakHashMap instead of vectors?
These lock() and unlock() would have to be called inside the book() method, right? In my design(if it's ok), it is in MyData class.
For eg: book() {
lock();
... do the steps for booking
unlock();
}
What should be listed in the booking method? I assume it is just asking for the passenger details and updating the seats.
Thank you
Nandini
[ July 21, 2003: Message edited by: Nandini Sriram ]
[ July 21, 2003: Message edited by: Nandini Sriram ]
Andrew Monkhouse
author and jackaroo
Marshal Commander

Joined: Mar 28, 2003
Posts: 11278
    
  59

Hi Nandini
Actually, I thought of defining the criteriaFind() in a subclass of Data. I had to call the readRecord() method like, String[] s = readRecord())and some private variables directly inside my method.

Yes, that is the biggest problem with implementing criteriaFind in a subclass of Data. But you should be able to use the heavier getRecord(int) to retrieve the records from your subclass. If you had not been provided with the source code to Data, then this is what you would have to do anyway. If you really want to use the private methods and variables within the Data class, then I recommend you implement criteriaFind inside Data class.
If lock() and unlock() are not needed for local access, do they also have to be by-passed entirely during local access???

They don't have to be bypassed. Personally I still used them in local mode - the fact that they were redundant did not bother me: I just preferred to have my local and remote code as common as possible.
1. interface FBNS with getFlightInfo() and book()
2. interface FBNS_RemoteIF extends Remote AND FBNS :same methods but throwing RemoteExcpn.
3. class MyData extends UnicastRemoteObject implements FBNS_RemoteIF

OK - so you are having booking methods running on the server, rather than calling lock(), modify() and unlock() directly from the client code.
This is being discussed in this thread. Please take a look at Svetlana's comments, and my response there, and add your own thoughts if you like.
I have defined the lock, unlock in MyData. Can I define them in Data and not call them in book() definition inside Flight_Svr_Local class?

Yes, you can do this.
Here are my lock() and unlock(). Please comment on them too.
...
Can I use HashMap/WeakHashMap instead of vectors?

Yes you can. In fact I was going to ask you why you were using Vectors.
I am not going to make any comments on your code, because this code will not compile. Therefore I assume this is psuedocode.
You have not yet put any logic in for having the entire database locked.
What should be listed in the booking method? I assume it is just asking for the passenger details and updating the seats.

Normally the booking method would be called after all the necessary details have been obtained from the client. So it should not ask for anything. It should be given whatever information is necessary to perform the booking.
Note that you do not need to get passenger details for this assignment. Even if you did get them, you have nowhere to store them.
In the booking method, you would normally lock the record, verify that the number of seats requested can be granted, modify the record, and release the lock. And of course, you need to handle the case where that check fails.
Regards, Andrew
Nandini Sriram
Ranch Hand

Joined: Jul 04, 2003
Posts: 132
Hai Andrew,
Thanks again.
That was a rudimentary code that I tried to implement for lock and unlock. Now after reading a few postings, I am thinking about clientID.
Andrew, I am not able to understand the importance of this unique ID(though I see how people have got one).
Let's say, booking "cycle"involves .. lock, read, modify, write and unlock (client first acquires a lock, reads the record, modifies and writes it to the database and then unlocks, right?)
What happens in the following scenario?
Client A locks RecordONE
Client B locks RecordTWO
Can Client A lock RecordTWO and Client B lock RecordONE NOW?
Qn. Can 'A' break out of the booking cycle in the middle, before unlocking RecordONE (other than crashing)??? In this case, that record remains locked. So, even 'A' will not be able to access RecordONE again.
Qn. Please give me some examples of deadlock.
Qn. (From the other posting).. implementing the Unreferenced will unlock all the records that a particular client locked(after the client disconnects).. and for this I need the ID..am I right in understanding this?
Qn. What is "write-only" lock? Does this mean the multiple clients can read a record simultaneously but cannot modify simulataneously? (lock..read..modify..unlock)
Qn. Once a locked record has been unlocked, the waiting client gets to lock. But what happens when there are more than one client waiting? Do we have to assign priority and then implement this concept?
Thanks
Nandini
[ July 22, 2003: Message edited by: Nandini Sriram ]
Andrew Monkhouse
author and jackaroo
Marshal Commander

Joined: Mar 28, 2003
Posts: 11278
    
  59

Hi Nandini
Andrew, I am not able to understand the importance of this unique ID(though I see how people have got one).

FBNS has the requirement: "If an attempt is made to unlock a record that has not been locked by this connection, then no action is be taken."
Since you have to provide the ability for a client to call the lock() and unlock() methods remotely, you have to have some way of tracking who owns the locks. Hence the unique ID.
Does that explain their importance?
What happens in the following scenario?
Client A locks RecordONE
Client B locks RecordTWO
Can Client A lock RecordTWO and Client B lock RecordONE NOW?

Client A can attempt to lock RecordTWO - in this case it will block until Client B releases the lock.
Client B can attempt to lock RecordOne - in this case it will block until Client A releases the lock.
Now we have a problem: A is blocked waiting for B, and B is blocked waiting for A: DEADLOCK!

Qn. Can 'A' break out of the booking cycle in the middle, before unlocking RecordONE (other than crashing)???

Not in the scenario above. Or are you talking about a different scenario?
In the scenario above, both clients will be blocked. The instructions state that the lock method will block until the lock is granted.
In this case, that record remains locked. So, even 'A' will not be able to access RecordONE again.

To get around this you would need some sort of dead client lock recovery mechanism.
Since you are using RMI, then if you are also using the ConnectionFactory described here many times, then you can also use one of the following:
  • Unreferenced
  • WeakHashMap


  • Either of these will give you a way of clearing locks that are owned by a client that is no longer connected.
    Both have their good points and their bad points. You will find many posts here discussing them.
    Qn. Please give me some examples of deadlock.

    Client A locks RecordONE
    Client B locks RecordTWO
    Client A attempts to lock RecordTWO
    Client B attempts to lock RecordONE

    This can actually get far more complex. For example: A is waiting for a lock owned by B who is waiting for a lock owned by C who is waiting for a lock owned by A. But the basic concept is still the same: you have clients that are blocking each other and neither of them will ever recover on their own.
    There are multiple ways to handle this being discussed at present:
  • Ignore the issue (my clients only ever lock/modify/unlock one record at any given time, so they will not get into this scenario where they are trying to get a second lock that will not be released because of the first lock they own).
  • Require the clients to request locks in numerical order.
  • Write a dedicated deadlock detection program.


  • For FBNS I think the first option may be the best. The instructions tell us that the attempt to lock must block until the lock is granted. So any deadlock detection cannot help us. You could document the second option as a way of avoiding deadlock, but again you cannot enforce it: what are you going to do if you detect that someone is not complying?
    Qn. (From the other posting).. implementing the Unreferenced will unlock all the records that a particular client locked(after the client disconnects).. and for this I need the ID..am I right in understanding this?

    Yes.
    Qn. What is "write-only" lock? Does this mean the multiple clients can read a record simultaneously but cannot modify simulataneously? (lock..read..modify..unlock)

    Many databases have what is termed a "read lock". That is, I can do two different sorts of reads: read a record with no locking - in which case it may be modified without my being aware of it, or a read with lock - in which case no one can modify the record as long as I hold the read lock. The advantage to this is that multiple clients can have a read lock, and as long as one of them still owns a read lock, the data cannot change. Typically you might use this when generating a report from several records and/or tables: you need the data to stay static while in the middle of the report. I can explain this further if you like.
    The comment by Sun that 'the locking required is effectively a "write" lock only' is telling you that you do not need to go into the complexity of handling the situation I just described for read locks.
    You only need to handle the case where one person (and only one person) can get a lock on an individual record for the purpose of doing a write.
    Once a locked record has been unlocked, the waiting client gets to lock. But what happens when there are more than one client waiting? Do we have to assign priority and then implement this concept?

    I dont think that you have to worry about priorities of waiting clients, although I know some candidates have.
    The lock/verify/modify/unlock sequence should not require any user interaction. Therefore it should be very fast. Even if multiple clients all attempt to modify the same record simultaneously, the waiting period should be small enough that we should not have to worry about granting locks in the order the requests were received.
    Regards, Andrew
    Nandini Sriram
    Ranch Hand

    Joined: Jul 04, 2003
    Posts: 132
    Hi Andrew,
    I'm now quite clear about locking. Thanks. Will work on it. Before that, I have some questions about the "Data Client". In the assignment , it is given, there has to be a class that implements the same public methods as in Data class on the client-side.
    Please take a look at this:
    I define criteriaFind, lock(), unlock() inside the Data class.
    1. interface FBNS with getFlightInfo() and book()
    2. interface FBNS_RemoteIF extends Remote AND
    FBNS :same methods but throwing RemoteExcpn.
    3. class RemoteData extends UnicastRemoteObject implements FBNS_RemoteIF {
    has a reference to data object inside; (do I need to make it private)
    define the getFlight()and book ()and call lock() and unlock()appropriately.
    }
    4. class Svr_Remote{
    reference to RemoteData object inside;
    Binding to Registry;
    }
    5. class Svr_Local implements FBNS {
    has a reference to Data object inside;
    getFlight () and book() again defined without considering the lock() and unlock();
    }
    6. On the client side, if it is a local access, then : new Svr_Local() handles it, and if remote access, then
    set a SecurityManager,
    FBNS_RemoteIF fsr = (FBNS_RemoteIF)Naming.lookup(name)and access the methods defined in the RemoteData class, remotely.
    In 3 and 5, the interface methods, getFlight() and book() are going to be defined using the methods of the Data class.
    So, should the client also have an implementation of the Data class methods?
    If that is so, then should DataInfo and FieldInfo also be accessible to the client program directly (because Data class makes use of these 2 classes).
    One more regarding the connection factory, I think ConnectionFactory and Unreferenced should be implemented by my RemoteData class, am I right?
    Thanks
    Nandini
    Andrew Monkhouse
    author and jackaroo
    Marshal Commander

    Joined: Mar 28, 2003
    Posts: 11278
        
      59

    Hi Nandini
    class RemoteData extends UnicastRemoteObject implements FBNS_RemoteIF {
    has a reference to data object inside; (do I need to make it private)

    The same rules apply with this instance or class variable as with any other: who needs access to it?
  • Should all other classes that can access this class have access to it's instance of Data?
  • Should classes in the same package have access to this instance of Data?
  • Should classes overriding RemoteData have access to it's instance of Data?
  • None of the above?

  • Once you have determined the answer to this question, then you will have worked out what access modifier to use (if any).
    A word of warning: don't get confused by the fact that this class is a Remote class. You still have to explicitly declare what methods are available through RMI. So no matter what access modifier you use, the instance of Data will not be accessible to a remote client.
    In 3 and 5, the interface methods, getFlight() and book() are going to be defined using the methods of the Data class.
    So, should the client also have an implementation of the Data class methods?

    The requirement is: "The remote client code that you write must provide all the public methods of the suncertify.db.Data class."
    (Slightly different from your way of writting it, but I am very pedantic at times )
    So you must export the lock(), modify(), create() ... in a Remote class. You cannot work around this by only having a remote bookFlights() method. However you may have a remote bookFlights() method in addition to all the public methods of the Data class.
    Personally I don't think this is a good idea. Please take a look at this thread. Particularly my comments "posted July 21, 2003 08:52 PM" starting with "There is nothing in the assignment that stops you" (that should give you two search phrases). There you will find why I believe (given that we have to implement the public methods of Data side) that the bookFlights() method should be implemented client side.
    If that is so, then should DataInfo and FieldInfo also be accessible to the client program directly

    Yes, I believe they have to be.
    One more regarding the connection factory, I think ConnectionFactory and Unreferenced should be implemented by my RemoteData class, am I right?

    Well your ConnectionFactory would create instances of your RemoteData class.
    But you are right on the second issue: your RemoteData class is the logical class to implement Unreferenced.
    Regards, Andrew
    Nandini Sriram
    Ranch Hand

    Joined: Jul 04, 2003
    Posts: 132
    Hai Andrew,
    I understand when u say implementing the getFlight() on the client-side is better. Thanks. That's exactly what I have done now. But since mine is now a "local access", I thougth I had to implement it on my server when I incorporate the networking principles.
    Let me tell you about my client-side as it is now:
    I have a "placeholder" class that contains the following:
    1. Remote interface (that should provide all the public methods of the Data class and this must be implemented by my server also, right?)
    2. Client class (has all the GUI)

    3. Now my Main class has different sections, of these the one we are concerned with, is the Reserve class, which again consists of a few classes

    In case of local access, the bookFlight() must call only modify(), right???
    Now here, I have used the data-object to access all the data methods. In remote access,
    do I need to use "rf" (in the Client class constructor) to access these methods? Is that
    my remote client then?
    [ July 24, 2003: Message edited by: Nandini Sriram ]
    Andrew Monkhouse
    author and jackaroo
    Marshal Commander

    Joined: Mar 28, 2003
    Posts: 11278
        
      59

    Hi Nandini
    Remote interface (that should provide all the public methods of the Data class and this must be implemented by my server also, right?)

    That would be good.
    get all the matching values as DataInfo object and add to a vector

    Just a little off topic discussion for the moment, regarding your use of the word "vector" in the above sentence.
    It is possible that this is your psuedocode, and you have for some reason decided that you should be using a Vector for this functionality, and so you have written it in there to remind yourself later that you want to use a Vector. If this is the case, then I think you should also have a comment saying why you want to use a Vector.
    But if you have not yet determined whether you are going to use a Vector or not, then you should try and describe it in more generic terms. Go back to the interface implemented - so use List if you feel it should be in a list, or even use Collection if you still havent decided if a List or a Set or a Map is appropriate.
    The two issues I have with the use of the word Vector are:
  • Give psuedocode to a junior programmer, and they will often blindly follow the psuedocode. So you have described using a Vector, so they will use a Vector, even if there is a better class to use.
  • Psuedocode is also often transformed into comments describing the code (often badly, but the programmer gets a happy feeling for having written comments ). This can result in your comment stating that you are using a Vector. If the actual implementation uses some other class, then you have to change the comment to match (and comments often get out of sync with the code) or else every programmer looking at the code later will stop and try and work out why the comment says Vector when something else is in use. This could be avoided if you just use the interface name

  • This also applies when you are writing your code - you should always to code to the interface. So instead of using:
    You should where possible use:

    This makes it much easier to change your code later.
    Now back to your post ....
    In case of local access, the bookFlight() must call only modify(), right???

    You can do this, and many people will agree with it. The main advantage of this is that you are not calling any code that you are not using.
    The alternative is to have the same code in both local and remote bookFlight() methods. So even in local mode you will be calling lock() (and all the other code). These calls are redundant, but it has the advantage that you can have the same code operating in both modes. There should never be a case where the customer rings you up and says that something works in one mode and doesnt work in the other mode.
    As you can see - both ways of coding have their advantages. You have to work out whether one advantage outweighs the other, or if they dont, you have to choose the one you prefer. Either way, you are making a design decision.
    Now here, I have used the data-object to access all the data methods. In remote access, do I need to use "rf" (in the Client class constructor) to access these methods? Is that my remote client then?

    This sounds right for the psuedocode you have provided.
    Regards, Andrew
    Nandini Sriram
    Ranch Hand

    Joined: Jul 04, 2003
    Posts: 132
    Hai Andrew,
    Thanks for pointing out my mistake about vectors. I will be careful in future.
    Andrew, I am yet to fully design my networking. I want to be clear with the following before that.
    1. Can I modify the Data class to implement an interface (for providing local access)?
    2. The connection factory interface must be implemented by my server and the unreferenced by my connection code, right?
    3. Can u give me some links about using the above mentioned 2 things? I found one on the Sun's site :http://java.sun.com/j2se/1.3/docs/guide/rmi/Factory.html
    Is it the same connection factory concept?
    4. When I make another class (extends UnicastRemoteObject)implement the remote interface (that contains all the public methods of Data class), do I need to define all those methods again in this Remote class also?
    Thanks
    Nandini
    [ July 25, 2003: Message edited by: Nandini Sriram ]
    Andrew Monkhouse
    author and jackaroo
    Marshal Commander

    Joined: Mar 28, 2003
    Posts: 11278
        
      59

    Hi Nandini
    Can I modify the Data class to implement an interface (for providing local access)?

    I am unsure about this. The instructions tell us that Data is complete with the exception of the lock(), unlock() and criteriaFind() methods. There is a big part of me that says that since the class is complete, we should not go adding our own methods, or making it implement our own interfaces. The other part of me says that since we are allowed to change the class itself (and are required to in order to fix the deprecated methods) then we should be able to make other changes that will not break the existing code.
    My feeling is that if there is a chance that we may loose marks for modifying the Data class in any way other than specified, then it is best not to change it. You have to decide for yourself whether you agree with that or whether you feel that your modification is justified.
    The connection factory interface must be implemented by my server and the unreferenced by my connection code, right?

    Correct.
    Can u give me some links about using the above mentioned 2 things? I found one on the Sun's site :http://java.sun.com/j2se/1.3/docs/guide/rmi/Factory.html
    Is it the same connection factory concept?

    Yes - this is exactly the connection factory that we talk about here.
    As for providing you with links ... I dont understand what sort of link you would want for implementing an interface, unless you are asking about the very basic "how do I implement an interface" - and I dont think you are asking that.
    Are you asking about document(s) that describe in general terms what the Factory Pattern is?
  • Gopalan Suresh Raj's description
  • Someone's lecture slides
    Or something that you can start experimenting with?
  • Someone's lecture slides
  • this thread where I give some examples (for unreferenced) that do use a factory (though it is not explained at all )
    When I make another class (extends UnicastRemoteObject)implement the remote interface (that contains all the public methods of Data class), do I need to define all those methods again in this Remote class also?

    Yes you will have to do this.
    Regards, Andrew
  • Nandini Sriram
    Ranch Hand

    Joined: Jul 04, 2003
    Posts: 132
    Hai Andrew,
    Thanks for the links. It was exactly what I had wanted. I wanted to see how exactly the interfaces were implemented to achieve the purpose.
    1. Andrew, the default constructor of a remote class has to throw Remote Exception. Now, if I am going to define another constructor for the remote class taking Data object as an argument, should that also throw RemoteException?
    2. Also, I have read that any object that is passed as an argument in remote methods must be serializable / remote object/primitives . Is that true for constructors also (like in the above case)?
    3. When I use a hashset to store the locked records in lock(), do I need to make it static ( I read about this somewhere). Please tell me the relevance of making it static.
    4. In the lock() method, when the record is "going to be" -1 (server about to be down), then what happens to the new clients that are in the process of acquiring locks? Do I need to "just say" what I intend doing with those clients (either wait till all them are done or bring it down in anycase) or any coding???
    5. When I design the server, I code to get the localhost name as an argument. Do I need to take into account the port number also?
    Eg: Naming.rebind("rmi://localhost/somestring",factoryObject);
    Should I modify to include the portnumber also?
    6. Please tell me if my understanding of the factory pattern is right:
    Client requests for a factory reference and obtains one. Then through a getRemoteObject() method, it gets a remote object. Now it accesses all the remote methods using that remote object.
    I read somewhere that "You want to reuse old objects. The factory has a dispose method. When an object is used up, for example an iterator, it's returned to the factory via a dispose call. When the factory is asked for a new object it first checks if there're any old objects in storage it can return instead of returning a new one."
    How does it track clientID by doing this ("not unlocking locks that it does not own")?
    Thanks
    Nandini
    [ July 26, 2003: Message edited by: Nandini Sriram ]
    Andrew Monkhouse
    author and jackaroo
    Marshal Commander

    Joined: Mar 28, 2003
    Posts: 11278
        
      59

    Hi Nandini
    Andrew, the default constructor of a remote class has to throw Remote Exception. Now, if I am going to define another constructor for the remote class taking Data object as an argument, should that also throw RemoteException?

    Yes.
    I think for simple questions like this, you should experiment and see what happens yourself. You are asking about something very specific that you can determine for yourself in a few seconds. And you will learn it better by experimentation than by asking me. If you try this, then you will see what sorts of errors you can get. Then latter, if you get one of those errors when coding a real application, you may remember what caused it.
    This is not to say that I object to answering these questions, just that I think you will learn better by trying this yourself.
    Also, I have read that any object that is passed as an argument in remote methods must be serializable / remote object/primitives .

    Correct. This is in the RMI Specifications.
    Is that true for constructors also (like in the above case)?

    No - the constructor should only be called by your code, so the same restriction does not apply.
    When I use a hashset to store the locked records in lock(), do I need to make it static ( I read about this somewhere). Please tell me the relevance of making it static.

    This is usually discussed in conversations about LockManager and other ways of ensuring that a record can only be locked by one client. Basically you need some common storage space which tracks all the locks granted to all clients. One way of doing that is to have a common collection to hold the locks. This is not the only way to do this, and you may not need to make your common collection static. I recommend you read some of the topics regarding LockManagers to find out more.
    In the lock() method, when the record is "going to be" -1 (server about to be down), then what happens to the new clients that are in the process of acquiring locks? Do I need to "just say" what I intend doing with those clients (either wait till all them are done or bring it down in anycase) or any coding???

    Who says the server is about to be shut down? There could be other reasons for locking the entire database including:
  • adding a record (in my mind it is not needed, but some people prefer it)
  • major maintenance (e.g. increasing all prices by 10% for all items)
  • backing up the database


  • In all three cases, it may be preferable to stop people from writing to disk temorarily while the action takes place, then once complete, allow writing again. This can be faster and friendlier than shutting down the database.
    But to answer your question: your instructions only tell you to block until a lock is granted. So if a client is waiting to have a lock request granted, they have to block until the database is unlocked again (or until the database is shut down in which case they should get an exception from RMI).
    When I design the server, I code to get the localhost name as an argument. Do I need to take into account the port number also?
    Eg: Naming.rebind("rmi://localhost/somestring",factoryObject);
    Should I modify to include the portnumber also?

    Maybe. And I can say that with certainty.
    There is nothing in the requirements to say that you have to support anything but the standard port. Some people who didnt allow the port number to be changed got very high marks. So you may not need to.
    On the other hand (having been working middleware and backend systems for too long) I know that most administrators would want to be able to change the port number (even if they never do), so I think this could be an easy addition to make for little coding, which will make your application a little more friendlier (and a little more secure since you are no longer stuck to the "well known" port).
    Time to make a design decision: what do you feel is right? Now document it!
    Regards, Andrew
    Nandini Sriram
    Ranch Hand

    Joined: Jul 04, 2003
    Posts: 132
    Hai Andrew,
    Thanks. And I'm sorry to have bothered u about simple questions. Please take a look at my design at this stage and guide me. I have defined lock, unlock and criteriaFind inside Data class itself.
    1. interface RemoteDataServices extends Remote - provides all public methods of Data
    2. RemoteData extends UnicastRemoteObject implements RemoteDataServices, Unreferenced {
    .. Data reference ..
    .. default constructor ..
    public RemoteData(Data data) throws RemoteException, IOException {
    .. method calls passed to Data class - values returned using the data object
    }
    >>> Qn. Is this ok? Or is it better to define all the Data methods explicitly?
    >>> Qn. I understand that Unreferenced.unreferenced() will be called automatically once the referenced set becomes empty. And usually takes about 20 min, right? So no action is required by the implementation? Inside my unreferenced, I just need to instruct for unlocking records?
    3. interface Factory extends Remote (with getConnection() method throwing RemoteExcpn and IOExcpn)
    4. FactoryImpl extends UnicastRemoteObject implements Factory {

    ... default constructor ...
    public getConnection() throws RemoteException, IOException {
    Data data = new Data("db.db");
    return new RemoteData(data);
    }
    public static void main (String [] ag) {
    .. get all hostname, portnumber from the command line argument..
    ...LocateRegistry.createRegistry(port)...
    Naming.rebind("rmi://"+host+":"+port+"/String",factoryObject);
    }
    }
    >>> Qn. Here since I need to instantiate the data object, I have modified the Factory interface to throw IOExcpn. Is this ok? Or any better way of doing it?
    >>> Qn. Do I need to get the file name (for eg, db.db) from the command line argument or can I include it in the code myself?
    Please take a look at my lock and unlock too..

    Andrew, I think I need to have my lock and unlock 'definitions' inside RemoteData also implementing another set (keeping client IDs) so that I check for "client-lock" pair (I mean, check if 'this' client has 'this' lock)and if yes, I will call my data.lock (whick is going to keep track of the locked records). Is my view right? I'm at a loss as to how to implement it. Please guide me.
    Also, let me give u my understanding of the connection factory. Please point out if wrong -
    Factory object bound to the registry >> clients access the connection objects via the factory object >> so each client gets a connection object for itself >> once a client is done, the factory object reuses the connection object and passes it to another client (and this is regardless of the operations performed by the previous client, right?)
    Thanks
    Nandini
    [ July 28, 2003: Message edited by: Nandini Sriram ]
    Andrew Monkhouse
    author and jackaroo
    Marshal Commander

    Joined: Mar 28, 2003
    Posts: 11278
        
      59

    Hi Nandini
    ... method calls passed to Data class ...
    Qn. Is this ok?

    Yep - that should be fine.
    Unreferenced.unreferenced() will be called automatically once the referenced set becomes empty. And usually takes about 20 min, right? So no action is required by the implementation? Inside my unreferenced, I just need to instruct for unlocking records?

    Yes. Correct. And right.
    public getConnection() throws RemoteException, IOException {
    Data data = new Data("db.db");
    return new RemoteData(data);
    }
    Here since I need to instantiate the data object, I have modified the Factory interface to throw IOExcpn. Is this ok?

    The concept of throwing the IOException is fine.
    According to your code above you will have one instance of Data class for every connected client. Is this correct?
    Qn. Do I need to get the file name (for eg, db.db) from the command line argument or can I include it in the code myself?

    That sounds like another thing you have to make a design decision about. Do you force the user to have the database named db.db and store it in the same directory as the jar file, or do you make your system more user friendly and allow the database to be in another directory and/or to have another name?
    The specifications dont tell us a requirement. So either way could be acceptable.
    Your lock() method will return instantly if the database is locked. Do you feel this meets the specification?
    Your psuedo code for the lock method does not show where the lock is actually granted - you only show the failures. So I don't know if your synchronized block is in the wrong place or not (it could be OK, but I can't tell), and I cant see a while loop in the attempt to gain the lock.
    I think I need to have my lock and unlock (methods) inside RemoteData also implementing another set (keeping client IDs) so that I check for "client-lock" pair (I mean, check if 'this' client has 'this' lock)and if yes, I will call my data.lock (whick is going to keep track of the locked records). Is my view right? I'm at a loss as to how to implement it. Please guide me

    I recommend you read some of the recent topics discussing locking, particularly this thread. There you will find out all sorts of issues with locking and how to implement it. You will also see that I believe that it is possible to maintain a collection in the RemoteData to track which locks have been granted, whereas Max believes that this violates the specification. You should try and read the discussions so you get an idea of what the issues are, and then make up your own mind.
    Also, let me give u my understanding of the connection factory. Please point out if wrong -
    Factory object bound to the registry >> clients access the connection objects via the factory object >> so each client gets a connection object for itself >> once a client is done, the factory object reuses the connection object and passes it to another client (and this is regardless of the operations performed by the previous client, right?)

    If the factory object reuses the connection object, then you have to take extra care with your unreferenced() code, as it is possible that unreferenced will be called more than once for any given instance of the connection object.
    Regards, Andrew
    Nandini Sriram
    Ranch Hand

    Joined: Jul 04, 2003
    Posts: 132
    Hai Andrew,
    Thanks for pointing out some valuable things in my lock method. I also read through the discussion between you and Max. Very interesting!!! I wish I could discuss things with you the same way, but ... that's ok anyway!!
    I have a doubt in that Andrew(it could be simple, but it just doesn't dawn on me). Please help -I don't understand when u say, having 1 data per client is going to have us make changes to the create and recordCount variable (in particular). Please explain.
    In my design, I have a set that tracks the locks(factory) owned by the clients in the Connection code. The Data class has the "wait and notify calls alone" in lock(this also checking if the record is within the range) and unlock respectively.
    >>Qn. I have not synchronized the lock and unlock in data class but having my wait and notify inside. Is this ok, since I am anyway making a call to lock and unlock from a synchronized code from the RemoteData class?
    1. interface RemoteDataServices extends Remote - provides all public methods of Data
    2. RemoteData extends UnicastRemoteObject implements RemoteDataServices, Unreferenced {
    Data data;
    HashSet lockedRecords = new HashSet();
    boolean locked = false;
    ...calls passed to Data class..

    Then I have the Factory class.
    FactoryImpl extends UnicastRemoteObject implements Factory {
    ... default constructor ...
    public getConnection() throws RemoteException, IOException {
    return new RemoteData(data);
    }
    public static void main (String [] ag) {
    .. get all hostname, portnumber from the command line argument..
    ...LocateRegistry.createRegistry(port)...
    Naming.rebind("rmi://"+host+":"+port+"/String",factoryObject);
    System.out.println("FBN Server started...");
    }
    }
    >>Qn. When I compile FactoryImpl and try to run it on say, 1234(port number), it is started. But when I try to run it on 1099, it gives me java.net.BindException, port already in use. Please tell me what it means.
    My unreferenced code

    Is this ok?

    Thanks
    Nandini
    [ July 30, 2003: Message edited by: Nandini Sriram ]
    Andrew Monkhouse
    author and jackaroo
    Marshal Commander

    Joined: Mar 28, 2003
    Posts: 11278
        
      59

    Hi Nandini
    I don't understand when u say, having 1 data per client is going to have us make changes to the create and recordCount variable (in particular).

    Some of the methods in the Data class rely on the recordCount variable. For example, the find() method will only search records between 0 and recordCount exclusive. So if you were to add a record in one instance of the Data class, you will only be updating the recordCount in that instance of the Data class, and no other instances will ever find the added record.
    You also need to think about how you ensure that only one client is performing an add() at any given time. With a single instance of Data class, you can just synchronize the entire method. With multiple instances of Data class, you have to have some other way of maintaining integrity.
    Qn. I have not synchronized the lock and unlock in data class but having my wait and notify inside. Is this ok, since I am anyway making a call to lock and unlock from a synchronized code from the RemoteData class?

    Somewhere you have to synchronize on an object that is common to all clients, otherwise how do you ensure that two clients do not think they have gained the same lock?
    The code you posted is in your RemoteData class. Correct?
    I do not understand what you are intending in the block with the comment "intimate all new clients that transactions are going to be temporarily stopped". Since this is in the instance of the RemoteData class, it will not know about any other connected clients, or about what locks others have.
    Qn. When I compile FactoryImpl and try to run it on say, 1234(port number), it is started. But when I try to run it on 1099, it gives me java.net.BindException, port already in use. Please tell me what it means.

    It means the port is already in use
    In other words, something (propably an RMI Registry) is already running on port 1099.
    Try going to a command prompt when you think nothing is running, and type "netstat -an". If you see anything "LISTENING" on port 1099, then you know that an application is running and using that port. In Linux it is very easy to not only see whether something is using a given port but also to work out what it is that is using it:

    Under Microsoft platforms, you don't get that extra functionality with netstat, so all you can do is find out that something is running. You could try looking in the taskmanager to see what is running. It is possible that your system has been configured to run the rmiregistry as a service.
    Since I have an rmiregistry running, if I try and start a new one, I get the same error:

    As it says - the address is already in use. You can only have one process listening on a given port, so the OS is stopping the second application from listening on the same port simultaneously.
    My unreferenced code ..... Is this ok?

    I suspect you are going to get a ConcurrentModificationException with this. As you iterate over the set, you are calling the unlock() method, which will remove the record number from the set, which will confuse the iterator. When you test your unreferenced code, if you get this exception then search in this forum for the exact exception name, and you will find a few suggestions on how to handle it.
    Regards, Andrew
    Nandini Sriram
    Ranch Hand

    Joined: Jul 04, 2003
    Posts: 132
    Hai Andrew,
    Thanks for pointing out that mistake of "intimating all clients". I did not notice it. It's going to be unique for a client.
    Nandini Sriram
    Ranch Hand

    Joined: Jul 04, 2003
    Posts: 132
    Sorry. It was done before I pressed the AddReply button.
    I tried with rmiregistry as you had suggested. Yes, it takes 1099. Thanks.
    Regarding my unreferenced, do I need to clear the set inside that method. I can just unlock the records (which is anyway going to remove the record fromt the set).
    On searching for the ConcurrentModificationException, I got this posting :
    http://www.coderanch.com/t/183783/java-developer-SCJD/certification/your-help
    Your response to this exception was:
    "Instead of iterating over your collection, perhaps you could make an array of the elements of that collection. Then you can walk through the array, removing items from the collection safely.
    Alternatively, since this collection seems specific to this instance of the Remote object, you could just unlock all the records in the iterator, then once complete, just empty the collection in one hit. There doesnt seem to be a need to remove the individual records during the iteration."
    Am I not implementing your second suggestion in my code for unreferenced?
    Thanks
    Nandini
    [ July 31, 2003: Message edited by: Nandini Sriram ]
    Andrew Monkhouse
    author and jackaroo
    Marshal Commander

    Joined: Mar 28, 2003
    Posts: 11278
        
      59

    Hi Nandini
    Regarding my unreferenced, do I need to clear the set inside that method. I can just unlock the records (which is anyway going to remove the record fromt the set).

    But if your unlock method removes the record from the set that you are concurrently itterating over then you will get a ConncurentModifcationException.
    On searching for the ConcurrentModificationException ....

    Awww, I wanted you to get the exception in testing before you looked for solutions It is a much better learning experience if you get to see the errors you are fixing, and understand why they are occurring.
    Am I not implementing your second suggestion in my code for unreferenced?

    I don't think so, because you are calling an unqualified unlock() method. This means that it will call the unlock() method in the RemoteData class, which as part of it's processing will try and remove the record number from the set you are concurrently iterating over.
    If you were calling the unlock() method of the Data instance you would then be able to wait till the end of the itteration, then clear the set as you propose - this would then work as per my second suggestion.
    But if you think you are right (and you could be - I have been known to be wrong ) just try it: see if it works.
    Regards, Andrew
    Nandini Sriram
    Ranch Hand

    Joined: Jul 04, 2003
    Posts: 132
    Hai Andrew,
    Sorry. Getting back took a long time. I was working on the client side and trying to network the whole thing. I have a few doubts regarding this. I shall discuss my whole design as soon as I complete it (hope to do it soon).
    1. On my client-side class, I try to catch the various java.rmi exceptions.

    I get a stack trace saying caught java.rmi.ConnectException ... nested exception is java.net.ConnectException. I get a similar thing for UnknownHostException.
    2. I have used a mix of Flow, Border and Grid Layouts in UI. It's kind of simple. Is it ok?
    3. In the UI, I have included a combobox for the client to select date of travel also. Is it ok? If the date is the current date or before current date, the client is intimated to choose another date. Else, only those flights on that day are shown (of course origin and dest taken into account)
    4. On the client-side, say , I have a close button, do I need to call System.gc() and runFinalization() before exiting?
    5. I have used JTable as a separate frame. Is it ok? I ensure another booking (by the same client) is not done before the current booking is complete. When seats are booked, changes are not immediately seen on the table, but when it is opened again ( I mean to say when another booking is to be done) the changes are seen. Is this correct? Or should the changes be seen on that client's window immediately?
    Thanks
    Nandini
    Andrew Monkhouse
    author and jackaroo
    Marshal Commander

    Joined: Mar 28, 2003
    Posts: 11278
        
      59

    Hi Nandini
    I get a stack trace saying ....

    I am not sure if you are asking me a question here or just describing what you are doing.
    Assuming you are just telling me what you are doing, I think you would be better providing a dialog box telling the client what just went wrong and (hopefully) a suggestion on how to fix it.
    I have used a mix of Flow, Border and Grid Layouts in UI. It's kind of simple. Is it ok?

    I don't believe it matters how simple your display is, or how many (or few) components you use in creating it. I believe Sun are looking at usability.
    And the best way of determining that is to give your client to someone else and give them very few (if any) instructions. See if they can use it easily. See if they try to do something the wrong way (this is very hard: you have to be silent and let them try so you can see what is wrong: you cannot interrupt and show them "your" right way). If they find your design easy to use, then chances are you are doing something right. If they give up saying that it is too complicated, or that it doesnt do things logically, chances are you have room for improvement.
    In the UI, I have included a combobox for the client to select date of travel also. Is it ok?

    Well, it is not required by the specifications, but shouldnt hurt.
    If the date is the current date or before current date, the client is intimated to choose another date

    Hmmm, in my database I only had Days of the week, not dates. If you have real dates, then this could be OK. Otherwise this is a bit iffy.
    On the client-side, say , I have a close button, do I need to call System.gc() and runFinalization() before exiting?

    You don't have to. However removing your reference to the remote object and calling System.gc() will usually cause the servers "unreferenced()" method to be called in a more timely fashion, so it is a nice idea. If you do call System.gc() for this reason, you might want to mention why you do it in a comment so that the junior programmer knows why you are doing it (and impress the examiner with your RMI knowledge ).
    I have used JTable as a separate frame. Is it ok?

    Maybe See my earlier comment about usability.
    When seats are booked, changes are not immediately seen on the table, but when it is opened again ( I mean to say when another booking is to be done) the changes are seen. Is this correct? Or should the changes be seen on that client's window immediately?

    I think that this could cause confusion, where one client knows that they have booked 'x' seats, but do not see that reflected in their list of available seats.
    Regards, Andrew
    Nandini Sriram
    Ranch Hand

    Joined: Jul 04, 2003
    Posts: 132
    Hai Andrew,
    Thanks a lot for your replies.
    I have a doubt in JTable refresh. I'm not sure if my thinking this way is correct.
    Client A books 4 seats (out of say, 10 available seats). Once booking is done, I show a confirmation for booking. And then I referesh the table. It has to show 6 seats (I presume this is when A is the only client doing the booking at that time)???
    And when it does, I have my doubt here. Client B may also be simultaneously booking, say, 3 seats (availability is not a problem, ok!!!). So when his table is refreshed, would it say "3" seats (because A has booked 4 already) when B would have expected to see 7 ?? So should I update B's table regarding the seat changes even as he views the table?
    I just noticed something else. My unreferenced is getting called very soon In my UI, I choose 'remote' and enter the hostname and port number. It connects. Once I go to the search panel and make a selection (say origin or destination), it says 'unreference called'. But I'm able to continue with the booking and modify the database, until the unlock(). Here again, unlock() is not called. It gives me IllegalMonitorStateException :current thread not the owner.
    Please tell me where I could be wrong.
    Thanks
    Nandini
    [ August 08, 2003: Message edited by: Nandini Sriram ]
    [ August 09, 2003: Message edited by: Nandini Sriram ]
     
    I agree. Here's the link: http://aspose.com/file-tools
     
    subject: Networking : RMI
     
    Similar Threads
    FBNS: Inherit from Data class and How to operate db.db
    FBNS: Have I completed enough to pass?
    FBNS beginner.. help!!!
    FBNS: Final locking architecture, comment please...
    FBNS: Elegant design for client-side business classes