Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Defne, RichFaces, JSF, JPA and CDI: Nice Combo for Java EE Web Application

DZone's Guide to

Defne, RichFaces, JSF, JPA and CDI: Nice Combo for Java EE Web Application

· Java Zone
Free Resource

Download Microservices for Java Developers: A hands-on introduction to frameworks and containers. Brought to you in partnership with Red Hat.

Defne is a service oriented web application framework. The main motivation behind Defne is ease of use. Defne allows developers to concentrate on their business logic while it provides all other application requirements such as transaction and security. With Defne, you can implement Java EE based business logics easily.

RichFaces is a component library for JSF and an advanced framework for easily integrating AJAX capabilities into business applications.

Apache OpenWebBeans/CDI is a  Contexts and Dependency Injection for the Java EE platform.

In this article, we are going to see how one implements a real  Java EE web application using JBoss RichFaces, Apache OpenWebBeans  and Defne libraries together. While RichFaces provides powerful AJAX capable GUI components, Defne provides implementation of the business services with service oriented fashion.  Never need a bunch of configuration files for JSF managed beans, because all of the bean creations and dependecy injections are handled by OpenWebBeans, thanks to Java EE standards!

Requirements

In this article we use SIwpas, http://code.google.com/p/siwpas, Simple Web Profile Application Server that contains all necessary libraries. If you wish to use Tomcat, Jetty or any other application server, you have to bundle necessary libraries with your application or server classpath.

Defne libraries can be downloaded from  http://code.google.com/p/defne/. JBoss RichFaces libraries can be downloaded from http://jboss.org/richfaces.

In this application, we use maven tool for or build tool. All dependencies of the application are defined in "pom.xml" files.

Sample Web Application

In this article, our application is a reservation web application that provides the following features;

  • Registration of users, (admin and normal users)
  • Admin user defines hotels and search for reservations,
  • Normal users can reserve hotels, update informations etc.
  • Security is handled by JSF phase listener approach
Here is the login page of the application,

 

And reservation page for the normal user. We use this page for the article. Here you see JBoss RichFaces Panel, Menu and Date components.

Modules of The Application

Application is architectured as several layers,

  • GUI Layer           : It contains JSF managed beans (actually CDI managed beans). Those beans are used by JSF pages via EL expressions,
  • Model Layer       : It contains JPA entity classes and JPA main configuration file i.e, persistence.xml,
  • Utility Layer       :  It contains utility classes that are used by all other layers,
  • Business Layer : It contains Defne Business Services that are interacted with backend database.

GUI Layer
This layer contains JSF/CDI managed beans. They have connected with JSF page using Expression Language method/value binding expressions. For example, following is the part of the "UserReservationBean"  that is ConversationScoped CDI managed bean.

@Named
@ConversationScoped
public class UserReservationBean implements Serializable
{

.........
.........

private @Inject @PojoExecutorProxy IServiceExecutorProxy serviceExecutor;

private @Inject Conversation conversation;

private @Inject SessionTracker tracker;

public UserReservationBean()
{

}


public String addReservation()
{
if(getReservationDate() == null)
{
JSFUtility.addErrorMessage("Reservation date can not be empty!", "");
return null;
}


if(conversation.isTransient())
{
conversation.begin();

JSFUtility.addInfoMessage("Reservation conversation with started with id : " + conversation.getId(), "");
}

Hotel hotel = (Hotel)model.getRowData();

SelectItem item = new SelectItem();
item.setValue(hotel.getId());
item.setLabel(hotel.getName());

if(contains(item.getValue()) != null)
{
JSFUtility.addErrorMessage("Given hotel is already added", "");

return null;
}

reservations.add(item);


ReservationModel model = new ReservationModel(hotel.getId(),reservationDate);
models.put(item.getValue().toString(), model);

return null;
}

public String checkout()
{
if(conversation.isTransient())
{
JSFUtility.addErrorMessage("Conversation is not running! Please add hotel for reservation", "");
this.reservations.clear();
this.reservationDate = null;
}
else
{
Message inBag = MessageFactory.newMessage(IUserService.SERVICE_NAME,IUserService.ADD_RESERVATION.METHOD_NAME);
inBag.putMessageParameter(IUserService.ADD_RESERVATION.INPUT.RESERVATIONS, models);
inBag.putMessageParameter(IUserService.ADD_RESERVATION.INPUT.ID, tracker.getUser().getId());

this.serviceExecutor.execute(inBag);

conversation.end();

JSFUtility.addInfoMessage("Reservation are completed succesfully. Conversation with id "+conversation.getId() + " is ended ", "");

this.reservations.clear();

this.reservationDate = null;
}

return null;
}
......
......
}

