New Topic
sleroux Feb 19, 2008 12:25 PMHi there,
First a word of warning: I'm new to Seam, EJB3, JSF, Hibernate, and so on... So please forgive me for this newbie
question.
Conversation, as I understand it
I have some trouble with the @End annotation in my stateful session bean (conversation scope). As I have said, I'm new to Seam. But by reading the Seam Reference manual and previous posts on the old forum (most notably this one), it appears to be clear that calling a @Begin method will start (or join) a conversation, and calling a @End method will end the current conversation.
I have (mis?)understood that the SFSB will then be destroyed by the application server after the @End method is completed. So the next time a @Begin method on that bean will be used in my JSF page, a new instance of the STSB will be created.
Conversation in my sample application
So, I've made a sample application to check that. Very simple, not much more that the Hello Seam world
program on Michael Yuan's book.A conversation scoped entity bean (Book), and a conversation scoped stateful session bean (BookManagerAction).
Here is the code:
@Entity @Name("book") @Scope(ScopeType.CONVERSATION) public class Book implements Serializable { private static final long serialVersionUID = 1L; @SuppressWarnings("unused") @Id @Length(min=10,max=10) private String ISBN; private String title; public Book() {}; public Book(String ISBN, String title) { this.ISBN = ISBN; this.title = title; } public String getISBN() { return ISBN; } public void setISBN(String isbn) { ISBN = isbn; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } @Override public String toString() { return title + "/" + ISBN; } }
@Stateful @Scope(ScopeType.CONVERSATION) @Name("bookManager") public class BookManagerAction implements BookManager { @PersistenceContext(type=EXTENDED) private EntityManager em; @In private Book book; @In private FacesContext facesContext; public BookManagerAction() { System.err.println("xxxxxxxxx PrintManagerAction()"); } @SuppressWarnings("unchecked") @Override public List<Book> allBooks() { return em.createQuery("select b from Book b") .getResultList(); } @Override public String save() { try { em.persist(book); em.flush(); book = new Book(); } catch(javax.persistence.EntityExistsException e) { FacesMessage message = new FacesMessage("Error: already exists. " + e.getMessage()); facesContext.addMessage(null, message); return null; } return "done"; } @Remove @Destroy public void destroy() { // nothing to do } }
And the view:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:s="http://jboss.com/products/seam/taglib"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>New book</title> </head> <body> <h1>New book</h1> <p>This page allow to add a new book to the database</p> <h2>Create</h2> <h:messages /> <form jsfc="h:form" id="Book"> <s:validateAll> <p><label for="title">Title:</label><input id="title" type="text" jsfc="h:inputText" value="#{book.title}" /><h:message for="title" /></p> <p><label for="isbn">ISBN-10:</label><input id="isbn" type="text" jsfc="h:inputText" value="#{book.ISBN}" /><h:message for="isbn" /></p> <p><input type="submit" jsfc="h:commandButton" value="Submit" action="#{bookManager.save()}" /></p> </s:validateAll> </form> <h2>Books in the database</h2> <h:form> <h:dataTable value="#{bookManager.allBooks()}" var="book"> <h:column>#{book.title}</h:column> <h:column>#{book.ISBN}</h:column> </h:dataTable> </h:form> </body> </html>
Notice that the application is deployed as an EAR, and that I do not use any page.xml.
At this point, it works fine. When running the application, I could see that a new STSB instance is created after each user action.
So, I've decided to use @Begin and @End annotation: allBooks
will start the conversation, and save
will end it:
@Begin(join=true) @SuppressWarnings("unchecked") @Override public List<Book> allBooks() { ... }
@End @Override public String save() { ... }
To my mind:
- a new conversation will begin when the user will load the page.
- The bean will join that conversation when allBooks will be called.
- In case of input error (wrong format for the ISBN), the page will be redisplayed, using the same conversation and the same STSB.
- And finally, the conversation will end at
save
time, and a new one will begin when the result page will be rendered, so the process will continue.
But, it doesn't work like that! It appears to me that the same bean will be used even after a save, just like if there wasn't any @End annotation ???
I cannot figure exactly what's wrong here. Maybe it is due to the fact that I use the same page to end and start a new conversation using the same STSB?
Or maybe it is due to something I read in a previous post (an that I don't really understand)
When an @End method is encountered, any long-running conversation context is demoted to a temporary conversation
So, if you have any idea...
Thanks in advance,
Sylvain.