Win a copy of Five Lines of Code this week in the OO, Patterns, UML and Refactoring forum!

R Bischof

Ranch Hand
+ Follow
since Feb 13, 2001
Cows and Likes
Total received
In last 30 days
Total given
Total received
Received in last 30 days
Total given
Given in last 30 days
Forums and Threads
Scavenger Hunt
expand Ranch Hand Scavenger Hunt
expand Greenhorn Scavenger Hunt

Recent posts by R Bischof

All they asked where questions like: how have you done locking, what where the options for synchronization, simple blabla questions to ensure you are the person who has developed the submitted system.
No SCJP-style questions.
But that was just my exam, so if anybody had different experience...
I would not use an ID identifying the client.
Why not use a Session concept where each client instance has it's own remote Session object on the server?
This uniquely identifies the client and you can be notified when the client dies, etc.
And no hassles with IDs
just my 0.02 Euro
Hi Kalichar,
I started with a simple design and came to the conclusion that a more robust solution would not be much more effort.
The first full-featured but quick-and-dirty solution took me about 20-30 hours without any docs. I than had to stop working on it for about half a year because of job demands.
Afterwards I had a fresh look at it, identified a lot of design weaknesses and started refactoring the complete system until it looked like I wanted it to be (again around 20 hours). Plus two weekends for complete documentation including full JavaDoc.
Looking back it seems to be a good way to go if you have the time. Complete it, try to forget everything about it and restart with a fresh mind. You quickly identify areas which are not as clearly designed as they could be.
I had the time as this was just fun stuff for me (Java developer and consultant since 1997).
the locking is implemented in the Data class via modification. I did not add an additional layer although I now think I should have done so. It makes the whole thing clearer.

I have one Data instance per DB-File which is shared amongst all clients using this particular file. The Data class implements a DataInterface interface which extracts the public interface of the Data manipulation methods.
Each client has a DataProxy instance on the client side that implemets the same DataInterface so that the client does not need to know whether it is dealing with a local or remote DB file.
The DataProxy itself is connected to a server side DataSession instance. This DataSession belongs to one single DataProxy and has a reference to the shared Data instance and performs the real work using this Data instance.

The Data class has the following lock method:
public void lock(Object session, int record)
This method puts the lock into a hashmap where the key is an Integer with the record id and the value is the session object. It checks for an existing record or DB lock before, of course.
For multi-user mode the client executes the lock(int record) method on the local DataProxy which executes lock(int record) on the remote DataSession which in turn executes lock(Object session, int record) on the shared Data instance. The DataSession passes itself a the session parameter to the lock method. For single user mode the client directly executes the method lock(int record) on the Data instance which does nothing but call lock(Object session, int record) with a String constant as the session object.

That way the DataSession holding any lock can be identified and vice versa. That means that as soon as the DGC collects the DataSession of a dead client you are able to remove the associated locks.
I synchronized on the Data instance, so notify() always wakes up all threads waiting for a lock, no matter what lock it is. I did not implement a lock queue either.
From what I can see this is a perfect fit. Not too easy, not too complex (it is mentioned in my assignment description that it should be understandable by junior programmers).
Good luck!
Kalichar, Steve,
quite some time since my post... In the meantime I changed the implementation quite a lot.
I was busy with my job and had no time to work on the assignmend for a couple of months. When I re-started I had a fresh look at the project and found my design flaws pretty soon. I changed a lot of stuff before submitting, all points Steve mentions were changed. I also introduced the concept of a FlightBean and a FlightService which helped me a lot to cleanup the project.
Re-Factoring is the key!

When I submitted, I had one remote DataSession per client instance which holds a reference to a shared Data instance that performs the file related work, a remote DataSessionFactory (singleton) which was used to construct a DataSession and pass the reference back. That factory was looked up using the naming stuff.
On the client side there was a DataFactory which created either a local Data instance or looked up the DataSessionFactory to build a DataProxy which was connected to the DataSession to access remote data.
BTW: In my case the client has to know what DB-file it is talking to. yu may use conventions here, e.g. the server knows the path and the client only knows the filename or so. It's the same as with a typical C/S system where the client knows which DB to talk to. In the real world you would be required to build a bullet-proof security file to ensure that clients only see what they are allowed to see.

