There are a few things I've been trying to get straight about Beans and Conversations with JBoss Seam. To that end I worked out these examples.
1)Stateless bean with number counter
package org.jlowrey.examples.sessionbeans; import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Scope; import org.jboss.seam.ScopeType; @Name("Stateless")//this put's this object in "el" scope in the xhtml page. @Scope(ScopeType.STATELESS) public class Stateless { private int count = 0; public int getCount() { count++; return count; } }
<html> Stateless has been called: <b>#{Stateless.getCount()}</b> times. </html>
Hit refresh several times and as one would guess the count never goes above 1. The bean is stateless and should not keep state between uses. Is there a case where this bean could show a count more than one? An improper use of a Stateless EJB does it.
package org.jlowrey.examples.sessionbeans; import org.jboss.seam.annotations.Name; import javax.ejb.Stateless; @Stateless //this annotation turns it into an Enterprise Java Bean. This annotation also sent me //on a wild goose chase as in my <a href="http://docs.jboss.com/seam/latest/reference/en/html/gettingstarted.html" title="http://docs.jboss.com/seam/latest/reference/en/html/gettingstarted.html">http://docs.jboss.com/seam/latest/reference/en/html/gettingstarted.html</a> I didn't specify an Ear file, I specified war. Thus the //configuration I had couldn't use EJB's and this this one wouldn't be found. @Name("StatelessEJB") public class StatelessEJBBean implements StatelessEJB //Also note EJB's have to implement an interface. Some abstraction little guys like //don't care much about, but have to adhere to. This is not <a href="http://www.rubyonrails.org" title="http://www.rubyonrails.org">http://www.rubyonrails.org</a> Dorothy... { private int count = 0; public int getCount() { count++; return count; } } package org.jlowrey.examples.sessionbeans; import javax.ejb.Local; @Local public interface StatelessEJB { public int getCount(); }
<html> Stateless has been called: <b>#{Stateless.getCount()}</b> times. StatelessEJB has been called: <b>#{StatelessEJB.getCount()}</b> times. </html>
I then hit refresh a few times.. wtf! StatelessEJB's counter is up to 5. Uh... as it turns out the container, in this case JBoss 4.x, is allowed to recycle Stateless EJB's as in use them over again, duh, it says it in the docs.
2) Stateful Session Beans in the session context. Next I tried some stateful session beans with the state being held in various contexts. First up a stateful session bean being held in the session context. Is it me, or do I hear the term session being used for stateful bean that has state in any context? Like a "session bean" in conversation context. Yes, I do. Here's quote from the docs "By default, stateful session beans are bound to the conversation context." That's confused me up until this point. So by session they mean any context that holds state. I guess I've confused HTTP session as a one size fits all session and not the fine grained variances they have, conversation, session, event, page, and so on. Anyway...
package org.jlowrey.examples.sessionbeans; import org.jboss.seam.annotations.Name; import javax.ejb.Stateless; import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.Scope; @Name("Stateful") @Scope(ScopeType.SESSION) public class StatefulBean { private int count = 0; public int getCount() { count++; return count; } }
<html xmlns="http://www.w3.org/1999/xhtml" > <br/> Stateless has been called: <b>#{Stateless.getCount()}</b> times.<br/> StatelessEJB has been called: <b>#{StatelessEJB.getCount()}</b> times.<br/> Statefull has been called: <b>#{Stateful.getCount()}</b> times.<br/> </html>
@Scope(ScopeType.CONVERSATION)
package org.jlowrey.examples.sessionbeans; import org.jboss.seam.annotations.Name; import javax.ejb.Stateless; import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.Scope; @Name("StatefulConversation") @Scope(ScopeType.CONVERSATION)//note that this is just a Java Bean (no @Stateful or @Stateless to turn it into an EJB so it needs the @Scope(ScopeType.CONVERSATION) else it would be in the Event context. public class StatefulConversationBean { private int count = 0; public int getCount() { count++; return count; } @Begin public void startConversation() { } @End public void endConversation() { } }
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:s="http://jboss.com/products/seam/taglib" > <br/> Stateless has been called: <b>#{Stateless.getCount()}</b> times.<br/> StatelessEJB has been called: <b>#{StatelessEJB.getCount()}</b> times.<br/> Stateful Session has been called: <b>#{Stateful.getCount()}</b> times.<br/> Stateful Conversation has been called: <b>#{StatefulConversation.getCount()}</b> times.<br/> <b><s:link value="Start a conversation" action="#{StatefulConversation.startConversation()}" /></b><br/> <b><s:link value="Stay in a conversation" view="/test.xhtml" /></b><br/> <b><s:link value="End conversation" action="#{StatefulConversation.endConversation()}" /></b><br/> </html>
looking closely at the status bar we see a query param "cid=6". We picked this up after click the start conversation link. As long as we click "stay" it continue to be "cid=6". We can reset the conversation counter by clicking the "end" link.
Comments
This was great!
My only question is that with the StatelessEJB, you mention that it holds state with an improper use of a Stateless EJB. What would be the proper use? I've been searching all over for this.
TIA,
Mike
Proper use of StatelessEJB
Anything that does not rely on instance variables in the statelessEJB. Anything that is basically atomic to that request. For example suppose you want to show some statistic from your db that must be recomputed every time a request is made.
public int getStat()
{
//don't appeal to any instance variables for this class
//'cause this class may have been recycled.
//do a db query and return some bit of info like how many comments to a post.
//select count(*) from comments where comment_id=34
return commentCount;
}
Or let a user submit some data that you will store. As long as you don't appeal to any information that the class in question could store in an instance variable.
For each request the container (JBoss) is allowed to reuse an already instantiated class or it can create a new one with fresh instance variables. Consider that you know what you are doing to a given instance variable for a given class. However since you don't know if the class has been used already, you don't know if said "doing" has been done. You could write stuff in to keep track, but that is what stateful beans are for.
Thank you!!!
Thank you for clarifying this for me! We are having some MAJOR conversation/state issues in our application, and your help and this post is much appreciated!
Thanks again!
Mike
Good Job!
Thank for explaining this as it is one of the tricky topics when you start using Seam.
Thanks
Glad to see someone found this :-)
@Stateless
Dude, what happened with the @Stateful annotation. Since you are talking about a @Stateful EJB you do not show any of a kind.
These are just POJOs in different scopes (except the first one) rather than EJB's.
I think you should fix either the text or the code ;)
Cheers.
No @Stateful EJBs here.
Actually I am not talking about a @Stateful EJB. Just a bunch of beans.
Perhaps the issue is the use of the term 'state'. By state I mean state being held between requests by the server on behalf of the user. Nothing to do with EJBs. EJBs may appeal appeal to this definition of state, but this definition of state knows nothing of EJBs. It is the classic definition of HTTP session state as I understand it.
These are just examples of "conversations" with various beans (the pun is intended). Specific care is taken to illustrate the life of these beans as they are instantiated, used, and possibly reused by the container depending on what annotation is used.
@Stateful wasn't an example because, for me, it wasn't confusing and didn't have any interesting side effects. @Stateless beans on the other hand were interesting.
Does that help?