Advertisement

CRUD APPLCATION FRAMEWORK IN SEAM

Seam is an application framework which makes development easy, by simplifying integration of existing frameworks, and making use of POJOs and annotations. It provides new stateful scopes, especially conversation, and adopts and extends the EJB3 model of extended- persistence context to provide application-scoped transaction support. This simplifies creation of applications that require multi-page user interactions.eg shopping carts. Seam does not stop with this. For basic database access in a web application, Seam provides a set of pre-built component templates, which can be re-used. The Seam documentation calls these classes as Seam Application Framework. We will call this as CRUD framework to avoid ambiguity. This “framework within a framework” reduces the amount of code you need to write when doing basic database access in a web application, using either Hibernate or JPA. In other words the inner framework is a handful of simple classes that reduce the code for performing create, read, update, and delete operations on entity instances and querying for data; if we don’t use them, the code required for performing the operations is more. For an earlier article, for creating a database-based web application, all that we did was creation of a table in a database and execution of few commands. The commands “seam setup” and “seam create-project” make use of the larger framework while the command “seam generate” the inner framework. We obtained a full-fledged running application with no code from us. The CRUD framework essentially provides prepackaged Data Access Objects (DAOs). Home is one of the DAO classes provided by Seam and is influenced by ActiveRecord of Rails -but a modification of it or even an improvement over it. We will look into the “Home” class and the crucial role played by it in the CRUD operations in the course of this article.

Example contactList application: To understand things better, at first we will have a look at contactlist application in the examples folder of in Seam distribution. We can build and deploy it, if you have Ant installed and ANT_HOME system variable set - as example applications come with build.xml files. You may have to edit the jboss.home variable in sample.build.properties file in jboss-seam\build folder. Ant will build the ear file and if there is some problem in deploying, you can manually copy the ear file and start JBoss and go to the browser and type http://locahost:8080/seam-contactlist and you will get Figure 3.If you fill Dan in First Name and click Search, You will get Figure 4.If you click Create New Contact tab you will get Figure 5.If you have a look at the source code there are only two java files Comment.java and Contact.java –both entity files. You can’t find the definitions for the methods create(),persist() or any other method required for a database operations in these classes. The controller classes supplied by the CRUD framework provide the methods necessary for database operations and they are packaged in jboss-seam.jar file. The hierarchy of controller classes in the CRUD framework is given in Figure 1:

The Controller, Persistence Controller, Home and Query classes are abstract classes and there are two implementations for Home and Query classes, to use JPA and Hibernate. We are seeing in the above figure the JPA implementations. The source code EntityHome.java is reproduced below and you can see that it contains the methods necessary for database access and understanding the code is not essential for using the class and the methods it defines.

EntityHome.java

package org.jboss.seam.framework;

import javax.persistence.EntityManager;
import javax.transaction.SystemException;
import org.jboss.seam.persistence.PersistenceProvider;
import org.jboss.seam.transaction.Transaction;
import org.jboss.seam.transaction.UserTransaction;

// Referenced classes of package org.jboss.seam.framework:
//            Home

public class EntityHome extends Home
{

    private static final long serialVersionUID = 0xd46c243e2cb30b98L;

    public EntityHome()
{
}

    public void create()
{
super.create();
if(getEntityManager() == null)
{
throw new IllegalStateException("entityManager is null");
} else
{
return;
}
}

    public boolean isManaged()
{
return getInstance() != null && getEntityManager().contains(getInstance());
}

    public String update()
{
joinTransaction();
getEntityManager().flush();
updatedMessage();
raiseAfterTransactionSuccessEvent();
return "updated";
}

    public String persist()
{
getEntityManager().persist(getInstance());
getEntityManager().flush();
assignId(PersistenceProvider.instance().getId(getInstance(), getEntityManager()));
createdMessage();
raiseAfterTransactionSuccessEvent();
return "persisted";
}

    public String remove()
{
getEntityManager().remove(getInstance());
getEntityManager().flush();
deletedMessage();
raiseAfterTransactionSuccessEvent();
return "removed";
}

    public Object find()
{
if(getEntityManager().isOpen())
{
Object result = loadInstance();
if(result == null)
{
result = handleNotFound();
}
return result;
} else
{
return null;
}
}

    protected Object loadInstance()
{
return getEntityManager().find(getEntityClass(), getId());
}

