Edem Morny’s Tech Blog

There’s a fine line between walking and flying. It’s called imagination.

Archive for the category “Seam”

AJAX Magic With JSF DataTables in Seam 2.0

<Seam 2.0 on Tomcat … | Seam Portlet Bridge Released >
RichFaces 3.1.3.GA came with a some new controls, and the <rich:listShuttle/> was of some interest to me. However, for a particular use case I found it not sufficient for my needs, and had to roll out my own version of it with a little bit of Ajax to add.

Let me use this simple scenario to display what I needed to do. Assuming you were keeping a shopping cart. After users select an item they want to buy, you want them to specify the quantity of that item following which their total charge is calculated for them on the fly. This I thought of doing using two DataTables just like the <rich:listShuttle/> appears but on a sleeker (or is it cruder?) level.

I defined an interface with a simple set of methods which I felt would do the trick called InPlaceEditing.

public interface InPlaceEditing {

void editSelection();

void addSelection();

void removeSelection();

void cancelSelection();

}

Here is my”shopper” Seam component which implements the interface. Notice the use of 2 DataModels “products” and “selectedItems” and their corresponding DataModelSelections. This is to enable me select from one table to another.

@Name(“shopper”)

@Scope(ScopeType.CONVERSATION)

public class Shopper implements java.io.Serializable, InPlaceEditing {

private boolean edit;

@In

EntityManager entityManager;

@In

FacesMessages facesMessages;

 

@DataModel

List<Product> products;

 

@DataModelSelection(“products”)

private Product product;

 

@DataModel

private List<CartItem> selectedItems;

 

@DataModelSelection(“selectedItems”)

private CartItem selectedItem;

 

@Out(required = false)

private CartItem cartItem;

 

private BigDecimal total = new BigDecimal(0.0);

 

private static int count = 0;

 

@Begin(flushMode=FlushModeType.MANUAL)

public void beginShopping() {

products = entityManager.createQuery(“Select p from Product p”).getResultList();

selectedItems = new ArrayList<CartItem>();

}

The beginShopping() method starts a conversation and FlushMode is set to MANUAL. This means that all changes made to entities will be made persistent only if I call flush() on entityManager. Seam defaults to AUTO which means all changes to all managed entities are merged into the persistence context after every Seam action call. Trust me, for the purposes of this trick, you DON’T want automatic persistence context merging! Anyway this action populates the “products” DataModel with products already entered into the database. The result is the table below.

<a:outputPanel id=”productPanel”>

<rich:dataTable value=”#{products}” var=”product”>

<h:column>

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

<a:commandLink value=”#{product.name}” actionListener=”#{shopper.editSelection}” reRender=”editPanel”/>

</h:column>

<h:column>

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

#{product.price}

</h:column>

<h:column>

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

#{product.stock}

</h:column>

</rich:dataTable>

</a:outputPanel>

Displayed editing panel

A look at the section of the shop.xhtml facelet shows an <a:commandLink/> – an Ajaxified version of the <h:commandButon/>. This supplies our “shopper” component with the selected product through the “product” data model selection through Ajax. Also take note of the “reRender” and <a:outputPanel/> tags, which specify which areas of our page should be Ajax refreshed after certain actions are called. In the editSelection() action a new CartItem (a join entity between a product and a shopping cart) containing the selected product is created and outjected.

public void editSelection() {

if (edit == false) {

cartItem = new CartItem();

cartItem.setId(count++);

cartItem.setProduct(product);

cartItem.setSelected(true);

return;

}

cartItem = selectedItem;

cartItem.setSelected(true);

edit = true;

}

I want to use the same action to represent selecting a new product (from “products”) and editing an already existing CartItem (from “selectedItems”). This is achieved with a private “edit” boolan field, which by default is false. Also since proper behaviour of DataModel and DataModelSelections depends on a properly implemented equals() method (i.e. instance uniqueness) I assigned artificial ids with the static “count” to each CartItem. Note that without setting flushMode to MANUAL, doing this will cause exceptions to be thrown down the lane somewhere. Finally setting the CartItem’s “selected” field to true enables the rendering of the panel in which the quantity of that product will be entered.

Displayed editing panel

 

DataTable with configured product

 

Once the quantity is specified, the addSelection() action is called. Because of the boolean “edit” we are able to determine if this is a new product selection or one from the existing list and respond appropriately, calculating the total cost of the users purchases so far and modifying the corresponding DataModels appropriately. In the case of an edit, the old computed cost of a product is deducted from the total, and re-computed and added to the total. To guarantee that the change in costs will reflect properly, the edited “cartItem” is removed and re-inserted in to the “selectedItems” DataModel.

It is also very easy to remove an already configured CartItem, again with the combination of <a:commandLink/> and the “selectedItem” DataModelSelection.

public void removeSelection() {

total.subtract(selectedItem.getCost());

selectedItems.remove(selectedItem);

}

Finally, the user may save their selection. This involves the creation of a new Cart object, which is persisted to get an ID and associated with the CartItems in the “selectedItems” DataModel. Note here that the fake Ids I generated for the CartItems will cause maximum trouble in the database, and so I set them to null to force the persistence context to generate proper Ids for them. Don’t forget the all important “entityManager.flush()” to make all changes permanent.

Completed Shopping

Finally I raise an event (“shopper.events.CartEdit”) which is being observed by the “shopList” Seam component’s list() action causing the “carts” DataModel to be refreshed with fresh data.

 

@Factory(“carts”)

@Observer(“shopper.events.CartEdited”)

public void list(){

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

carts = entityManager.createQuery(“Select c from Cart c”).getResultList();

}

Carts DataTable displaying products selected

The Job Is Done. This is use of Ajax and DataTables is quite simplistic, but I’ve used it in some really tight corners for some advance stuff. One scenario that I can see with this example is the requirement to remove a product from the list of products once selected and configured, or to put it back once it has been removed from the configured ones. Another will be how to edit an already persisted cart to remove or add products to that cart. I’ve just laid the foundation. With some tricks of your own, you should be able to achieve some serious magic.

NetBeans Setup of Seam 2.0 Applications for Tomcat 6.0″

< @RequestParameter and @Observer usage | Ajax Magic with DataTables >

Recently I’ve had need to begin developing a new application using Seam. However this time I’ve decided to go lightweight, so the obvious choice was Tomcat 6. I realized that the Seam plugin for NetBeans was limited to project generation for JBoss and so wasn’t an option. I decided to create everything on my own. Thankfully there is an example of the booking application with build scripts for Tomcat 6, Glassfish, WebLogic and WebSphere under jboss-seam-2.0.GA/examples/jpa. So here’s how you can set up yours work on Tomcat 6.

 

First, build the tomcat example by running ant tomcat6, which generates 2 folders – dist-tomcat6 and exploded-archives-tomcat6. With that done, create a library in NetBeans which you’ll add it to your project. I called mine “Seam4Tomcat” and added all the jar files in jpa/exploded-archives-tomcat6/jboss-seam-jpa.war/WEB-INF/lib.

Adding a library

Then create the project itself. Select the “Web Application” project type, specify Tomcat 6 as the target server and JavaEE 5 as the version of JavaEE. Next check Facelets as the framework to be used and create the project. Right click on the project and select “Properties”. Select “Libraries” on the left panel and “Add Library” to add your Seam4Tomcat (or whatever name you gave it) jars to your project. Remember to uncheck the Facelets related libraries provided by the NetBeans facelets support, since they are already in you newly added library.

Add library to project

Since the Seam filter needs to be installed to allow seam integration (as well as other configurations), just copy the contents of jpa/exploded-archives-tomcat6/jboss-seam-jpa.war/WEB-INF/web.xml and paste them in your web.xml file. You may change the <url-pattern> under the “Faces Servlet” servlet mapping to the url you want from the default “*.seam”.

 

Append this to the top of the web.xml file to add the blueSky RichFaces skin to RichFaces components you might use in the application.

 

<context-param>

<param-name>org.ajax4jsf.SKIN</param-name>

<param-value>blueSky</param-value>

</context-param>

 

Note that your faces-config.xml will already contain the reference to the Facelet view handler as well after creating the project.

 

Next, Seam gives you advanced navigation in its pages.xml file compared to JSF’s faces-config.xml file. To use it, just copy the jpa/exploded-archives-tomcat6/jboss-seam-jpa.war/WEB-INF/pages.xml into your WEB-INF folder. Also add the components.xml from the same directory to your WEB-INF folder. This is the most central file to any seam application and must always be there.

 

We’ll need to connect to some database to begin work with. So right-click your project, go to “New” and select “Entity Classes from Database”. We’ll assume no existing datasource and create one from an existing database connection. Drop down the “Data Source” combo box and select “New Data Source”. Enter a jndi name (mine is “jdbc/example”) and select the database connection. Enter the username and password for connecting to that database and your tables will be displayed.

Data source creation

Select the tables you want to generate entities for and click “Next”. You are then given the chance to edit the names of the Entities to be generated as well as specify the package within which they will be kept (mine is “example.entity”). NetBeans can generate named queries for you, but more importantly any JPA project needs a persistence unit. This consists of your entities and an ever so vital persistence.xml or orm.xml file.

 

Generating entities

Click the “Create Persistence Unit” button to create a persistence.xml file. Enter a persistence unit name (note the name you give. It will be used later). Specify your persistence provider – NetBeans comes with TopLink, but for Seam Hibernate is the better persistence provider. Note that I’ve changed the “Data Source” from “jdbc/example” to “java:comp/env/jdbc/example”. This is the fully qualified JNDI name that will be used by the container to resolve the EntityManager resource we’ll be injecting into our code. Since our database tables already exist, we’ll select “None” for “Table Generation Strategy” and click “OK”. We are finished with everything now and will click “Finish” to end the wizard.

View of persistence.xml

The preceding process creates two very important files: context.xml and persistence.xml files. Every resource that would be used in Tomcat should be declared in context.xml as a resource. Here is mine from the process above. You are free to tweak yours as the need may be.

 

<Context path=”/example”>

<Resource auth=”Container” driverClassName=”com.mysql.jdbc.Driver”

maxActive=”20″ maxIdle=”10″ maxWait=”-1″

name=”jdbc/example” password=”" type=”javax.sql.DataSource”

url=”jdbc:mysql://localhost:3306/knust” username=”edem”/>

</Context>

 

Here is my persistence.xml file as well. Note that I have changed the transaction-type to “RESOURCE_LOCAL” from “JTA”. However Seam provides JTA support for our application and therefore the <jta-data-source> declaration instead of <non-jta-data-source>. These must be exactly as it is here or your application will DEFINITELY give you errors.

 

 

<persistence-unit name=”exampleDatabase” transaction-type=”RESOURCE_LOCAL”>

<provider>org.hibernate.ejb.HibernatePersistence</provider>

<jta-data-source>java:comp/env/jdbc/example</jta-data-source>

<properties/>

</persistence-unit>

</persistence>

 

Now go back to your components.xml file. If you did copy the one from the exploded jpa example, you should have the following declaration in this file.

 

<core:manager conversation-timeout=”120000″

concurrent-request-timeout=”500″

conversation-id-parameter=”cid”/>

 

<transaction:entity-transaction entity-manager=”#{em}”/>

 

<persistence:entity-manager-factory name=”bookingDatabase”/>

 

<persistence:managed-persistence-context name=”em”

auto-create=”true”

entity-manager-factory=”#{bookingDatabase}”/>

 

<security:identity authenticate-method=”#{authenticator.authenticate}”/>

 

First things first. Replace all instances of “bookingDatabase” with the name of your persistence unit (I told you to take note of that – mine is “exampleDatabase”). Secondly, by giving the name “em” to all references to EntityManager and managed persistence contexts, it means that your code can only inject the EntityManager under the same name like so

 

@In EntityManager em

 

If you use a different name to inject it don’t say I didn’t tell you about the errors you’ll be getting. Alternatively you could change it to “entityManager” or whatever, just make sure that you use the same name as declared in components.xml throughout your code.

 

The last but often most forgotten thing that needs to be added is a seam.properties file. I can recount the number of times I’ve had nightmarish debugging sessions when a fresh application I’d just created to display Seam to someone didn’t work because of this file. In NetBeans, just right-click the project, select “New” and the “Properties file”. Call it “seam” and do not put it in any package (which puts it in default).

 

 

With all this done, you are good to go developing for Tomcat 6 using Seam. NetBeans offers some level of incremental deployment to Tomcat, detecting if Java classes have changed and redeploying the application. However, since NetBeans remotely deploy web applications to Tomcat, Tomcat will be reading from your project folder directly to deploy the application. This means that some changes like changes made to your facelets page will immediately appear on your web-browser. Just save the changes you make to a facelet, refresh your web browser and boom! For me that is enough. Tomcat deploys quickly and so redeploying when a Java class changes is not that painful.

 

Here’s an application I created to display this process to a mate. It’s got all the configurations files, some entities and Seam components to get you started.

 

Using @RequestParameter and @Observer events model in Seam

<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.

old dept list

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

new department creation

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.

Updated list of depts

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

Annoying NetBeans 6.0 Facelets Support Issue on Tomcat

Yesterday i got a call from a good friend of mine who has been dipping his fingers into JSF a bit. He’d decided to jump ship to using JSF on XHTML files, a technology known as Facelets. So he goes to download NetBeans 6.0 Facelets support plugin and installs it.

After developing a simple facelets page, he decides to deploy it to Tomcat 6.0.14 only to get BIG FAT class loader exceptions. What better way to treat a sceptic who is just getting into the game of web development in Java. These are the kind of things that can be so annoying about doing something in Java. Being a Seam advocate and user, I didn’t immediately realise what could have been the problem, since my Seam applications run fine using the jars from Seam.

After doodling around and making some changes to jars that came with the Facelets support, i just decided to ditch the jars from Facelets support and use my own. I picked the jars that come with Seam and VOILA! Problem solved. Makes me wonder if the guys who developed the plugin didn’t try to deploy it themselves AT LEAST to Tomcat before putting it out there. Anyways i just felt like putting up the solution to this simple but very annoying problem here for the sake of those who might try an introduction to Facelets.

Note that i got these jars from the JBoss Seam 2.0.GA’s lib folder. I can’t tell you where u can get them individually but downloading seam altogether will give you a change to start playing around with it if you haven’t started already.

Simply create a new Library in NetBeans by going to Tools->Libraries. I gave mine the name Facelets4Tomcat. Here are the jar files you need.

