JSF 2, PrimeFaces 3, Spring 3 & Hibernate 4 Integration Project

This article shows how to integrate JSF2, PrimeFaces3, Spring3 and Hibernate4 Technologies. It provides a general project template for Java developers.

Also if Spring is not used for Business and Data Access layer, JSF – PrimeFaces & Hibernate Integration Project can be offered.

Used Technologies :

  • JDK 1.6.0_31
  • Spring 3.1.1
  • JSF 2.1
  • Hibernate 4.1.0
  • Primefaces 3.1.1
  • MySQL Connector 5.1.17
  • MySQL 5.5.8
  • c3p0 0.9.1.2
  • Tomcat 7.0
  • Maven 3.0.2

STEP 1 : CREATE MAVEN PROJECT

A maven project is created as below. (It can be created by using Maven or IDE Plug-in).

STEP 2 : CREATE USER TABLE

A new USER Table is created by executing below script:

CREATE TABLE USER (
   id int(11) NOT NULL,
   name varchar(45) NOT NULL,
   surname varchar(45) NOT NULL,
   PRIMARY KEY (`id`)
);

STEP 3 : LIBRARIES

Spring, JSF, Hibernate, Primefaces, MySQL and c3p0 dependencies are added to Maven’ s pom.xml.

<properties>
  <spring.version>3.1.1.RELEASE</spring.version>
 </properties>

 <dependencies>

  <!-- Spring 3 dependencies -->
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-core</artifactId>
   <version>${spring.version}</version>
  </dependency>

  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-context</artifactId>
   <version>${spring.version}</version>
  </dependency> 

  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-web</artifactId>
   <version>${spring.version}</version>
  </dependency>

  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-tx</artifactId>
   <version>${spring.version}</version>
  </dependency>

  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-orm</artifactId>
   <version>${spring.version}</version>
  </dependency>

  <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.version}</version>
        </dependency>

  <!-- JSF dependencies -->
  <dependency>
    <groupId>com.sun.faces</groupId>
    <artifactId>jsf-api</artifactId>
    <version>2.1.6</version>
  </dependency>

  <dependency>
    <groupId>com.sun.faces</groupId>
    <artifactId>jsf-impl</artifactId>
    <version>2.1.6</version>
  </dependency>

  <dependency>
   <groupId>javax.servlet</groupId>
   <artifactId>jstl</artifactId>
   <version>1.2</version>
  </dependency>

  <!-- Primefaces dependency -->
   <dependency>
   <groupId>org.primefaces</groupId>
   <artifactId>primefaces</artifactId>
   <version>3.1.1</version>
  </dependency>

  <!-- Hibernate dependencies -->
  <dependency>
   <groupId>org.hibernate</groupId>
   <artifactId>hibernate-core</artifactId>
   <version>4.1.0.Final</version>
  </dependency>

  <dependency>
   <groupId>javassist</groupId>
   <artifactId>javassist</artifactId>
   <version>3.12.1.GA</version>
  </dependency>

  <!-- MySQL Java Connector dependency -->
  <dependency>
   <groupId>mysql</groupId>
   <artifactId>mysql-connector-java</artifactId>
   <version>5.1.17</version>
  </dependency>

  <!-- c3p0 dependency -->
  <dependency>
   <groupId>c3p0</groupId>
   <artifactId>c3p0</artifactId>
   <version>0.9.1.2</version>
  </dependency>            

 </dependencies>

STEP 4 : CREATE USER MODEL CLASS

A new User Model Class is created.

package com.otv.model;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

/**
 *
 * User Entity
 *
 * @author onlinetechvision.com
 * @since 25 Mar 2012
 * @version 1.0.0
 *
 */
@Entity
@Table(name="USER")
public class User {

 private int id;
 private String name;
 private String surname;

 /**
  * Get User Id
  *
  * @return int - User Id
  */
 @Id
 @Column(name="ID", unique = true, nullable = false)
 public int getId() {
  return id;
 }

 /**
  * Set User Id
  *
  * @param int - User Id
  */
 public void setId(int id) {
  this.id = id;
 }

 /**
  * Get User Name
  *
  * @return String - User Name
  */
 @Column(name="NAME", unique = true, nullable = false)
 public String getName() {
  return name;
 }

 /**
  * Set User Name
  *
  * @param String - User Name
  */
 public void setName(String name) {
  this.name = name;
 }

 /**
  * Get User Surname
  *
  * @return String - User Surname
  */
 @Column(name="SURNAME", unique = true, nullable = false)
 public String getSurname() {
  return surname;
 }

