Seam: Simple Data Table & Conversation Example

<Getting NetBeans 6 … | Using @RequestParameter and @Observer …>

We’ll start off the new year running our series on Seam. In this post, we’ll deal with data in a table and with conversations. We’ll first try to model a university environment, something I know will come handy on this or some campus sometime.

 

Let’s assume that we had to capture Faculties, Departments and Courses in our system. Here, of course a course is run by a department, which in turn belongs to a faculty. This is our department entity

 

@Entity

@Table(name=”faculty”)

@Name(“faculty”)

public class Faculty extends Model implements Serializable {

 

private Integer id;

private String name;

private String dean;

private String office;

private List<Department> departments = new ArrayList<Department>();

 

public String getDean() {

return dean;

}

 

public void setDean(String dean) {

this.dean = dean;

}

@OneToMany(mappedBy=”faculty”,cascade=CascadeType.ALL)

public List<Department> getDepartments() {

return departments;

}

 

public void setDepartments(List<Department> departments) {

this.departments = departments;

}

 

public String getOffice() {

return office;

}

 

public void setOffice(String office) {

this.office = office;

}

 

@Id

@GeneratedValue

public Integer getId() {

return id;

}

 

public void setId(Integer id) {

this.id = id;

}

 

@Length(max = 20)

public String getName() {

return name;

}

 

public void setName(String name) {

this.name = name;

}

 

Don’t forget to override equals() and hashCode() as well. NetBeans can easily generate these for you using Alt + Insert.

 

Our list of faculties will be displayed on a facultyList.xhtml using the following facelet section, displaying only the id and names of each faculty.

 

 

<rich:dataTable id=”facultyList” var=”faculty” value=”#{faculties}”

rendered=”#{not empty faculties}”>

 

<h:column>

<f:facet name=”header”>Id</f:facet>

#{faculty.id}

</h:column>

<h:column>

<f:facet name=”header”>Name</f:facet>

<s:link id=”faculty”

value=”#{faculty.name}”

action=”#{facultyListing.showDetails}”/>

</h:column>

</rich:dataTable>

 

</div>

List page

 

The “faculties” is a List of Facultys with a @DataModel annotation. However the list can be initialized (for the first time only) by using a @Factory annotation on any method as follows.

 

@Stateful

@Name(“facultyListing”)

@Scope(ScopeType.SESSION)

public class FacultyListBean implements FacultyList {

 

@PersistenceContext(type=PersistenceContextType.EXTENDED)

EntityManager em;

 

@DataModel

List<Faculty> faculties;

 

@DataModelSelection

private Faculty faculty;

 

@Factory(“faculties”)

public void facultyList(){

faculties = em.createQuery(“Select f from Faculty f”).getResultList();

}

 

public void showDetails(){

faculty.setSelected(true);

}

 

 

I hope I don’t have to remind you that a Stateful EJB must have a method annotated with @Remove as well as Seam’s @Destroy annotation. Our Seam component “facultyListing” is also a session scope component, which preserves the DataModel “faculties” at session scope and makes it available to the page all through the user’s interaction with it.

 

The Faculty object annotated with @DataModelSelection enables us to select a faculty and inject it into this object, passing it to our “facultyListing” Seam component. This is possible with the <s:link on the facelet. The faculty’s “selected” property is set to true, which enables us to redisplay the details of the selected faculty on a different panel as ff:

 

<rich:panel rendered=”#{faculty.selected}”>

<f:facet name=”header”><h:outputText value=”#{faculty.name}”/></f:facet>

<h:panelGrid columns=”2″>

<h:outputLabel for=”office” value=”Office” style=”font-weight:bold”/><h:outputText id=”office” value=”#{faculty.office}”/>

<h:outputLabel for=”dean” value=”Dean” style=”font-weight:bold”/><h:outputText id=”dean” value=”#{faculty.dean}”/>

<h:outputLabel for=”departments” value=”No. of depts” style=”font-weight:bold”/><h:outputText id=”departments” value=”#{faculty.departments.size()}”/>

</h:panelGrid>

</rich:panel>

 

list_page_details.jpg

OK, enough with the gimmicks on data in a table. What about if you want to create a new “Faculty”? Well, there the power of conversations in Seam comes in.

 

Clicking the “Create faculty” button begins a conversation, which can be considered a series of steps needed to be taken before a process is complete.

 

@Stateful

@Name(“facultyManager”)

public class FacultyManagerBean implements FacultyManager {

 

@In

EntityManager entityManager;

 

@Out

private Faculty faculty;

 

@Begin

public String createFaculty() {

faculty = new Faculty();

return “success”;

}

 

 

@End

public String saveFaculty() {

entityManager.persist(faculty);

Contexts.getSessionContext().set(“faculties”, null);

return “success”;

}

 

The “facultyManager.createFaculty()” (annotated with @Begin) begins a seam conversation and the navigation rule defined takes us to the faculty.xhtml facelet if “succes” is returned. This method initializes the “faculty” object whose fields will be populated on the faculty.xhtml facelet and outjects it to the scope of the “facultyManager”, in this case conversation scope.

 

<page view-id=”/facultyList.xhtml”>

<navigation from-action=”#{facultyManager.createFaculty}”>

<rule if-outcome=”success”>

<redirect view-id=”/faculty.xhtml”/>

</rule>

</navigation>

</page>

 

You can now provide the details required to create a new faculty. Note the s:decorate around each field. This allows us to specify how the fields will be laid, defined in a template file. It also enables validation of fields based on Hibernate Validator annotations defined on fields of an entity eg the @Email and @Length annotations. The a4j:support tag forces this validation to be done by AJAX, based on the occurrence of some events, in this case “onblur”. Adding AJAX support to JSF components is quite easy – the RichFaces documentation shows you how.

Ajaxified editing

 

Validated edit

Clicking on the “Save” button causes the “facultyManager.saveFaculty” method to be called, forcing us to now persist the entity to the database. To update the list of faculties being displayed on the “facultyList.xhtml” page, we set the “faculties” DtaModel to null. This forces Seam to repopulate it by calling the Factory method initializing the list again. Returning “success” causes the redisplay of the facultyList.xhtml facelet with the reloaded faculties and the job is done.

Updated list

 

I believe that with this it will be easy to implement the Departments and Courses list as well. We’ll continue next time.