  • commons-beanutils.jar
  • commons-collections.jar
  • commons-digester.jar
  • commons-logging.jar
  • jboss-el.jar
  • jsf-api.jar
  • jsf-facelets.jar
  • jsf-impl.jar

This goes into your web.xml file.

<context-param>
<param-name>com.sun.faces.validateXml</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>javax.faces.DEFAULT_SUFFIX</param-name>
<param-value>.xhtml</param-value>
</context-param>
<context-param>
<param-name>facelets.DEVELOPMENT</param-name>
<param-value>false</param-value>
</context-param>
<context-param>
<param-name>facelets.SKIP_COMMENTS</param-name>
<param-value>true</param-value>
</context-param>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.jsf</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
<welcome-file-list>
<welcome-file>forward.jsp</welcome-file>
</welcome-file-list>

If you want to add the Ajaxified RichFaces components then add the following from the same Seam lib folder.

  • richfaces-api.jar
  • richfaces-ui.jar
  • richfaces-impl.jar

And add these to the top of your web.xml file

<filter>
<display-name>RichFaces Filter</display-name>
<filter-name>richfaces</filter-name>
<filter-class>org.ajax4jsf.Filter</filter-class>
</filter>
<filter-mapping>
<filter-name>richfaces</filter-name>
<url-pattern>*.jsf</url-pattern>
</filter-mapping>
<context-param>
<param-name>org.ajax4jsf.SKIN</param-name>
<param-value>classic</param-value>
</context-param>

You may use a different skin if you want. Check out the documentation for details

You may then add the library you created to your project by right clicking your web project and selecting “Properties”. At Libraries, click “Add Library” and selected the library you just created. Make sure that the check box is enabled or else it will not put the jar files in the right location i.e. WEB-INF/lib.

Oh, and MAKE SURE that the Facelets support libraries are unchecked, or else you’ll be back to square 1.

Happy Faceleting.

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.

 

 

Getting NetBeans 6.0 Ready for Seam Development

| Simple DataTable & Conversation Example

I’m starting a series of tutorials on web application development using the JBoss Seam framework. However, before I go on to that i’ll like to get started with setting up my favourite IDE – NetBeans for Seam development (sorry Eclipse folks, but I’m an addict. Just wishing that JBoss will see sense in working on a NetBeans version of the excellent JBoss Tools).

The following will be needed to follow this setup process
JDK 5 (6 is way faster to use) – http://java.sun.com
NetBeans 6.0 – http://www.netbeans.org
JBoss Seam 2.0 – http://labs.jboss.com/projects/download
JBoss Application Server (JBoss AS) 4.2.x – http://labs.jboss.com/projects/download
Seam plugin for NetBeans & Facelets Support – http://nbfaceletssupport.dev.java.net

I’ll assume that both the JDK and NetBeans are already installed. I’ll also assume that JBoss AS has been extracted into a suitable location, the JBOSS_HOME environment variable set and it has been added to your PATH variable.

In NetBeans, click the “Services” tab and right-click the “Servers” tree for the “Add Server” option.
NetBeans 6.0 Services Tab
Clicking that causes a “Add Server Instance” dialogue box to open up. This same result can be gained by selecting the “Tools” menu and selecting the “Servers” menu option, followed by the “Add Server” button. Select “JBoss Application Server” and in the Name field add the full name of the version of JBoss AS installed. This helps differentiate different instances of JBoss AS you might install. Currently mine reads “JBoss Application Server 4.2.1.GA”, reflecting the currently installed instance.
Supported servers in NetBeans
Clicking “Next” takes you to the next step to specify the location of the server. Mine is as shown below.
Location of Installed Server in NetBeans 6.0
The next step is to specify server configuration. The “default” domain is good enough for us and we’ll click “Finish” to conclude JBoss AS setup.
Configuring your instance of the server
Next is to add the Seam plugin for NetBeans. This is done by selecting the “Plugins” option from the “Tools” menu. NetBeans will scan all your installed plugins as well as establish an internet connection to find out available plugins. On the downloaded tab, click the “Add plugins” button. Navigate to the location of the Seam plugin for netbeans and click “Open” to add it. Click the “Install” button to install the Seam plugin.
Installing Seam plugin for NetBeans
Now specify where the Seam package you downloaded from have been extracted to. This saves you the trouble of having to specify it every time you use the Seam Generator to create a project. This can be done by selecting “Options” from the “Tools” menu and selecting the “Miscellaneous” icon. The “Seam Gen Framework” tab will allow to specify the location of Seam.

Seam Gen Configuration

The last thing to do is to install the NetBeans Facelets Support. Extract the nbfacelets-support. Following the previously described process, select all the nbm files included in nbfacelets-support zip archive.
Installing Facelets plugin for NetBeans
This ends the preparatory setup of NetBeans for Seam applications development. We’ll tackle some simple applications next on this series after this short commercial break.

Post Navigation

Follow

Get every new post delivered to your Inbox.