views:

764

answers:

5

I have a stateless session bean that contains one public method, several private methods, and some instance level variables. Below is a pseudo code example.

private int instanceLevelVar

public void methodA(int x) { 
  this.instanceLevelVar = x;
  methodB();
}

private void methodB() {
  System.out.println(instanceLevelVar);
}

What I'm seeing is that methodB is printing values that weren't passed into MethodA. As best I can tell it's printing values from other instances of the same bean. What would cause this?

I should point out the code works as expected 99.9% of the time. However, the .01% is causing some serious issues / concerns for me.

I understand that if I had different public methods then I might not get the same bean back between calls, which would result in this behavior. However, in this case the only call is to the single public method. Will the container (Glassfish in this case) still swap the beans out between private method calls?

(edit) I renamed "class level" to "instance level" as this was causing some confusion.

+1  A: 

Because this is very strange I performed a quick test with Netbeans and my local Glassfish 2.1.

  1. Create a new project using Samples->Java EE->Servlet Stateless. This creates an enterprise project with a simple stateless bean and a servlet that uses it.
  2. I modified the stateless bean to look like this, as close to your example as possible I think.

    @Stateless
    public class StatelessSessionBean implements StatelessSession {
    
    
       String clName;
    
    
       private void testNa() {
          System.out.println(clName);
       }
    
    
       public String sayHello(String name) {
          this.clName = name;
          testNa();
          return "Testcase";
       }
    }
    

This works as it should. I don't know what editor you're using, but if it's Netbeans it may be interesting to run it yourself.

fvu
The code is considered as nested in the list, it needs 8 blanks oO
Pascal Thivent
Thank you very much Pascal!
fvu
The example you have looks right. However, it think the problem only occurs when there are multiple beans in use. I'm going to to try and write some test code and use some load software to see if I can reproduce a hit.
Preston
@fvu Is this EJB 3.0? I think question was specifically about EJB 2.1
Rocket Surgeon
@RocketSurgeon, as Preston mentioned that he works on a GlassFish container I more or less assumed 3.0. I don't see any reference to 2.1 in the original question, there's just a quote from the 2.1 spec by Pascal Thivent in another answer.
fvu
yes, the spec is EJB 3
Preston
@Preston was the test I proposed useful to you?
fvu
@fvu - man was it useful! ;)
Rocket Surgeon
@fvu I still haven't tried developing a load test yet, but yes it was useful.
Preston
+2  A: 

When I read What is a Session Bean? section of the J2EE 1.4 tutorial:

Stateless Session Beans

A stateless session bean does not maintain a conversational state for a particular client. When a client invokes the method of a stateless bean, the bean's instance variables may contain a state, but only for the duration of the invocation. When the method is finished, the state is no longer retained. Except during method invocation, all instances of a stateless bean are equivalent, allowing the EJB container to assign an instance to any client.

In your case, the call to methodB() from methodA() will be on the same instance and is equivalent to this.methodB(). I'm thus tend to say that methodB() can't output something else that the value that what was passed to methodA().

This is confirmed by the first sentence in section 7.8.11 in the EJB 2.0 spec: "The container must ensure that only one thread can be executing an instance at any time". This means you cannot come to a situation where data (in your instance variables) from different clients (threads) will be mixed. You are ensured unique access to the instance variables until methodA() has returned!

That said, I'm not saying that you don't have a problem somewhere. But I don't think that your pseudo code is equivalent.

(EDIT: Having read some comments to the OP's question, there is now clearly a doubt about the pseudo code and semantic used. I'm clarifying possible consequences below.)

As underlined by Rocket Surgeon, what do you mean exactly by class variable? Do you really mean class variable as opposed to instance variable? If yes, the pseudo code doesn't reflect it but this will clearly lead to unpredictable behavior. Actually, from section 24.1.2 (and first point) in the EJB 2.0 spec, it is clear that you are not allowed to write data to a class variable (although you can do it). There must be a good reason for this :)

Pascal Thivent
I'm calling it a class level variable just because it has scope to the class as opposed to a method level variable. The actual declaration looks like private int x;
Preston
The EJB spec also says "Because all instances of a stateless session bean are equivalent, the container can choose to delegate aclient-invoked method to any available instance. This means, for example, that the container may delegate the requests from the same client within the same transaction to different instances, and that the container may interleave requests from multiple transactions to the same instance."It's the last part of the last sentence that makes me wonder. "and that the container may interleave requests from multiple transactions to the same instance"
Preston
@Pascal, so apparently this is an EJB 3.0 spec question, not 2.1
Rocket Surgeon
@Rocket Mmm, the OP wrote *"Because all instances of a stateless session bean are equivalent, the container can choose to delegate a client-invoked method to any available instance. This means, for example, that the container may delegate the requests from the same client within the same transaction to different instances, and that the container may interleave requests from multiple transactions to the same instance."* which is in EJB 2.x spec. But I'm doubting now, I'd like the OP to confirm.
Pascal Thivent
@Pascal Yes, this was for the ejb 3.0 spec. Thanks for the help!
Preston
@Preston @Rocket This still holds for EJB 3.0, the behavior is the same, the version of the spec is not the important part.
Pascal Thivent
A: 

It all hinges on what you mean by "class level variable". A class variable must have the static modifier. If clName doesn't, then each instance of your stateless session bean has its own copy of clName. Your Java EE server probably created a pool of two or more instances of the stateless session bean, and each of your calls to testNa() and sayHello() gets sent to an arbitrary instance.

Jim Ferrans
I'm calling it a class level variable just because it has scope to the class as opposed to a method level variable. The actual declaration looks like private int x;
Preston
So you're saying that public call to sayHello might be handled by bean 1 and the private call to testNa might be handled by bean 2?
Preston
Yes, or in the current example, you call methodA() of one bean and methodB() of another, etc. Since each bean (object) has its own instanceLevelVar, if you were expecting instanceLevelVar to be shared by all the beans in your class, you'd be surprised by the results.
Jim Ferrans
+1  A: 

I would just not bother using instance variable in stateless session bean at all. Regardless of what the cause of the issue you have encountered, it's probably not something you would want to do anyway. Just try using local variables throughout or define instance variables in helper classes you are calling from the stateless session bean business methods.

Rocket Surgeon
one of my team members is saying the same thing.
Preston
+1  A: 

The likely cause of the issue is that the container is using the same object in two requests (therefore two threads) at the same time. So the first thread gets to line that calls methodB and then the next thread gets to the code which calls methodB and then the first thread executes the call to methodB, causing the issue. That would explain the behavior, at any rate. It doesn't seem to fit the spec, but that could just be a bug.

In general, even if permitted, keeping state in the bean is not a great idea. It leads to confusion code and can easily lead to bugs where you forget to start over with your all your state on every method call.

It would be much better to just pass those objects around between methods, and that would avoid all issues.

Yishai