UserReservationBean is a @ConversationScoped bean. Developers start conversation with Conversation.begin() method and end its lifecycle with Conversation.end() method. Here, user adds hotels into the list and starts the conversation,  if  it has not been already started. When user checks out(clicks checkout button) the reservations, conversation is ended/destoyed at the end of the current JSF request and hotels are reserved for the user. Conversations enable the users to open different tabs on the same internet browser page!!!

Each conversation has an unique id for current user session. Under the hood, each conversation instance is saved in user session with those unique conversation ids.

The conversation context is provided by a built-in context object for the built-in passivating scope type @ConversationScoped. The conversation scope is active:

  • During all standard lifecycle phases of any JSF faces or non-faces request
The conversation context provides access to state associated with a particular conversation.

Most important part is the @Injection part and service execution part,

  • @Inject @PojoExecutorProxy IServiceExecutorProxy serviceExecutor: Injected for executing Defne Services.
  • @Inject Conversation conversation : Injected for managing conversation state
  • @Inject SessionTracker tracke : Injected for getting the current user information

SessionTracker is a session scoped CDI bean that contains user information,

@SessionScoped
@Named
public class SessionTracker implements Serializable
{
private static final long serialVersionUID = 6365740106065427860L;

private User user;

/**
* When event fires, this observer method is called
* by the {@link BeanManager} interface.
*
* @param loggedInEvent event
*/
public void userAdded(@Observes LoggedInEvent loggedInEvent)
{
this.user = loggedInEvent.getUser();
}

public User getUser()
{
return this.user;
}

/**
* @param user the user to set
*/
public void setUser(User user)
{
this.user = user;
}


}

Here you see @Observes annotation. This is provided by CDI specification for implementing Event-Observer pattern. When user is logged into the system, this method is called by the container. Here is the logged-in process,

@RequestScoped
@Named
public class LoginBean
{
/**User name*/
private String userName;

/**Password*/
private String password;

/**Inject of the event instance*/
private @Inject @Any Event<LoggedInEvent> loggedInEvent;

/**Database related login controller*/
private @Inject @PojoExecutorProxy IServiceExecutorProxy serviceExecutor;

/**
* Check user login.
*
* @return navigation result
*/
public String login()
{
if(GenericValidator.isBlankOrNull(userName) || GenericValidator.isBlankOrNull(password))
{
JSFUtility.addErrorMessage("User name and password fields can not be empty", "");

return null;
}

Message inBag = MessageFactory.newMessage(LoginService.LOGIN_SERVICE.SERVICE_NAME,
LoginService.LOGIN_SERVICE.CHECK_LOGIN_METHOD.NAME);

inBag.putMessageParameter(LoginService.LOGIN_SERVICE.CHECK_LOGIN_METHOD.USER_NAME, userName);
inBag.putMessageParameter(LoginService.LOGIN_SERVICE.CHECK_LOGIN_METHOD.PASSWORD, password);

inBag = this.serviceExecutor.execute(inBag);

if(!inBag.getMessageParameter(Boolean.class, LoginService.LOGIN_SERVICE.CHECK_LOGIN_METHOD.LOGIN_RESULT))
{
JSFUtility.addErrorMessage("Login failed!,User name or password is not correct. Try again!", "");

return null;
}

User user = inBag.getMessageParameter(User.class, LoginService.LOGIN_SERVICE.CHECK_LOGIN_METHOD.LOGIN_USER);

//Fire Event
LoggedInEvent event = new LoggedInEvent(user);
loggedInEvent.fire(event);


if(user.isAdmin())
{
return "adminHome";
}

return "userHome";
}
......
......
}

Here, if logged in is succefull, LoggedInEvent event object is fired by the method, "loggedInEvent#fire(event)".  Nice feature of CDI :). Observers specify with event type that would like to observe.

JSF Page

Here is the JSF Facelet page that uses reservation bean instance,

<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:rich="http://richfaces.org/rich"
xmlns:ui="http://java.sun.com/jsf/facelets">

<head>
<title>Sample Web Application</title>
<link type="text/css" rel="stylesheet" href="#{facesContext.externalContext.requestContextPath}/main.css"/>
</head>

<body>

<ui:composition template="/user/menu.xhtml">

<ui:define name="caption">
<h:outputText value="Add Reservation Page" styleClass="captionTitle" />
</ui:define>

<ui:define name="body">

<h:form id="form">

<rich:panel>

<f:facet name="header">
<h:outputText value="Add New Reservation" />
</f:facet>