 /**
  * Set User Surname
  *
  * @param String - User Surname
  */
 public void setSurname(String surname) {
  this.surname = surname;
 } 

 @Override
 public String toString() {
  StringBuffer strBuff = new StringBuffer();
  strBuff.append("id : ").append(getId());
  strBuff.append(", name : ").append(getName());
  strBuff.append(", surname : ").append(getSurname());
  return strBuff.toString();
 }
}

STEP 5 : CREATE USER MANAGED BEAN CLASS

User Managed Bean is created.

package com.otv.managed.bean;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.RequestScoped;

import org.springframework.dao.DataAccessException;

import com.otv.model.User;
import com.otv.user.service.IUserService;

/**
 *
 * User Managed Bean
 *
 * @author onlinetechvision.com
 * @since 25 Mar 2012
 * @version 1.0.0
 *
 */
@ManagedBean(name="userMB")
@RequestScoped
public class UserManagedBean implements Serializable {

 private static final long serialVersionUID = 1L;
 private static final String SUCCESS = "success";
 private static final String ERROR   = "error";

 //Spring User Service is injected...
 @ManagedProperty(value="#{UserService}")
 IUserService userService;

 List<User> userList;

 private int id;
 private String name;
 private String surname;

 /**
  * Add User
  *
  * @return String - Response Message
  */
 public String addUser() {
  try {
   User user = new User();
   user.setId(getId());
   user.setName(getName());
   user.setSurname(getSurname());
   getUserService().addUser(user);
   return SUCCESS;
  } catch (DataAccessException e) {
   e.printStackTrace();
  }  

  return ERROR;
 }

 /**
  * Reset Fields
  *
  */
 public void reset() {
  this.setId(0);
  this.setName("");
  this.setSurname("");
 }

 /**
  * Get User List
  *
  * @return List - User List
  */
 public List<User> getUserList() {
  userList = new ArrayList<User>();
  userList.addAll(getUserService().getUsers());
  return userList;
 }

 /**
  * Get User Service
  *
  * @return IUserService - User Service
  */
 public IUserService getUserService() {
  return userService;
 }

 /**
  * Set User Service
  *
  * @param IUserService - User Service
  */
 public void setUserService(IUserService userService) {
  this.userService = userService;
 }

 /**
  * Set User List
  *
  * @param List - User List
  */
 public void setUserList(List<User> userList) {
  this.userList = userList;
 }

 /**
  * Get User Id
  *
  * @return int - User Id
  */
 public int getId() {
  return id;
 }

 /**
  * Set User Id
  *
  * @param int - User Id
  */
 public void setId(int id) {
  this.id = id;
 }

 /**
  * Get User Name
  *
  * @return String - User Name
  */
 public String getName() {
  return name;
 }

 /**
  * Set User Name
  *
  * @param String - User Name
  */
 public void setName(String name) {
  this.name = name;
 }

 /**
  * Get User Surname
  *
  * @return String - User Surname
  */
 public String getSurname() {
  return surname;
 }

 /**
  * Set User Surname
  *
  * @param String - User Surname
  */
 public void setSurname(String surname) {
  this.surname = surname;
 }

}

STEP 6 : CREATE IUserDAO INTERFACE

IUserDAO Interface provides methods of Data Access Layer. The data access layer manages all the logic to persist and retrieve the data from database.

package com.otv.user.dao;

import java.util.List;

import com.otv.model.User;

/**
 *
 * User DAO Interface
 *
 * @author onlinetechvision.com
 * @since 25 Mar 2012
 * @version 1.0.0
 *
 */
public interface IUserDAO {

 /**
  * Add User
  *
  * @param  User user
  */
 public void addUser(User user);

 /**
  * Update User
  *
  * @param  User user
  */
 public void updateUser(User user);

 /**
  * Delete User
  *
  * @param  User user
  */
 public void deleteUser(User user);

 /**
  * Get User
  *
  * @param  int User Id
  */
 public User getUserById(int id);

 /**
  * Get User List
  *
  */
 public List<User> getUsers();
}

STEP 7 : CREATE UserDAO CLASS

UserDAO Class is created by implementing IUserDAO Interface.

package com.otv.user.dao;

import java.util.List;

import com.otv.model.User;

import org.hibernate.SessionFactory;

/**
 *
 * User DAO
 *
 * @author onlinetechvision.com
 * @since 25 Mar 2012
 * @version 1.0.0
 *
 */

public class UserDAO implements IUserDAO {

 private SessionFactory sessionFactory;

