The requirement is to seralize multiple executions of one particular action. In a non-EJB scenario, a singleton class with a synchronized method would have helped. As EJB spec does not recommend non-final static attributes and it allows the container to have more than one JVM, that idea will not work. I am trying to implement it using beans in two ways :
1. Stateless SB with a pool size of 1
Problem : A second instance always seems to get created when the first call has engaged the first instance.
2. Stateful SB
Problem : An InvalidStateException is thrown when second call is made. The ejbRemove() method gets called on the first instance. Though the first call eventually completes that instance becomes useless thereafter.
Any explanation for this behaviour? Alternate ideas?
Here are the reasons for your problems:
1. This is not covered by the spec, and your container can implement the pool any way it wants. If it creates more than one instance it doesn't sound right, but it doesn't violate any rules. Note that this type of solution is not portable and probably won't work as the environment evolves into clusters, for instance. You will have to deploy on a single server (unless the App server has some sort of a distributed pool), and sacrifice fault tolerance.
2. A client may not concurrently invoke business methods of stateful session beans (see 7.5.6 in EJB2.0). The container may throw back an exception when such an attempt is made.
There is no portable way that relies purely on the EJB spec to do what you want. This is because EJB does not provide any type of "global" singleton components.
If you want to accomplish this portably, probably the easiest way is to use a DB to synchronize. When you start the method select some row FOR UPDATE to block any other method calls.
Note that it may be neccesary to perform the method in a seperate transaction from the caller context, or the lock will not be released until the caller's transaction concludes.
There are other ways to accomplish this using a singleton RMI object, for instance, but these usually sacrifice fault-tolerance. I've seen a solution that uses Jini to accomplish the same thing without sacrificing fault-tolerance, but such solutions are usually far less efficient.