    protected void joinTransaction()
{
if(getEntityManager().isOpen())
{
try
{
Transaction.instance().enlist(getEntityManager());
}
catch(SystemException se)
{
throw new RuntimeException("could not join transaction", se);
}
}
}

    public EntityManager getEntityManager()
{
return (EntityManager)getPersistenceContext();
}

    public void setEntityManager(EntityManager entityManager)
{
setPersistenceContext(entityManager);
}

    protected String getPersistenceContextName()
{
return "entityManager";
}

    protected String getEntityName()
{
return PersistenceProvider.instance().getName(getInstance(), getEntityManager());
IllegalArgumentException e;
e;
return null;
}
}

You can simply adopt the EntityHome for any entity, for example Contact, by extending the EntityHome and passing on the name of the entity as a parameter as shown below:
@Name("contactHome")
public class contactHome extends EntityHome<Contact> 
{
}
The above code is sufficient and the view files can now access the create() persist() etc methods  implemented in EntityHome class. You can also use xml to adopt EntityHome for an entity. The contactlist application uses xml to adopt EntityHome for the Entity Contact.  Look at following extract from resources\WEB-NF\component.xml.

 

<            factory name="contact" value="#{contactHome.instance}"/>//---------------2)
<fwk:entity-home name="contactHome"
             entity-class="org.jboss.seam.example.contactlist.Contact"/>  //---1)
…….
<fwk:entity-query name="contacts"
max-results="5">
<fwk:ejbql>select c from Contact c</fwk:ejbql>
<fwk:order>lastName</fwk:order>

1) See the use of the tag <fwk:entity-home> which takes two attributes name and entity-class. In the view files, the attributes are  accessed through instances of the entity-class.ie  attribute firstName in the Contact entity can be accessed from the facelets file through EL as "#{entityHome.instance.firstName}".
2)To simplify access from facelets, the factory method is used to give the instance a simple name eg contact. Now the above attribute can be accessed with the simplified name in EL "#{contact.firstName}".

 But the methods create() persist() etc. cannot be accessed from the instance but from the entityHome component only as can be seen from the extract from the file editContact.xhtml from the above application.

<s:decorate id="firstNameDecorate"><h:inputText id="firstName" value="#{contact.firstName}" required="true"/></s:decorate>//--atrribute access
              ……

 

<h:commandLink id="createContact" action="#{contactHome.persist}" //…method access
value="Create Contact" rendered="#{!contactHome.managed}"/> 

Home template    What is the purpose of the Home? As mentioned earlier, Rails exerted a great influence on Seam. In the Active Record pattern followed in Rails the domain object is responsible for saving and retrieving itself  from the database. Thus, in addition to encapsulating data, it encapsulates data access logic.. So Seam also did not favor anemic domain model, where-in domain objects were treated only as buckets for holding data. But the Active Record pattern bears a close resemblance to Ejb2 entity beans. Because of the tight coupling of the domain object to the framework in this model and the success of the POJO, Seam did not want to follow this pattern entirely. It designed a solution influenced by ActiveRecord pattern but based on POJOs. The Home class plays an important role in this solution.
A Home encapsulates the entity instance and the persistence manager, facilitating communication between them without making them aware of each other, as shown in the figure 2.

To the outside world, this domain object appears as a single unit, allowing the domain model to be “active” without contaminating the entity class with data access logic. The pattern followed by Seam resembles Mediator Design pattern. A Home uses the persistence manager to manipulate the persistence state of the entity instance it manages. To coordinate these state transitions, the Home performs the well-known CRUD operations by delegating the work to the persistence manager. This encapsulation and delegation is makes the Home pattern a good object-oriented design. The Mediator pattern sets the Home apart from the entity instance itself, and the Home is both transactional and stateful. ie Home works with Seam managed persistence context and provides transaction support to the entity instance. This transparent management of the entity instance is the quintessence of stateful behavior and is claimed to be more “active” than what the Active Record pattern affords.

Create a Project    Create a table person with the following fields: 1) id int auto-increment 2) username varchar(20) notnull 3) name varchar(20) notnull. Create a seam project by name seamcrud by executing the command seam setup and seam create-project. Open the project with NetBeans. If you execute the command seam generate necessary files be generated by reverse engineering from the tables without any code from us. But to learn things it is better if we customize the generated code. So execute the command seam new-entity. It will ask for the entity class name. You can give the name Person. You can accept the default values suggested for the other queries. We can open the files in the IDE and customize them.
The seam-gen generated entity will have Long id Integer version and String name attributes and getters and setters for the same. We can modify the code for the following: Integer id, String name, String username. The modified code may look as under:

