File APIs for Java Developers
Manipulate DOC, XLS, PPT, PDF and many others from your application.
http://aspose.com/file-tools
The moose likes Developer Certification (SCJD/OCMJD) and the fly likes Does the lock associate session ID or customer ID? Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of Spring in Action this week in the Spring forum!
JavaRanch » Java Forums » Certification » Developer Certification (SCJD/OCMJD)
Bookmark "Does the lock associate session ID or customer ID?" Watch "Does the lock associate session ID or customer ID?" New topic
Author

Does the lock associate session ID or customer ID?

Hu Yong Jun
Greenhorn

Joined: Jun 20, 2003
Posts: 26
Q1. Is the following statement true or not?
------------------------------------------------------------------
When the client creates a new RMI connection and gets the stub of the remote object, the RMI server will create a new remote implementation object for that stub; When the stub is dead an collected by GC at client side, the remote implementation object will be destroyed and collected by GC at server side too.

Q2. Does the lock associate session ID or customer ID?
------------------------------------------------------------------
A session ID stands for the period from the time a Customer Service Representative opens the application window and the time he closes the window.
A customer ID stands for the customer for whom the Customer Service Representative books the home services. Within a client session(namely session ID) a Customer Service Representative can book home services for more than 2 customers with different customer ID.
Andrew Monkhouse
author and jackaroo
Marshal Commander

Joined: Mar 28, 2003
Posts: 11477
    
  94

Hi Hu Yong Jun,

Q1. Is the following statement true or not?
------------------------------------------------------------------
When the client creates a new RMI connection and gets the stub of the remote object, the RMI server will create a new remote implementation object for that stub; When the stub is dead an collected by GC at client side, the remote implementation object will be destroyed and collected by GC at server side too.


Not true.

When the client creates a new RMI connection and gets the stub of the remote object, the RMI server will use the existing implementation object for that stub. It may (or may not) create a new thread to handle the new connection. It may (or may not) use an existing thread to handle the new connection.