<h:panelGrid columns="2" styleClass="table" cellspacing="2" cellpadding="5" columnClasses="leftColumns,rightColumns">
<h:outputText value="Reservation Date : " />

<rich:calendar datePattern="dd/MM/yyyy" value="#{userReservationBean.reservationDate}">
</rich:calendar>

</h:panelGrid>


<h:dataTable id="dt" cellpadding="5" value="#{userReservationBean.hotels}" binding="#{userReservationBean.model}" var="model" styleClass="table dataTable" rowClasses="oddRow,evenRow">

<h:column id="dt1">
<f:facet name="header">
<h:outputText id="col1" value="Name" />
</f:facet>

<h:outputText id="col11" value="#{model.name}" />
</h:column>

<h:column id="dt2">
<f:facet name="header">
<h:outputText id="col2" value="Star" />
</f:facet>

<h:outputText id="col22" value="#{model.star}" />
</h:column>

<h:column id="dt5">
<h:commandLink action="#{userReservationBean.addReservation}" value="Add Hotel for Reservation" />
</h:column>

</h:dataTable>
</rich:panel>

<rich:panel>

<f:facet name="header">
<h:outputText value="Added Hotels For Reservation" />
</f:facet>

<div class="caption">
<h:outputText value="Added Hotels" styleClass="captionTitle" />
</div>

<h:panelGrid columns="2" styleClass="table" cellspacing="2" cellpadding="5" columnClasses="leftColumns,rightColumns">

<h:outputLabel for="name">
<h:outputText value="Name" />
</h:outputLabel>

<h:selectManyListbox style="width:225px;height:75px;" value="#{userReservationBean.itemSelected}">
<f:selectItems value="#{userReservationBean.reservations}"/>
</h:selectManyListbox>


<h:commandButton action="#{userReservationBean.checkout}" value="Checkout" />

<h:panelGroup>
<h:commandButton action="#{userReservationBean.delete}" value="Delete" />
<h:commandButton action="#{userReservationBean.clear}" value="Cancel" />
</h:panelGroup>

</h:panelGrid>
</rich:panel>

</h:form>
</ui:define>
</ui:composition>
</body>
</html>

 

Model Layer

Model layer only contains JPA entity classes and JPA configuration file. For example, here is the part of the Reservation class,

@Entity
public class Reservation
{
@Id
@GeneratedValue
private int id;

@ManyToOne
private User user;

@OneToOne
private Hotel hotel;

@Temporal(TemporalType.DATE)
private Date reservationDate;

@Version
private int version;

public Reservation()
{

}
.....
}

 Utility Layer

This layer contains some utility classes that are used by all layers. For example, it contains CDI binding types,constants etc.

 Service Layer

 This layer contains the business services of the application that interacts with database. It uses Defne annotations heavily. Below is the Register Service,

@Service
public class RegisterService
{
private static final ILogger logger = LoggerProvider.getLogProvider(RegisterService.class);

@Operation
@TransactionAttribute(TransactionPolicy.WITH_TRANSACTION)
@EntityManagerAttribute
public static Message registerUser(Message inBag) throws DefneException
{
Message oBag = MessageFactory.newServiceBag(inBag.isReturnsOutMessage());
try
{
String userName = inBag.getMessageParameter(String.class, "USER_NAME");
String password = inBag.getMessageParameter(String.class, "PASSWORD");
String name = inBag.getMessageParameter(String.class, "NAME");
String surname = inBag.getMessageParameter(String.class, "SURNAME");
int age = inBag.getMessageParameter(Integer.class, "AGE");
boolean admin = inBag.getMessageParameter(Boolean.class, "ADMIN");


EntityManager entityManager = EntityManagerUtil.getEntityManagerFromBag(inBag);
logger.info("Register a new user with user name : " + userName);

if(GenericValidator.isBlankOrNull(userName) || GenericValidator.isBlankOrNull(password))
{
logger.info("Registering is failed. User name and password can not be null");
return null;
}

User user = new User();

user.setUserName(userName);
user.setPassword(password);
user.setName(name);
user.setSurname(surname);
user.setAge(age);
user.setRegisterDate(CalendarUtil.getCurrentDate());
user.setAdmin(admin);

entityManager.persist(user);

oBag.putMessageParameter("USER", user);
}
catch (Exception e)
{
Utility.throwsDefneException(e);
}

return oBag;
}
}

 TransactionAttribute and EntityManagerAttribute annotations are used for defining Transaction and JPA requirements of the service operation.

Rich Faces Configuration for JSF 2