Person.java

package com.mydomain.myproject.model;

import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.GeneratedValue;
import javax.persistence.Version;
import org.hibernate.validator.Length;

@Entity
public class Person implements Serializable
{
private Integer id;
private String username;
private String name;

 

    @Id @GeneratedValue
public Integer getId() {
return id;
}

    public void setId(Integer id) {
this.id = id;
}

     @Length(max = 20)
public String getUsername() {
return name;
}

    public void setUsername(String usersname) {
this.username = username;
}
@Length(max = 20)
public String getName() {
return name;
}

    public void setName(String name) {
this.name = name;
}

}

   The code generated for PersonHome.java requires only a small modification. After deletions the code may look as under:


Person.java

package com.mydomain.myproject.action;

import org.jboss.seam.annotations.Name;

import org.jboss.seam.framework.EntityHome;

import com.mydomain.myproject.model.Person;

@Name("personHome")
public class PersonHome extends EntityHome<Person>
{

}

You can see that the class is empty.

PersonList.java  You can also have a look at the code for PersonList.java.

PersonList.java

package com.mydomain.myproject.action;

import org.jboss.seam.annotations.Name;
import org.jboss.seam.framework.EntityQuery;
import com.mydomain.myproject.model.Person;

@Name("personList")
public class PersonList extends EntityQuery<Person>
{
public PersonList()
{
setEjbql("select person from Person person");
}
}

You can also look at the following extract from personList.xhtml which accesses the resultList from the above component. The resultList is one of the objects obtained by it from EntityQuery.

<h:dataTable id="personList" var="person"
value="#{personList.resultList}"
rendered="#{not empty personList.resultList}">
<h:column>

personList.xhtml may be modified. The following portion may be copied

 

         <h:column>
<f:facet name="header">Name</f:facet>
<s:link id="person"  //-------------1)
value="#{person.name}"
propagation="none"
view="/person.xhtml">
<f:param name="personId"  //----2)
value="#{person.id}"/>
</s:link>
</h:column>

  1. See how <s:link> is used.
  2. See how personId passed on through <f:param>

The copied portion  may be pasted  and modified for username as under:

 

<h:column>
<f:facet name="header">User Name</f:facet>
<s:link id="person"
value="#{person.username}"
propagation="none"
view="/person.xhtml">
<f:param name="personId"
value="#{person.id}"/>
</s:link>
</h:column>

The change required in person.xhtml is as follows: The portion  of the file for getting input for name is given hereunder:

 

<s:decorate id="nameField" template="layout/edit.xhtml"> //--------1)
<ui:define name="label">Name</ui:define>
<h:inputText id="name" required="true"
value="#{personHome.instance.name}"/>//-----2)
</s:decorate>

  1. See how input is obtained within <s:decorate>
  2. The input is set in name attribute of instance of personHome.

  The same may be copied and modified for username as under:

 

<s:decorate id="usernameField" template="layout/edit.xhtml">
<ui:define name="label">User Name</ui:define>
<h:inputText id="username" required="true"
value="#{personHome.instance.username}"/>
</s:decorate>

Run the Application Now you can go to the command prompt and type seam explode. You can start the server and go to the Browser and type http://localhost:8080/seamcrud and see the result as in Figure 6 and if you click Create Person button and fill up the text boxes you may get Figure 7.If You click Save button you may get “Successfully created” message.

 

 








Added on February 27, 2012 Comment

Comments

#1

Www.Bofigo.com commented on July 27, 2013 at 12:34 a.m.

Hello, Neat post. There is a problem together with your web site in web
explorer, may test this? IE still is the marketplace chief and a huge element of folks
will omit your excellent writing due to this problem.

#2

kaliteli commented on August 1, 2013 at 11:18 a.m.

Greetings!

#3

kaliteli Pelu_ Oyuncaklar commented on August 7, 2013 at 5:27 p.m.

After exploring a handful of the blog posts on your web
page, I really like your technique of writing
a blog. I book-marked it to my bookmark site list and will be checking back in the near future.

Please check out my web site too and tell me how you feel.

#4

ucuz Besin Haz_rlay_c_lar commented on August 15, 2013 at 8:16 p.m.

I visited multiple web sites however the audio feature for audio songs current at
this website is genuinely fabulous.

Post a comment