The current (1.4) version of Sun's JRE seems to ensure that only one connection is using any one thread at any given time (you cannot guarantee that this is the case though). But that can mean that:
  • connection A can use thead 1 for it's first method call
  • connection B can use thead 1 for it's first method call
  • connection A can use thead 2 for it's second method call
  • connection B can use thead 1 for it's second method call
  • connection A can use thead 1 for it's third method call
  • connection B can use thead 2 for it's third method call

  • but all on the same object!

    Q2. Does the lock associate session ID or customer ID?
    ------------------------------------------------------------------
    A session ID stands for the period from the time a Customer Service Representative opens the application window and the time he closes the window.
    A customer ID stands for the customer for whom the Customer Service Representative books the home services. Within a client session(namely session ID) a Customer Service Representative can book home services for more than 2 customers with different customer ID.

    Hmmm, I haven't seen any assignments with a "session ID".

    A CSR can start the application and book records for more than one customer. So in that context, if you have a session ID, then your last statement would be correct.

    Regards, Andrew


    The Sun Certified Java Developer Exam with J2SE 5: paper version from Amazon, PDF from Apress, Online reference: Books 24x7 Personal blog
    Hu Yong Jun
    Greenhorn

    Joined: Jun 20, 2003
    Posts: 26
    Hmmm, I haven't seen any assignments with a "session ID".

    A CSR can start the application and book records for more than one customer. So in that context, if you have a session ID, then your last statement would be correct.


    My assignment is about the Bodgitt & Scarper. In the book Java 2 Developer Exam Cram, there is a LockManager in which record locks associate Client ID. Its method lock takes the form as public void lock(int rowNumber, Object client). Here the client is customer, isn't it?

    In the case of record locks associating CSR session, the CSR-A adds:
    a lock #1 on record #1 for customer #1
    and a lock #2 on record #2 for customer #2,
    it means that the lock #1 and lock #2 associate CSR-A, not customer #1 or customer #2 respectively.

    While in the cse of record locks associating customer ID, the lock #1 and lock #2 do not associate CSR-A, but customer #1 or customer #2 respectively.

    Whick case is more reseanable?

    If record locks associate customer ID, How does more than 2 CSR books home service for the same Customer? The locks associating the same customer are added by different CSRs, and CSRs can not distinguish the locks from each other, and one would operate the locks created by other CSR.



    I have completed the design model of the assignment befor posting the first message of this thread. I assumes that the record locks associate customer ID. The DB file access logic is encapsulated in Data, I have another class BookingFacade hold reference to Data. I do not expose the Data but the BookingFacade to client:

    For server mode, the BookingFacade is a RMI remote object and something like session bean that it has a state of customer.

    The only strong reference to Customer is from BookingFacade. Another reference to Customer is a weak reference from map entry of locked map in LockManager.

    I formerly imagine that the weak reference does not keep the Cutomer from being collected by GC when BookingFacade loses the only strong reference to it, so I can clear the corresponding lock in LockManager.

    For example, a CSR books home service for another customer and he set the customer state of BookingFacade, replacing the old customer with a new customer and losing strong reference to old customer.


    Based on the following assumption quoted from my first message in this thread:
    When the client creates a new RMI connection and gets the stub of the remote object, the RMI server will create a new remote implementation object for that stub; When the stub is dead an collected by GC at client side, the remote implementation object will be destroyed and collected by GC at server side too.

    When a CSR closes a RMI invoking cennection, the corresponding BookingFacade at server side is collected by GC and the only strong reference to Customer is lost, so that I can clear the corresponding lock in LockManager too.

    But now thank Andrew Monkhouse tell me that BookingFacade at server side does die when the corrsponding stub dies at client side. So I cannot clear the corresponding lock in LockManager in case of client session closing. I do not know how to resolve the problem of this case, would anyone suppose an good idea or I haven't found such message thread in this saloon?

    Thanks
    [ September 25, 2004: Message edited by: Hu Yong Jun ]
    peter wooster
    Ranch Hand

    Joined: Jun 13, 2004
    Posts: 1033
    I've fought with this problem using both sockets and RMI and I no longer need any Session information. I use the following structure with RMI:

    Client:
    - DataProxy gets a DataAdapter from a DataAdapterFactory
    - both DataAdapter and DataAdapterFactory are remote interfaces
    - DataAdapter.close() closes the adapter

    Server:
    - DataAdapterFactoryImpl is registered with the RMI registry and is permanently available as long as the server is active.
    - a new DataAdapterImpl is created by a call to DataAdapterFactory.newAdapter().
    - DataAdapterImpl adapts the provided Data implements DBAccess to provide open, close and RemoteExceptions
    - locks store a cookie and a reference to a Data object.

    This means that each client DataProxy has an associated Data instance on the server.

    Each business command gets a new DataProxy and therefore a new Data object, this object is closed at the end of the business command.

    When the client closes the DataProxy, the DataAdapter is closed, this closes the DataAdapterImpl which closes the Data object, which unlocks any orphan locks.

    There is a possibility that a client can disappear without closing its DataProxy while a lock is active. This is very unlikely and will be dealt with by the RMI lease expiry, rather late, but sufficient for this project. My Data class has a finalize method that calls close, but I don't rely on GC or weak references.
    Hu Yong Jun
    Greenhorn

    Joined: Jun 20, 2003
    Posts: 26
    Thank Peter Wooster for contributing a very good idea, and maybe I could take it and prefer to using both close() and weak reference.

    But I still complaint about the following solution about releasing lock created by overtime RMI client because you should set suitable expiry period.
    There is a possibility that a client can disappear without closing its DataProxy while a lock is active. This is very unlikely and will be dealt with by the RMI lease expiry, rather late, but sufficient for this project. My Data class has a finalize method that calls close, but I don't rely on GC or weak references.



    The locks must be shared by all client, how do you identify the locks created by the client session that you are using and then those locks are destroyed in close() some time later? It seems that you locks are identified by client session, doesn't it or your locks are identified by customer id?

    --------------------------------------------------------------------
    I see!

    Let the DataAdapter hold the reference to Lock objects created by the specific client and let the LockManager hold the reference to Lock objects created by all client, because there is one DataAdapter per client session, so the client can distinguish his locks from other's. The LockManager is singleton shared by all clients. It means that the lock is identified by client session. The lock is nothing about cutomer id.
    [ September 26, 2004: Message edited by: Hu Yong Jun ]
    Andrew Monkhouse
    author and jackaroo
    Marshal Commander

    Joined: Mar 28, 2003
    Posts: 11477
        
      94

    Hi Hu Yong Jun,

    My assignment is about the Bodgitt & Scarper. In the book Java 2 Developer Exam Cram, there is a LockManager in which record locks associate Client ID. Its method lock takes the form as public void lock(int rowNumber, Object client). Here the client is customer, isn't it?


    No, in this case the client is supposed to be the instance of the client application - one per CSR. The CSR can still process more than one booking for different customers.

    Note the "supposed to be" - there is a problem in this book in that the server does not generate a unique identifier for each client, so that lock method will not work as designed: all connecting CSRs will use the same "client" object.

    I mention this problem (and some others) in my review of Alain Trottier's book here in the bunkhouse.

    Regards, Andrew
    peter wooster
    Ranch Hand

    Joined: Jun 13, 2004
    Posts: 1033
    Originally posted by Andrew Monkhouse:
    Hi Hu Yong Jun,



    No, in this case the client is supposed to be the instance of the client application - one per CSR. The CSR can still process more than one booking for different customers.

    Note the "supposed to be" - there is a problem in this book in that the server does not generate a unique identifier for each client, so that lock method will not work as designed: all connecting CSRs will use the same "client" object.

    I mention this problem (and some others) in my review of Alain Trottier's book here in the bunkhouse.

    Regards, Andrew



    I have a copy of Alain Trottier's book, its not correct on this matter. You really need a remote object per client, or as I do per business operation. My code allows a single client to have multiple business operations active at once.

    I've found in testing that the RMI lease is not a very reliable or easily tunable way to deal with orphan locks. I've just implemented a keepalive process that works quickly and reliably. It goes like this:

    - the DataAdapterImpl object (per business operation on the server) runs a timer that fires every second. This increments a tick counter (synchronized since the timer is in another thread). When the counter reaches the timeout value (20 seconds) the DataAdapterImpl closes the Data object and unexports itself.

    - the DataAdapterImpl defines a keepAlive method that sets the tick counter to zero.

    - the DataProxy (per business operation on the client) runs a timer that executes the DataAdapter.keepAlive every 5 seconds.

    - the DataProxy will get a RemoteException if it tries to use the unexported DataAdapter. The user is then given an opportunity to select another server. They can just select the same one if they want to retry.

    - the Data object is kept with the cookie in the lock map keyed by record, when a Data object is closed all locks associated with that Data object are unlocked.

    This is actually quite easy to implement and appears to work properly. I haven't tested yet it against all crash scenarios, but since the close is done in response to the lack of an application level keep alive, I expect it to work even for the Blue Screen of Death on the client.

    You don't need an explicit session to do this, since the DataProxy -> Data objects act as a session object, although in my case it only represents a single business operation such as book or search. I don't actually maintain a session since that could tie up scarce socket resources. I have a single DataAdapterFactory per server that is shared with all its clients, this is the only object in the rmi registry.
    Andrew Monkhouse
    author and jackaroo
    Marshal Commander

    Joined: Mar 28, 2003
    Posts: 11477
        
      94

    Hi Peter,

    Originally posted by peter wooster:
    I've found in testing that the RMI lease is not a very reliable or easily tunable way to deal with orphan locks. I've just implemented a keepalive process that works quickly and reliably. It goes like this:
    <cut>


    Can you elaborate on what your problems were with the RMI lease?

    It is tunable - I used to set my lease to 10 seconds during testing (because I didn't want to wait for the normal lease expiration period), and I always found that my unreferenced() method was called for any orphaned connection.

    So I will be interested to learn what problems you found.

    Regards, Andrew
    peter wooster
    Ranch Hand

    Joined: Jun 13, 2004
    Posts: 1033
    Originally posted by Andrew Monkhouse:
    Hi Peter,



    Can you elaborate on what your problems were with the RMI lease?

    It is tunable - I used to set my lease to 10 seconds during testing (because I didn't want to wait for the normal lease expiration period), and I always found that my unreferenced() method was called for any orphaned connection.

    So I will be interested to learn what problems you found.

    Regards, Andrew


    I'm still experimenting with this area and would love to use lease and the unreferenced interface instead of a bespoke solution. It may just be that the documentation is opaque and I implemented this kind of support in C years ago, so it just seems easier to write it myself. I'm taking another look at it and will keeep you informed of progress.

    /pkw
    peter wooster
    Ranch Hand

    Joined: Jun 13, 2004
    Posts: 1033
    Andrew,

    I finally got the Unreferenced interface to do the keepalive for me.

    The main problem I found was the poor documentation on how to set the leaseValue under program control. The following done at startup works:


    with that done the client crash detection is very simple:



    I'm not sure the unexportObject is needed when called from unreferenced.

    Thanks/peter
    Andrew Monkhouse
    author and jackaroo
    Marshal Commander

    Joined: Mar 28, 2003
    Posts: 11477
        
      94

    Hi Peter,

    Sorry, didn't realise that the problem was just in setting the lease value. You are correct in that you should not need to unexport the object.

    Some things you should be aware of:
  • it is possible for unreferenced() to be called while the server is still running methods called from the orphaned client.
  • Logically, therefore, unreferenced() and finalize() will be called from different threads than the thread that your client's methods are running in.

  • Here's some sample code to show this:



    Note that I have both my server and client all in one file. That is for my personal convenience here. To compile the code you would run:



    The first time you run this the server will start:



    This will just sit there waiting for connections, so you will need to open a new window to run the client.

    The second time you run this, the client will start:



    Simultaneously in the server window you should see:



    So you can see that the client exited at 10:12:11, Unreferenced was called at 10:12:21, but the method that the client had called continued until 10:12:34. And Finalize was called 30 seconds after that!

    And there were three separate threads running those three methods:
  • RMI TCP Connection(4)-192.168.1.31
  • RMI Unreferenced-0
  • Finalizer

  • Regards, Andrew
    peter wooster
    Ranch Hand

    Joined: Jun 13, 2004
    Posts: 1033
    Originally posted by Andrew Monkhouse:
    Hi Peter,

    Sorry, didn't realise that the problem was just in setting the lease value. You are correct in that you should not need to unexport the object.

    Some things you should be aware of:
  • it is possible for unreferenced() to be called while the server is still running methods called from the orphaned client.
  • Logically, therefore, unreferenced() and finalize() will be called from different threads than the thread that your client's methods are running in.

  • Here's some sample code to show this:

    ...
    Thanks Andrew,

    I'm aware of the multithreading aspects of this, the way I've built my client I have to take account of the fact that a single client can have multiple threads on the server. The test I've been using for this involves the client locking a record and then displaying a modal dialog, attempting to update the same record from another client on the same machine, putting it in a lock wait and then unplugging the ethernet cable. The client is running on W2K and the server on Solaris. I display the thread name and command sequence in all RMI and server related log messages, and have confirmed that the threading works.

    I currently have a few problems in the client if I plug the ethernet cable back in, but it does recover after the user reopens the netwotk connection.
    Marlene Miller
    Ranch Hand

    Joined: Mar 05, 2003
    Posts: 1391
    Each business command gets a new DataProxy and therefore a new Data object, this object is closed at the end of the business command.

    Hi Peter, what does it mean to close an object? I am guessing, resources associated with the object (files, locks) are closed or removed. Thank you. Marlene
    [ October 06, 2004: Message edited by: Marlene Miller ]
    peter wooster
    Ranch Hand

    Joined: Jun 13, 2004
    Posts: 1033
    Originally posted by Marlene Miller:
    Hi Peter, what does it mean to close an object? I am guessing, resources associated with the object (files, locks) are closed or removed. Thank you. Marlene

    [ October 06, 2004: Message edited by: Marlene Miller ]


    Marlene,

    Your're close on the close.

    My Data class implements a second interface that provides data control operations, including a close() method. The close tells the DatabaseFile singleton to unlock any remaining locked records for that Data object. This also occurs if the DataAdapterImpl goes unreferenced.

    The action of closing the Data object does not close the RandomAccessFile, this is controlled by the DatabaseFile singleton, which remains open until server shutdown.

    /peter
    Marlene Miller
    Ranch Hand

    Joined: Mar 05, 2003
    Posts: 1391
    Thank you very much Peter.

    Each business command gets a new DataProxy and therefore a new Data object, this object is closed at the end of the business command.

    DataProxy gets a DataAdapter from a DataAdapterFactory

    This means that each client DataProxy has an associated Data instance on the server.

    Peter, I don�t understand the role of a DataProxy on the client side. I would have guessed the stub (DataAdapterImpl_stub) was the proxy.

    I have been assuming that (philosophically) RMI creates the illusion that a distributed program is running on one system. From the programmer�s perspective, remote objects and methods work like local objects and methods. But in reality, there is this stub on the client that stands-in for the remote object.

    I am curious to know the purpose of this class, the DataProxy, between your business command and the DataAdapter object, and why it serves as a proxy.

    Regards, Marlene

    ----------
    hours later... I am guessing DataProxy is the "switch". It has a reference either to a local Data object or to the stub. - Wrong.
    [ October 07, 2004: Message edited by: Marlene Miller ]
    peter wooster
    Ranch Hand

    Joined: Jun 13, 2004
    Posts: 1033
    Originally posted by Marlene Miller:
    Thank you very much Peter.

    Peter, I don�t understand the role of a DataProxy on the client side. I would have guessed the stub (DataAdapterImpl_stub) was the proxy.

    I have been assuming that (philosophically) RMI creates the illusion that a distributed program is running on one system. From the programmer�s perspective, remote objects and methods work like local objects and methods. But in reality, there is this stub on the client that stands-in for the remote object.

    I am curious to know the purpose of this class, the DataProxy, between your business command and the DataAdapter object, and why it serves as a proxy.

    Regards, Marlene

    [ October 07, 2004: Message edited by: Marlene Miller ]


    Marlene,

    Thanks for the question, it helps to clarify my choices doc.

    The DataProxy has exactly the same interface as the Data class, so I can cast either Data or DataProxy to a DBAccess reference. The DataAdapter and DataAdapterImpl add RemoteException to the methods, this is not consistent with the DBAccess interface. So what I have is

    For standalone mode
    Business -> DBAccess(Data)

    For networked mode
    Business -> DBAccess(DataProxy) -> DataAdapter -RMI-> DataAdapterImpl -> Data

    This way all the Business class cares about is the DBAccess interface and a factory method that produces DBAccess references directly to Data if standalone and using a DataAdapterFactory obtained from the registry if its remote.

    A proxy is defined in GoF as an adapter that "defines a representive or surrogate for another object and does not change its interface". As such the DataAdapter provides a proxy to the DataAdapterImpl but it doesn't provide one to Data since it changes the interface, the DataProxy simply deals with the exceptions and provides the identical interface to the Data class provided in the instructions.

    If you decided to change the interface provided in the instructions you could remove this.

    /peter
    Marlene Miller
    Ranch Hand

    Joined: Mar 05, 2003
    Posts: 1391
    Thank you Peter.
     
    I agree. Here's the link: http://aspose.com/file-tools
     
    subject: Does the lock associate session ID or customer ID?