To use RichFaces 3.3.3 in JSF 2 environment (like Apache MyFaces 2.0.1 in SIwpas), you have to tweak some parameters in faces-config.xml and web.xml of the application. Here is the necessary part for faces-config.xml,

<faces-config>
.....
<application>
<view-handler>org.ajax4jsf.application.AjaxViewHandler</view-handler>
</application>
.....
</faces-config>

 And here is the web.xml,

  <listener>
<listener-class>org.defne.service.scanner.ScannerListener</listener-class>
</listener>

<context-param>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>server</param-value>
</context-param>

<context-param>
<param-name>javax.faces.DISABLE_FACELET_JSF_VIEWHANDLER</param-name>
<param-value>true</param-value>
</context-param>

<context-param>
<param-name>org.ajax4jsf.VIEW_HANDLERS</param-name>
<param-value>com.sun.facelets.FaceletViewHandler</param-value>
</context-param>

<context-param>
<param-name>org.richfaces.SKIN</param-name>
<param-value>blueSky</param-value>
</context-param>

<context-param>
<param-name>org.richfaces.CONTROL_SKINNING</param-name>
<param-value>enable</param-value>
</context-param>

<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>
<servlet-name>Faces Servlet</servlet-name>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
</filter-mapping>

<context-param>
<param-name>javax.faces.DEFAULT_SUFFIX</param-name>
<param-value>.xhtml</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>

<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>

<error-page>
<exception-type>java.lang.Exception</exception-type>
<location>/src/main/webapp/index.html</location>
</error-page>

 To use RichFaces with JSF 2, you have to disable Facelet support in JSF 2 and manually add Facelet libraries to your web application classpath.

beans.xml and defne-service.xml Files

Those files are used by the Apache OpenWebBeans and Defne respectively. defne-service.xml file is a marker file that is put into META-INF/ folder of the application classpath.  Defne framework looks for this file to scan deployment. beans.xml is a CDI configuration file.

JPA persistence.xml File

Defne framework uses Java Persistence API for  handling database operations. Here is the persistence.xml file used by the application that is contained in "Model" layer.

	<persistence-unit name="default" transaction-type="RESOURCE_LOCAL">
<provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider>

<class>org.sample.reservation.entity.Hotel</class>
<class>org.sample.reservation.entity.User</class>
<class>org.sample.reservation.entity.Reservation</class>

<properties>
<property name="openjpa.jdbc.DBDictionary" value="hsql" />
<property name="openjpa.ConnectionDriverName" value="org.hsqldb.jdbcDriver" />
<property name="openjpa.ConnectionURL" value="jdbc:hsqldb:mem:test" />
<property name="openjpa.ConnectionUserName" value="sa" />
<property name="openjpa.ConnectionPassword" value="" />
<property name="openjpa.Log" value="DefaultLevel=TRACE" />
<property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(ForeignKeys=true)" />
</properties>

</persistence-unit>

 

Source Code Of The Application

Source code of the reservation application can be downloaded from SVN, http://defne.googlecode.com/svn/trunk/defne-samples/reservation/

Conclusion

Defne provides an easy way to write your business logic using Java EE technologies. Defne services could be called by different clients easily such as, Pure AJAX, Standalone Java, Java Servlet, JSF, RESTful Services etc. We will add more clients at the next release, such as JMS, TCP, Web Service etc. 

JBoss RichFaces provides powerful AJAX capable JSF components.

Apache OpenWebBeans/CDI provides dependecy injection support,

Java EE JSF 2 (Apache MyFaces) is a powerful MVC framwork for  developing component based AJAX capable web applications,

Java EE JPA 2 (Apache OpenJPA)  is a specification for accessing, persisting, and managing data between Java objects / classes and a relational database

MechSoft SIWpas provides lightweight Java EE Web profile compatible server environment.

Defne URLs

Web Site : http://code.google.com/p/defne/

SVN Site : http://code.google.com/p/defne/source/browse/

Maven Snapshot : https://oss.sonatype.org/content/repositories/snapshots/org/defne/

Maven : http://repo1.maven.org/maven2/org/defne/

Defne Discussion : http://groups.google.com/group/defnedev

RichFace URL

Web Site : http://jboss.org/richfaces

SIwpas URL

Web Site : http://code.google.com/p/siwpas/

Apache Software Foundation

Web Site : http://apache.org

Enjoy!

Gurkan Erdogdu

ASF Member,http://apache.org

PMC Chair, Apache OpenWebBeans

CTO, MechSoft Mechanical and Software Solutions, http://www.mechsoft.com.tr

Download Building Reactive Microservices in Java: Asynchronous and Event-Based Application Design. Brought to you in partnership with Red Hat

Topics:

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}