<Simple DataTable Example | Seam on Tomcat >
One good thing that Seam adds to JSF is the ability to use GET requests to retrieve data. The JSF spec decided to make every request a post, and this makes it difficult to bookmark pages or fetch pages directly from entering a url along with some parameters.
Well see how this problem is solved in Seam using a simple annotation: @RequestParameter. This annotation allows us to pass a request parameter to our Seam component. Its value is injected before any method is called, guaranteeing us that the request paremeter will be available to us to make use of in our code. A look at our previous example shows us that departmens belong to specific faculties. This means we will need to pass the particular faculty whose departments we want to see on our departmentList.xhtml page displaying departments. Here’s the code that does it in our departmentListing Seam component:
@Stateful
@Name(“departmentListing”)
@Scope(ScopeType.SESSION)
public class DepartmentListBean implements DepartmentList {
@PersistenceContext(type=PersistenceContextType.EXTENDED)
EntityManager em;
@DataModel
List<Department> departments;
@DataModelSelection
private Department department;
@In FacesMessages facesMessages;
@RequestParameter
Integer facId;
@Out(required=false,scope=ScopeType.SESSION)
Faculty faculty;
@Factory(“departments”)
@Observer(“univseam.event.DepartmentChanged”)
public void departmentList() {
//select if a faculty id has been passed to us
if(facId != null){
try {
faculty = (Faculty) em.createQuery(“Select f from Faculty f where f.id=:id”).
setParameter(“id”, facId).getSingleResult();
} catch (NoResultException exception) {
facesMessages.add(“Non-existent faculty passed!”);
return;
}
}
//if the faculty is not null then select its departments
if (faculty != null) {
departments = em.createQuery(“Select d from Department d where d.faculty=:faculty”).
setParameter(“faculty”, faculty).getResultList();
return;
}
facesMessages.add(“No departments under this faculty yet”);
}
Our list of departments is as shown below.
The “facId” is a request parameter passed from the page displaying the list of faculties. The method departmentList() is annotated with @Factory(“departments”), which forces Seam to load up the list of departments into the “departments” ArrayList. Seam guarantees that the faculty id will be properly converted to an Integer and placed in the facId variable before we initialize our list of departments, enabling us to first select the particular faculty and pass it to the query to load the departments. Outjecting the faculty object to the Session context is necessary to this discuss and we’ll see why soon.
But how was the request parameter passed? Well, the simple <f:param> tag in JSF allows use to do that. Take a look at this portion of the facultyList.xhtml facelet.
<h:column>
<f:facet name=”header”>Action</f:facet>
<s:link value=”Departments” view=”/departmentList.xhtml”>
<f:param name=”facId” value=”#{faculty.id}”/>
</s:link>
</h:column>
With the use of an <s:link> we are able to append the faculty id to our URL under the name facId and seam binds to that name using the RequestParameter.
Not only is RequestParemeter useful in searching, but can also be very helpful in determining if an entity is being edited or a new one being created. Here we are with a list of departments. We want to use the same page to edit as we do for new department creation. RequestParameter to the rescue.
@Stateful
@Name(“departmentManager”)
public class DepartmentManagerBean implements DepartmentManager {
@In
EntityManager entityManager;
@In
FacesMessages facesMessages;
@In
Faculty faculty;
@Out(required=false)
private Department department;
@RequestParameter(“depId”)
Integer depId;
public void createDepartment() {
//if the department already exists, then allow an edit
if(depId != null){
try {
this.department = (Department) entityManager.createQuery(“Select d from Department d where d.id=:id”).setParameter(“id”, depId).getSingleResult();
} catch (NoResultException noResultException) {
facesMessages.add(“Invalid department”);
}
facesMessages.add(“Editing a department”);
return ;
}
//else instantiate a new department entity
this.department = new Department();
this.department.setFaculty(faculty);
facesMessages.add(“Creating a new department”);
return;
}
Passing the department id enables us to find out if a department like this exists already, in which case we load up that department for editing. If not we create a new department instance, passing it the faculty to which it belongs (which we injected from the previously outjected instance).
Look at how this is done in the departmentList.xhtml facelet.
<h:column>
<f:facet name=”header”>Action</f:facet>
<s:link id=”edit” value=”Edit”
view=”/department.xhtml” action=”#{departmentManager.createDepartment}” propagation=”begin”>
<f:param name=”depId” value=”#{department.id}”/>
</s:link>
</h:column>
The page for modifying/creating a new department is below
Again this appends the department id as depId to the URL, and Seam makes it available to our departmentManager to use before the createDepartment method is called. Through this the department.xhtml facelet can be used both for creation and editing of department entities.
I’ve also been looking at alternative ways of automatically refreshing a list when a new element has been added to it in the database. Since @Factory is called only if the referred to object is null, we need another way to reload the list of departments and add the new department as well. Seam has an event mechanism based on the Observer pattern. This allows me to raise events, and all observers of that event immediately get notified of it. After populating the fields of a department I call saveDepartment, which saves my entity to the database. I then raise my own pretentious event: “univseam.event.DepartmentChanged”.
@End
public String saveDepartment() {
if(department.getId()!= null){
entityManager.merge(department);
facesMessages.add(“Department updated!”);
}else{
entityManager.persist(department);
facesMessages.add(“New department added!”);
}
Events.instance().raiseEvent(“univseam.event.DepartmentChanged”);
return “success”;
}
Notice that the factory method that initializes the list of departments (displayed previously) is also annotated with @Observer(“univseam.event.DepartmentChanged”). This time the facId will be null, but faculty is still in session scope, so we are able to reload the list of departments as if it’s nobody’s business.
Seam events enable applications to be very stateful, updating themselves when changes happen on the fly. Combining it with request parameters even makes it more fun to do.
Added on 8th April 2008:
Here is the updated link to the source for this tutorial



January 28, 2008 at 6:06 pm |
Bookmarkable parameters and the events model in Seam
Bookmarkable parameters and the events model in Seam, One good thing that Seam adds to JSF is the ability to use GET requests to retrieve data. The JSF spec decided to make every request a post, and this makes it difficult to bookmark pages or f…
March 17, 2008 at 6:33 am |
Great tutorial Edem. It’s great to see some coverage of the lesser talked about features of Seam such as @Observer. These are such powerful features, but often overlooked.
One note. You certainly don’t have to call entityManager.merge(department) in the @End method. You started a conversation, so the entity should still be managed. The update will happen when the transaction ends and the persistence context is flushed. If you want to eagerly flush, perhaps to catch any exception thrown, just call entityManager.flush().
Merging should only be done when a non-managed entity needs to be brought into a different persistence context than what loaded it. Seam conversations all but eliminate the need to do so.
April 1, 2008 at 9:53 pm |
Nice tutorial! I was looking for a better explanation to both @RequestParameter and @Observer.
On the link to your tutorial, it is before the changes you made. Is there a link to the full source?
April 6, 2008 at 5:06 pm |
Nice post although your download doesnt contain all the code.
April 7, 2008 at 4:06 pm |
@Scott and @John Hedden
I don’t have the code with me here. I’ll get it up very soon (maybe tomorrow if i remember to copy it from my other pc).
Fingers crossed and thanks for the interest.
April 7, 2008 at 4:09 pm |
@Dan Allen
There have been some cases where I’ve experienced exceptions if i don’t merge the entity used in a conversation. I cannot explain why but I’ve adopted the habit of putting it there to make sure the persistence context does not miss any such update I make. Thanks for the comment though.
April 8, 2008 at 8:52 am |
@Scott and @John Hedden
I’ve update the source now. Thanks for drawing my notice to it.
April 11, 2008 at 12:49 am |
Thanks Edem! Dan’s point about merge was something i didnt know. Thats pretty cool.
May 21, 2008 at 9:25 am |
[...] Seam: Simple Data Table & Conversation Example <Getting NetBeans 6 … | Using @RequestParameter and @Observer …> [...]
May 30, 2008 at 12:48 pm |
Great tutorial,
when clicking on login there is an exception -home.uni is not available …. cant see it in the source code either is source code up to date
thanks
June 11, 2008 at 9:35 am |
Sorry about that login link. I just didn’t implement it. I guess i’ll leave that there for someone else to experiment with implementing. Ciao.
July 23, 2008 at 5:46 am |
Response to post on April 7, 2008 at 4:09 pm
@Edem Morny
You might have experience that while using @PersistenceContext (not extended) and nested conversations, it was my case.
July 23, 2008 at 9:27 am |
@Bernard
I don’t remember exactly what made me concoct up this way of using the @Observer and @RequestParameter annotations, but i believe it had something to do with what u just mentioned. Good to hear it solved your problem.
March 30, 2009 at 12:11 pm |
[...] Setup of Seam 2.0 Applications for Tomcat 6.0″ < @RequestParameter and @Observer usage | Ajax Magic with DataTables [...]
August 6, 2009 at 8:43 pm |
I am trying to pass parameter to initialize my Seam component on page request:
(pages.xml)
…
…
(SLB)
…
@RequestParameter(“type”)
private String _type;
@Create
public void method() {…}
…
When method() is executed the _type is null always.
Why is that? _type’s value is supposed to be already injected!..
Regards,
Andy.