 /**
  * Get Hibernate Session Factory
  *
  * @return SessionFactory - Hibernate Session Factory
  */
 public SessionFactory getSessionFactory() {
  return sessionFactory;
 }

 /**
  * Set Hibernate Session Factory
  *
  * @param SessionFactory - Hibernate Session Factory
  */
 public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

 /**
  * Add User
  *
  * @param  User user
  */
 @Override
 public void addUser(User user) {
  getSessionFactory().getCurrentSession().save(user);
 }

 /**
  * Delete User
  *
  * @param  User user
  */
 @Override
 public void deleteUser(User user) {
  getSessionFactory().getCurrentSession().delete(user);
 }

 /**
  * Update User
  *
  * @param  User user
  */
 @Override
 public void updateUser(User user) {
  getSessionFactory().getCurrentSession().update(user);
 }

 /**
  * Get User
  *
  * @param  int User Id
  * @return User
  */
 @Override
 public User getUserById(int id) {
  List list = getSessionFactory().getCurrentSession()
           .createQuery("from User where id=?")
                 .setParameter(0, id).list();
  return (User)list.get(0);
 }

 /**
  * Get User List
  *
  * @return List - User list
  */
 @Override
 public List<User> getUsers() {
  List list = getSessionFactory().getCurrentSession().createQuery("from User").list();
  return list;
 }

}

STEP 8 : CREATE IUserService INTERFACE

IUserService Interface provides methods to process the business logic.

package com.otv.user.service;

import java.util.List;

import com.otv.model.User;

/**
 *
 * User Service Interface
 *
 * @author onlinetechvision.com
 * @since 25 Mar 2012
 * @version 1.0.0
 *
 */
public interface IUserService {

 /**
  * Add User
  *
  * @param  User user
  */
 public void addUser(User user);

 /**
  * Update User
  *
  * @param  User user
  */
 public void updateUser(User user);

 /**
  * Delete User
  *
  * @param  User user
  */
 public void deleteUser(User user);

 /**
  * Get User
  *
  * @param  int User Id
  */
 public User getUserById(int id);

 /**
  * Get User List
  *
  * @return List - User list
  */
 public List<User> getUsers();
}

STEP 9 : CREATE UserService CLASS

UserService Class is created by implementing IUserService Interface.

package com.otv.user.service;

import java.util.List;

import org.springframework.transaction.annotation.Transactional;

import com.otv.model.User;
import com.otv.user.dao.IUserDAO;

/**
 *
 * User Service
 *
 * @author onlinetechvision.com
 * @since 25 Mar 2012
 * @version 1.0.0
 *
 */
@Transactional(readOnly = true)
public class UserService implements IUserService {

 // UserDAO is injected...
 IUserDAO userDAO;

 /**
  * Add User
  *
  * @param  User user
  */
 @Transactional(readOnly = false)
 @Override
 public void addUser(User user) {
  getUserDAO().addUser(user);
 }

 /**
  * Delete User
  *
  * @param  User user
  */
 @Transactional(readOnly = false)
 @Override
 public void deleteUser(User user) {
  getUserDAO().deleteUser(user);
 }

 /**
  * Update User
  *
  * @param  User user
  */
 @Transactional(readOnly = false)
 @Override
 public void updateUser(User user) {
  getUserDAO().updateUser(user);
 }

 /**
  * Get User
  *
  * @param  int User Id
  */
 @Override
 public User getUserById(int id) {
  return getUserDAO().getUserById(id);
 }

 /**
  * Get User List
  *
  */
 @Override
 public List<User> getUsers() {
  return getUserDAO().getUsers();
 }

 /**
  * Get User DAO
  *
  * @return IUserDAO - User DAO
  */
 public IUserDAO getUserDAO() {
  return userDAO;
 }

 /**
  * Set User DAO
  *
  * @param IUserDAO - User DAO
  */
 public void setUserDAO(IUserDAO userDAO) {
  this.userDAO = userDAO;
 }
}

STEP 10 : CREATE applicationContext.xml

Spring Application Context’ s content is shown as follows :

<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:tx="http://www.springframework.org/schema/tx"
  xmlns:context="http://www.springframework.org/schema/context"
  xsi:schemaLocation="http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans-3.0.xsd


http://www.springframework.org/schema/tx


http://www.springframework.org/schema/tx/spring-tx-3.0.xsd


http://www.springframework.org/schema/context