I guess that my stuff was somewhat useful. I got 152 points which makes 98% ;-)
Ooops forgot:
The written exam is just piece of cake.
I went through it in 25 minutes. They just want to make sure you are the one who did the real work, nothing else.
just checked the Website: I passed with 152 )
Many thanks to all who provided feedback when things were not so clear...
Score: 152
General Considerations(maximum = 58): 57
Documentation(maximum = 20): 20
GUI(maximum = 24): 23
Server(maximum = 53): 52
My comments:
RMI based general dataserver server with a session concept capable of serving multiple datafiles simultaneously.
Locking per session with automatic lock removal for dead clients and possibility to upgrade from record lock to DB lock.
The locking / session concept was quite complex but works fine.
On the client a simple GUI with command objects for each activity, communication between GUI and commands hidden via event-listening concept (so that a search command does not need to know the combobox, etc).
A FlightService object on the client performing data operations, a FlightBean encapsulating data for each flight.
I used lot's of patterns (factory, singleton, proxy, command, etc) and used JUnit for unit tests of the DB server.
I had a 10 page design decisions doc and a 2 page user doc, both in HTML. Paid some attention to the packaging and README as I didn't want to loose points here.
I just finalized my package yesterday evening (it's early morning here right now) as I want to upload it today. I decided to remove the dynamic class loading and granted AllPermission to both client and server. I tried for hours a lot of other things. Nothing worked. I was lucky that I used Ant and JUnit so that I did not have to make my own manual tests each time ;-)
The hassle of propertly configuring security and codebase was just too much. I rather accept one or two points reduction because of leaving these things out (I explain why in my docs so I don't expect a redutction) than getting 0 points for a non-working solution...
Reg your security issue I gues I did not explain it clear (not a native english speaker), so I try again:
* You specify a file:// codebase on the server at startup.
* The client needs to download the stubs from the server and asks the server where to find it.
* The server returns the codebase property.
* The client gets the codebase (file://d/scjd/starting)
* The client "downloads" the stubs from that path using it's own Classloader
* This "download" is not really a download: Since you specififed a file:// codebase the client has to access that file to "download" from that file.
This is IMHO the reason why the client needs access to that file. If you use an http:// based codebase you can remove this permission.
Another reason why you would want to grant AllPermission to the client as otherwise you have to ask the assessor to edit your policy file to reflect their path structure which is not allowed.

I just tried the hostname property. No difference.
The domain does not matter. When working with both client and server on the same machine I use the file::// protocol for the codebase. Therefore no class definition should go over the network.
When working with my server on the internet I use the http:// protocol for the codebase. In this case the classdefinitions go over the wire.
The later is much faster...

Regarding your security issues:
The process of dynamic downloads as I understand it is as follows:
The client performs an RMI call and receives a class identifier that it does not know. It asks the RMI server for the codebase. The client uses the codebase to download the class definition. The server does _not_ stream the class to the client but only the information where to find it.
That means that the classloader of the client has to access "d:\\scjd\starting\\-" to find the stub that is missing in it's classpath. If it does not have the required permissions it throws a security exception.

That is one of the reasons why I decided to provide a completely open policy file and explain it in the decisions document. You can't ask the SUN guys to edit your policy files to match their environment (paths, hostnames, etc).
If I keep having this trouble I will do the same for the codebase issue and simply put the stub in the client jar. >:-[
I tried all combinations of IP, computer name,, localhost, I hacked my HOSTS file, etc.
No difference. The only thing I found was that the delay depends on the netwrok connected:
No network: subsecond
LAN at home: 10 secs
LAN at work: 15 secs
LAN at home connected to the internet: 25-30 secs
Funny but not really satisfying...
you may use
java.rmi.registry.Registry registry = java.rmi.registry.LocateRegistry.createRegistry( port );
where the default port is 1099

But how do you gracefully stop it? I think this has not been covered in this thread.
I have no idea. I first unbind the bootstraped instance of my dataserver but still there may be lots of DataSession open.
There might be some clients currently performing a transaction when I call System.exit().

I think the only clean way is to unbind the bootstrapped instance, stop the registry without a System.exit() (how?) and let all RMI threads finish what they are currently doing (how?).
Any idea?
Hi all,
It's getting funny:
I have access to a server located in the public internet.
I just tried to run my FBN Server on that machine, using a codebase
The client has to connect to that machine (slow ISDN), identify that it does not have the stub classes and download the complete 25kb fbn_server.jar via HTTP to get it.
It takes only around 5 seconds to connect _and_ perform the initial search for all flights.
I need some help. Anyone?
Hi Rasika,
"network enabled" in this case just means: I have my network cable plugged in, so the network adapter is active. That means that my machine has an IP address provided by the DHCP host. If it is unplugged my machine has only the loopback IP.
The main thing I just don't understand: I am using a file based codebase. nevertheles the system tries to connect to the network, I can see some activity in my network monitor.
Unfortunately serialization can't be an issue as it must be performed for every RMI call, no matter if this call goes through a real network or the "virtual" loopback adapter. Also serialization is pretty fast, somewhere in the area of a millisecond for typical objects.
I have the impression that for some reason the system tries to resolve my machine's name. But why does it do this just because of the Codebase?
Before including the codebase I had the stubs in the client JAR as well and everything worked fine without a delay. Although I tried all machine names (real name, IP, localhost).
this is not really a threading issue as these operations are usually performed within separate client calls and thus by different threads.
If you want a more bullet-proof approach you may use one remote DataSession per client. This DataSession object may provide the same services as the Data class and has thus a similar interface.
As soon as a client dies the distributed garbage collector makes it's server side DataSession eligibla for garbage collection. In the DataSession's finalize method you can remove all locks held by this session.
There have been some threads around reagrding this design.
Although it does not really help here because the second client will have to wait for the lock until the DataSession of the first client has been garbage collected. But it makes the design clear and ensures that dead locks won't live forever.
My $0.02
1) this is done automatically. You call something on the server and the client is blocked until the server side method returns
2) if you use the notion of a DB session (one remote session object per client) your remote session will be garbage collected by the DGC. You can use the finalize method to unlock all records locked by this session