Accra Seam Seminar Update
April 1, 2008In my haste to announce the seminar I forgot to add the time. Its between 3:30pm and and 5:00pm. Date again is 24th April at AITI-KACE, Accra.
See ya there.
In my haste to announce the seminar I forgot to add the time. Its between 3:30pm and and 5:00pm. Date again is 24th April at AITI-KACE, Accra.
See ya there.
One of the reasons why I’ve come to love Seam is that it really lives up to its appellation as a programming and integration model – because of its ability to let me use technologies which are complex in their own right without the need to learn the nitty gritty of them. One example is the use of facelets for email, something which if I had to do programmatically using the JavaMail API will be quite a hell. With Seam all I have to learn are new facelets tags related to email. I still have access to my Business Process, Application, Session,Conversation etc contexts and can use resources from these contexts just like a normal facelet which generates a web page. Another one is pdf rendering, and that is what we’ll be talking of today.
I’ll use the shopper application that I developed for my previous post on AJAX, DataTables and Seam. Before we go on though, let’s not forget to mention the need for the following jar files in your classpath as per Chapter 16 of the Seam reference manual.
itex.jar
jboss-seam-pdf.jar
Next add these declarations to your web.xml file
<servlet>
<servlet-name>Document Store Servlet</servlet-name>
<servlet-class>org.jboss.seam.pdf.DocumentStoreServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Document Store Servlet</servlet-name>
<url-pattern>*.pdf</url-pattern>
</servlet-mapping>
And these to your components.xml file, making sure the namespace is properly declared
<pdf:document-store use-extensions="true" />
Since we will be using charting from JFreeChart, we need to add these additional jars.
jcommon.jar
jfreechart.jar
I’ve decided to add two links that render pdf documents. One provides a pie chart of the products held in my database and their stock levels. Very simple use case, since all I have to do is to select the products I’m interested in into an ArrayList and display them.
public List<Product> getProductView(){
return entityManager.createQuery("Select p from Product p").getResultList();
}
Here is the section of the facelet that displays the contents of the resulting ArrayList.
<p:image alignment="right" wrap="true" value="/jboss.jpg" />
<p:font id="test" size="24"><p:paragraph spacingAfter="50">Chart</p:paragraph></p:font>
<p:piechart title="Product Stock Levels" width="500" height="350" legend="true" is3D="true" plotForegroundAlpha=".25">
<ui:repeat value="#{shopList.productView}" var="item">
<p:data key="#{item.name}" value="#{item.stock}" />
</ui:repeat>
</p:piechart>
Now that the easy one is out of the way, lets look at the second link. This is to render a table telling us the date a cart was created, the total cost and the number of products in that cart. Well, date and cost fields are already declared on the Cart entity we created and we could do cart.getCartItems().size and get the number of products in each cart. But I decided to use a less talked about feature of JPA – native queries. Native queries enable us write SQL statements to retrieve records in our database that may not have been captured, modelled or contained in an existing entity. These allow us to write very complex queries and apply aggregation functions and so on on data.
We begin by first examining our query
select cart.date_created as date,cart.cost as cost, count(cart_item.product_id) as products from cart left join cart_item on cart_item.cart_id=cart.id group by date
Hmm. We have three aliases/fields being fetched from the database. JPA requires the declaration of an @SqlResultSetMapping which assigns a name to a native query and the fields that will be fetched from that native query. I decided to declare mine on the Cart entity, though I could have declared it on any entity.
@SqlResultSetMappings({
@SqlResultSetMapping(
name = "productStock",
columns = {
@ColumnResult(name = "date"),
@ColumnResult(name = "cost"),
@ColumnResult(name = "products")
})}
Having sorted out what I want to fetch and meeting JPA’s requirements on declaring a @SqlResultSetMapping, I now go on to fetch the data using the entityManager.
public List<Map> getCartView(){
List<Object[]> results = entityManager.createNativeQuery(
"select cart.date_created as date,cart.cost as cost, count(cart_item.product_id) as products from cart left join cart_item on cart_item.cart_id=cart.id group by date","productStock").getResultList();
List data = new ArrayList<HashMap>();
if (!results.isEmpty()) {
for (Object[] result : results) {
HashMap resultMap = new HashMap();
resultMap.put("date", (Date)result[0]);
resultMap.put("cost", result[1]);
resultMap.put("products", result[2]);
data.add(resultMap);
}
}
return data;
}
There are lot of things to note here.
We use entityManager.createNativeQuery(), not entityManager.createQuery().
After stating the query, you must also give the name of the named query which you defined in the SqlResutSetMapping. Ours is “productStock”.
Each row/record of data fetched from the database is assigned to an Object array. In this case “date” is in the 0th index, “cost” is in the 1st and so on. Since I’m fetching more than one, I use entityManager.getResultSet() and assign to a List.
Expression Language( EL) allows us to refer to data in a Map by its key, and that feels more natural to me on my facelet than referring to indexes of an array, so I rather iterate through my “results” List, creating a HashMap for each row/record from the database and using appropriate names to refer to the fetched data.
Now here’s the facelet that renders the table containing our records.
<p:image alignment="right" wrap="true" value="/jboss.jpg" />
<p:font id="test" size="24"><p:paragraph spacingAfter="50">Table</p:paragraph></p:font>
<p:table columns="3" headerRows="1">
<p:cell ><p:paragraph alignment="center">Date</p:paragraph></p:cell>
<p:cell><p:paragraph>Cost</p:paragraph></p:cell>
<p:cell><p:paragraph>No. of products</p:paragraph></p:cell>
<ui:repeat value="#{shopList.cartView}" var="data">
<p:cell><p:paragraph><p:text value="#{data.date}"><f:convertDateTime dateStyle="medium" type="both"/></p:text></p:paragraph></p:cell>
<p:cell><p:paragraph>#{data.cost}</p:paragraph></p:cell>
<p:cell><p:paragraph>#{data.products}</p:paragraph></p:cell>
</ui:repeat>
</p:table>
Explaining each of the individual tags on this facelet is out of the coverage area of this post and further details can be gleaned from the Seam Reference Manual. However using EL, I can just refer to the date field as #{data.date} and so on and we will all be none the wiser. Of particular interest is the use of the <p:text/> tag. It allows us to apply JSF formatting/conversion etc on data being rendered in a PDF, and here we needed to format the date using the f:convertDateTime. Another use of this is to determine if some data will be rendered using the standard “rendered” JSF component attribute.
The combination of bijection and contexts means that Seam can always find whatever I’m referencing in its appropriate context and display it for me, whether on a facelets web page, PDF, email or in an asynchronous process.
Added on 7th April 2008
Give the code a spin and see.
As part of efforts to create a greater awareness of enterprise java technologies and tools especially on JBoss Seam, I’ve been able to secure a seminar on the 24th April 2008 at the Kofi Annan Center (AITI-KACE), Accra Ghana. This is part of their Technology Transformation Seminar that they organise to talk about trends and technologies in IT.
The seminar is titled “Stateful, Secure Enterprise Applications with JBoss Seam” and as the title suggests will be centered on the use of the Seam framework in web-based enterprise application development.
Looking forward to meeting all interested “Seamers” there. Will make the slides available on this blog after the seminar. Thanks in advance to AITI-KACE for the opportunity.
My next post will be focusing on PDF report generation and subsequently a look at the new feature of natural conversations. Keep your eyes on the ball.
I was glad last week when I heard that the JBoss Portlet Bridge has been released for deploying Seam projects in JBoss Portal.
I’ve been waiting for this for a while, since I find the idea of portals very interesting. I evaluated the SeamBookingPortlet example that comes with this release and its not bad. Looking forward to the opportunity to develop applications for a business in a portlet fashion, and will be blogging on my portlet learning experiences.
The last milestone I’m waiting for is the ability to deploy JBoss Portal on Tomcat, a feature which can only be available after the completion of the JBoss 5 project which includes the new JBoss Microcontainer. This feature will enable JBoss apps like JBoss Portal to be deployed on Tomcat.
JBoss, speed it up.
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>
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.
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.
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();
}
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.
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.
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.
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.
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.
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.
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.
I’ve been following a bit the JVM languages that are struggling for pole position in the blogosphere of late. And the more time passes the more I’m convinced that the JVM is here to stay, even if folks might not be too happy about the Java language itself.
The stability of the JVM as well as the number of different technologies and APIs that it has evolved has made it a good breeding ground for languages that haven’t had the wide level of adoption as Java. Now with a greater push to support languages like Ruby (JRuby), Python (Jython) and totally new ones like Groovy and Scala, developers can still eat their cake and have it. There are even comments that JRuby is even faster than native Ruby, taking away the JVM startup time. And NetBeans is fast becoming the IDE for Ruby development. Support for other languages is being worked on aggressively in the IDE.
The focus on stability and platform independence is now reaping off for Sun Microsystems, and I’m happily exploring my options of getting on the bandwagon of new static and non-statically typed languages. The ability to still use all these language features as well as plugin to the technologies that Java and JVM already provide is very enticing.
Scala I must say looks very advanced and promising. A friend of mine said that sometimes exploring the language frightens him a bit because of the level of new, advanced and easy to use language features which are far from being just syntactic sugar. Scala is a statically typed language like Java, but it’s feature set is amazingly richer than Java’s. It is 100% compatible with Java. There’s a lot of noise on the blogosphere if Scala might not become the next flagship language for the JVM if Sun decides to move on from Java. Whichever they finally decide to choose, it will only be further to the advantage of the Java ecosystem.
The Scala support in IDEs is not as advanced as other languages like JRuby and Groovy. Here you’ll find a plugin for Groovy development in NetBeans. I’ve tried writing a few scripts with Groovy to get my feet wet and I’m beginning to enjoy it. This is basically because Groovy is so much like Java and the learning curve is not as steep. That is good for me, who hasn’t tried Ruby or Python before. My only issue is that IDE the support has not yet gotten to the point where I can productively use it in a project. However, I’m yet to explore the Eclipse support for it. Might be more advanced.
Proposals for JDK 7 include easy integration between Java and other JVM languages at JVM level. All the better I’d say. Fingers crossed, the JVM isn’t dieing anytime soon. It’s only getting better because unlike companies like Microsoft who just focus on doing things to please developers and gain market shares, Sun Microsystems takes it time to think throught the implications of it’s technology decisions, knowing that the future is what will vindicate it.
It turns out the problem with NetbBeans 6.0 not rendering well when desktop effects are enabled in Fedora 8 has been solved at the JDK level. Just upgrade to JDK 6 update 4 from Sun. Now my NetBeans will enjoy being wobbled about.
Oh and i just discovered JavaDB (or more popularly Derby) is bundled with JDK 6. Didn’t quite notice its existence. And with the latest JDK it comes with documentation on how to use it in your apps. This is good for simple applications that need to bundle some small database to work with. Congrats to Sun.
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.
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.
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.
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.