http://www.springframework.org/schema/context/spring-context-3.0.xsd">

 <!-- Beans Declaration -->
 <bean id="User" class="com.otv.model.User"/>

 <!-- User Service Declaration -->
 <bean id="UserService" class="com.otv.user.service.UserService">
  <property name="userDAO" ref="UserDAO" />
 </bean>

 <!-- User DAO Declaration -->
 <bean id="UserDAO" class="com.otv.user.dao.UserDAO">
  <property name="sessionFactory" ref="SessionFactory" />
 </bean>

 <!-- Data Source Declaration -->
 <bean id="DataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
  <property name="driverClass" value="com.mysql.jdbc.Driver" />
  <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/Test" />
  <property name="user" value="root" />
  <property name="password" value="root" />
  <property name="maxPoolSize" value="10" />
  <property name="maxStatements" value="0" />
  <property name="minPoolSize" value="5" />
 </bean>

 <!-- Session Factory Declaration -->
 <bean id="SessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
  <property name="dataSource" ref="DataSource" />
  <property name="annotatedClasses">
   <list>
    <value>com.otv.model.User</value>
   </list>
  </property>
  <property name="hibernateProperties">
   <props>
    <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
    <prop key="hibernate.show_sql">true</prop>
   </props>
  </property>
 </bean>

 <!-- Enable the configuration of transactional behavior based on annotations -->
    <tx:annotation-driven transaction-manager="txManager"/>

 <!-- Transaction Manager is defined -->
    <bean id="txManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
       <property name="sessionFactory" ref="SessionFactory"/>
    </bean>

</beans>

STEP 11 : CREATE faces-config.xml

JSF Configuration is shown as follows :

<?xml version="1.0" encoding="UTF-8"?>
<faces-config
    xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 

http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"

    version="2.0">

   <!-- JSF and Spring are integrated -->
   <application>
     <el-resolver>
      org.springframework.web.jsf.el.SpringBeanFacesELResolver
     </el-resolver>
   </application>

 <!-- configuration of navigation rules -->
 <navigation-rule>
     <from-view-id>/pages/index.xhtml</from-view-id>
     <navigation-case>
         <from-outcome>success</from-outcome>
            <to-view-id>/pages/success.xhtml</to-view-id>
        </navigation-case>
         <navigation-case>
         <from-outcome>error</from-outcome>
            <to-view-id>/pages/error.xhtml</to-view-id>
        </navigation-case>
    </navigation-rule>

</faces-config>

STEP 12 : CREATE web.xml

web.xml is configured as follows :

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns="http://java.sun.com/xml/ns/javaee"
   xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
   id="WebApp_ID"
   version="2.5">

   <display-name>OTV_JSF_PrimeFaces_Spring_Hibernate</display-name>

   <!-- Spring Context Configuration' s Path definition -->
      <context-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>
      /WEB-INF/applicationContext.xml
      </param-value>
   </context-param>

   <!-- The Bootstrap listener to start up and shut down Spring's root WebApplicationContext. It is registered to Servlet Container -->
   <listener>
  <listener-class>
   org.springframework.web.context.ContextLoaderListener
  </listener-class>
   </listener>
   <listener>
  <listener-class>
   org.springframework.web.context.request.RequestContextListener
  </listener-class>
   </listener>

   <!-- Project Stage Level -->
   <context-param>
     <param-name>javax.faces.PROJECT_STAGE</param-name>
     <param-value>Development</param-value>
   </context-param>

   <!-- Welcome Page -->
   <welcome-file-list>
     <welcome-file>/pages/index.xhtml</welcome-file>
   </welcome-file-list>

   <!-- JSF Servlet is defined to container -->
   <servlet>
     <servlet-name>Faces Servlet</servlet-name>
     <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
     <load-on-startup>1</load-on-startup>
   </servlet>

   <!-- Mapping with servlet and url for the http requests. -->
   <servlet-mapping>
     <servlet-name>Faces Servlet</servlet-name>
     <url-pattern>*.jsf</url-pattern>
   </servlet-mapping>
   <servlet-mapping>
     <servlet-name>Faces Servlet</servlet-name>
     <url-pattern>*.faces</url-pattern>
   </servlet-mapping>

</web-app>

STEP 13 : CREATE index.xhtml

index.xhtml is created as follows :

<html xmlns="http://www.w3.org/1999/xhtml"
     xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
     xmlns:p="http://primefaces.org/ui">
 <h:head><title>Welcome to OTV_JSF_Spring_Hibernate_Project</title></h:head>
 <h:body>
     <h:form>
      <table>
       <tr>
        <td><h:outputLabel for="id" value="Id : " /></td>
        <td><p:inputText id="id" value="#{userMB.id}">
          <f:converter converterId="javax.faces.Integer"/>
             <p:ajax event="blur" update="idMsg" />
         </p:inputText>
         <p:message id="idMsg" for="id" display="icon"/>
        </td>
       </tr>
       <tr>
        <td><h:outputLabel for="name" value="Name : " /></td>
        <td><p:inputText id="name" value="#{userMB.name}">
          <f:validateLength minimum="5" />
          <p:ajax event="blur" update="nameMsg" />
         </p:inputText>
         <p:message id="nameMsg" for="name" display="icon"/>
        </td>
       </tr>
       <tr>
        <td><h:outputLabel for="surname" value="Surname : " /></td>
        <td><p:inputText id="surname" value="#{userMB.surname}">
          <f:validateLength minimum="5" />
          <p:ajax event="blur" update="surnameMsg" />
         </p:inputText>
         <p:message id="surnameMsg" for="surname" display="icon"/>
        </td>
       </tr>
          <tr>
        <td><p:commandButton id="addUser" value="Add" action="#{userMB.addUser}" ajax="false"/></td>
        <td><p:commandButton id="reset" value="Reset" action="#{userMB.reset}" ajax="false"/></td>
       </tr>
      </table>
     </h:form>
</h:body>
</html>

STEP 14 : CREATE success.xhtml

success.xhtml is created as follows :

<html xmlns="http://www.w3.org/1999/xhtml"
 xmlns:h="http://java.sun.com/jsf/html"
 xmlns:f="http://java.sun.com/jsf/core"
 xmlns:p="http://primefaces.org/ui">
<h:head>
 <title>Welcome to OTV_JSF_Spring_Hibernate_Project</title>
</h:head>
<h:body>
 <h:form>
  <h:outputText value="USERs : "></h:outputText>
  <p:dataTable id="users" var="user" value="#{userMB.userList}" style="width: 10%">
   <p:column>
    <f:facet name="header">
     <h:outputText value="ID" />
    </f:facet>
    <h:outputText value="#{user.id}" />
   </p:column>
   <p:column>
    <f:facet name="header">
     <h:outputText value="Name" />
    </f:facet>
    <h:outputText value="#{user.name}" />
   </p:column>
   <p:column>
    <f:facet name="header">
     <h:outputText value="Surname" />
    </f:facet>
    <h:outputText value="#{user.surname}" />
   </p:column>
  </p:dataTable>
 </h:form>
</h:body>

</html>

STEP 15 : CREATE error.xhtml

error.xhtml is created as follows :

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

 <h:head><title>Welcome to JSF_PrimeFaces_Spring_Hibernate Project</title></h:head>
 <body>
 <f:view>
     <h:form>
         <h:outputText value="Transaction Error has occurred!"></h:outputText>
     </h:form>
 </f:view>
</body>
</html>

STEP 16 : DEPLOY PROJECT

After OTV_JSF_Spring_Hibernate Project is deployed to Tomcat, index page can be opened via following URL :

http://ip:port/OTV_JSF_Spring_Hibernate_Project-1.0-SNAPSHOT/pages/index.jsf

STEP 17 : DOWNLOAD

OTV_JSF_Spring_Hibernate

Reference: JSF2 + Primefaces3 + Spring3 & Hibernate4 Integration Project from our JCG partner Eren Avsarogullari at the Online Technology Vision blog.

Related Whitepaper:

Functional Programming in Java: Harnessing the Power of Java 8 Lambda Expressions

Get ready to program in a whole new way!

Functional Programming in Java will help you quickly get on top of the new, essential Java 8 language features and the functional style that will change and improve your code. This short, targeted book will help you make the paradigm shift from the old imperative way to a less error-prone, more elegant, and concise coding style that’s also a breeze to parallelize. You’ll explore the syntax and semantics of lambda expressions, method and constructor references, and functional interfaces. You’ll design and write applications better using the new standards in Java 8 and the JDK.

Get it Now!  

25 Responses to "JSF 2, PrimeFaces 3, Spring 3 & Hibernate 4 Integration Project"

  1. Victorino Hernández says:

    Hi friend, the link is broken again, can you fix it please?

Leave a Reply


one × 5 =



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use | Privacy Policy
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.

Sign up for our Newsletter

20,709 insiders are already enjoying weekly updates and complimentary whitepapers! Join them now to gain exclusive access to the latest news in the Java world, as well as insights about Android, Scala, Groovy and other related technologies.

As an extra bonus, by joining you will get our brand new e-books, published by Java Code Geeks and their JCG partners for your reading pleasure! Enter your info and stay on top of things,

  • Fresh trends
  • Cases and examples
  • Research and insights
  • Two complimentary e-books