Skip to main content

Java EE Application Development – Add EJB modules and Database Operations

Github Source Code

EJB, Enterprise Java Bean, encapsulates the business logic of an application. You can use it to invoke system-level services, such transctions and security.1 Based on the JPA module we created last time, we now use EJB to do database operations. From this tutorial, you will be able to add a new user to the database, query a list of users and display them in the JSF page.

Project Structure

 

Implement DAO

Let’s add some code to the notebookDomain module to manipulate data in the database. Create an interface IUserDao under com.zxuqian.notebook.dao package with the following code:

public interface IUserDao {

    User getUserById(Long id);

    List<User> getAllUsers();

    Long addUser(User user);

    void deleteUser(User user);
}

Then create the implementation class UserDao under com.zxuqian.notebook.dao.impl package. The UserDao class constructor takes an EntityManager as the only argument. Since EJB is a container managed component, we need it to inject the EntityManager and pass it to our persistence layer.

public class UserDao implements IUserDao, Serializable {


    private EntityManager entityManager;

    public UserDao(EntityManager entityManager) {
        this.entityManager = entityManager;
    }


    @Override
    public User getUserById(Long id) {
        return this.entityManager.find(User.class, id);
    }

    @Override
    public List<User> getAllUsers() {
        List<User> userList = this.entityManager.createNamedQuery(
                "getAllUsersQuery", User.class).getResultList();
        return userList;
    }

    @Override
    public Long addUser(User user) {
        this.entityManager.persist(user);
        return user.getId();
    }

    @Override
    public void deleteUser(User user) {
        this.entityManager.remove(user);

    }
}

This class makes four method calls using EntityManager API.

  • find() method is to do a query on the database, given the primary key, and return the related Java object.
  • createNamedQuery() executes a query that is predefined. It is defined in the User class which I will show you later.
  • persist() method insert the user object to the database.
  • remove() method delete a record from the database based on the id of the given user object.

The named query is defined using @NamedQuery class annotation on the User class:

@NamedQuery(name = "getAllUsersQuery", query = "from User u")
public class User implements Serializable {

The query language used here is called JPQL which is defined by JPA specification and uses similar sytax to SQL statetments. Here we query all user objects from the database. The select clause is omiited if selecting all columns.

There is a little change in the Persistence.xml file:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
    <persistence-unit name="notebookDomain" transaction-type="JTA">
        <jta-data-source>java:/MySqlDS</jta-data-source>
        <properties>
            <!-- Have to define dialect and use hibernate ddl generation strategy -->
            <property name="hibernate.hbm2ddl.auto" value="create-drop"/>
            <property name="hibernate.dialect" value="MySQL5" />
        </properties>
    </persistence-unit>
</persistence>

The properties are changed to be hibernate specific, as it is the default JPA provider in Wildfly. Previous configurations does not work perfectly here. For example, the default configuration will not drop tables even if you specify the “create-and-drop” in this file. The hibernate.hbm2ddl.auto will work here. The hibernate.dialect is to define the vendor of the database you use.

Create EJB modules

EJB Service client module

A EJB component can have interfaces to define wether it is a local or remote bean. Local bean can only be accessed in the same container, i.e. application server (Wildfly e.g.). Remote bean can be accessed across different containers distributed on a group of machines.

Now, let’s create the service interfaces in an maven module called notebookServiceClient.

The content of pom.xml is:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>notebookRoot</artifactId>
        <groupId>com.zxuqian</groupId>
        <version>0.0.2</version>
        <relativePath>../notebookRoot/pom.xml</relativePath>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>notebookServiceClient</artifactId>

    <build>
        <resources>
            <resource>
                <directory>src</directory>
                <excludes>
                    <exclude>**/*.java</exclude>
                </excludes>
            </resource>
        </resources>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

    <dependencies>
        <dependency>
            <groupId>com.zxuqian</groupId>
            <artifactId>notebookDomain</artifactId>
        </dependency>
        <dependency>
            <groupId>org.jboss.spec.javax.ejb</groupId>
            <artifactId>jboss-ejb-api_3.2_spec</artifactId>
            <scope>provided</scope>
        </dependency>
    </dependencies>

</project>

As you see, it also inheris from notebookRoot module, use notebookDomain and jboss ejb implementaiton as dependencies.  &lt;resource&gt; defines which folder content resource files and what fiels are excluded.

Create an interface IUserService using following code:

public interface IUserService {

    User getUserById(Long id);

    List<User> getAllUsers();

    Long addUser(User user);

    void deleteUser(User user);
}

These methods are general CRUD operations to the database. There we defined four methods to retrieve all users and a single user by user id, add a new user, and delete a user.

Create another interface IUserServiceLocal that extends IUserService, annotated it as @Local. This is the local bean interface.

@Local
public interface IUserServiceLocal extends IUserService {
}

Create the remote interface IUserServiceRemote

@Remote
public interface IUserServiceRemote extends IUserService {
}

They all implement same methods, so we can just leave them blank, using method defined in the parent interface.

EJB Service module

Create a maven module notebookService. This is the implementation of notebookServiceClient. The pom.xml has the following content:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>notebookRoot</artifactId>
        <groupId>com.zxuqian</groupId>
        <version>0.0.2</version>
        <relativePath>../notebookRoot/pom.xml</relativePath>
    </parent>

    <modelVersion>4.0.0</modelVersion>
    <packaging>ejb</packaging>

    <artifactId>notebookService</artifactId>
    <build>
        <resources>
            <resource>
                <directory>src</directory>
                <excludes>
                    <exclude>**/*.java</exclude>
                </excludes>
            </resource>
        </resources>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
            </plugin>
            <plugin>
                <artifactId>maven-ejb-plugin</artifactId>
            </plugin>
        </plugins>
    </build>


    <dependencies>
        <dependency>
            <groupId>org.jboss.spec.javax.ejb</groupId>
            <artifactId>jboss-ejb-api_3.2_spec</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.hibernate.javax.persistence</groupId>
            <artifactId>hibernate-jpa-2.1-api</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>com.zxuqian</groupId>
            <artifactId>notebookDomain</artifactId>
        </dependency>
        <dependency>
            <groupId>com.zxuqian</groupId>
            <artifactId>notebookServiceClient</artifactId>
        </dependency>
    </dependencies>

</project>

The difference is the “ has a value of ejb, which will be packaged as an EJB module. You may need to put a ejb-jar.xml in src/META-INF folder, but it is unnecessary if the EJB version is above 3.0. The content of ejb-jar.xml is:

<?xml version="1.0" encoding="UTF-8"?>
<ejb-jar 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/ejb-jar_3_1.xsd"
         version="3.1">
</ejb-jar>

Now, create a Java class UserServiceBean implements IUserServiceLocal with a @Stateful annotation. This means this bean will keep its states during client calls. In this class, it injects a EntityManager using @PersistenceContext annotation which means the container is responsible to manage it. Saying container, that’s why you can’t inject it in an ordinary Java class that is not managed by the container. The class here just initiates the UserDao data access object, and invokes methods provided by it.  @PostConstruct is a lifecycle annotion, which means the method annotated with it will be called after the object has been created.

@Stateful
public class UserServiceBean implements IUserServiceLocal {

    @PersistenceContext
    private EntityManager entityManager;

    private IUserDao userDao;

    @PostConstruct
    private void init() {
        this.userDao = new UserDao(entityManager);
    }

    public User getUserById(Long id) {
        return this.userDao.getUserById(id);
    }

    public List<User> getAllUsers() {
        return this.userDao.getAllUsers();
    }

    public Long addUser(User user) {
        return this.userDao.addUser(user);
    }

    public void deleteUser(User user) {
        this.userDao.deleteUser(user);
    }
}

Service Invocation (JSF)

Now it’s time to using the EJB service to present and save data for us. Create a class UserBackBean in the notebook JSF module with the following code:

public class UserBackBean implements Serializable {

    private Logger logger = Logger.getLogger(UserBackBean.class.getCanonicalName());

    @EJB
    private IUserServiceLocal userService;

    private List<User> users;

    private User user;

    public UserBackBean() {
        this.user = new User();
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    public List<User> getUsers() {
        return users;
    }

    public void setUsers(User user) {
        this.users.add(user);
    }

    public String register() {
        this.userService.addUser(this.user);
        return this.getAllUsers();
    }

    public String getAllUsers() {
        this.users = this.userService.getAllUsers();

        return "user_list";
    }
}

This is the back bean of a JSF page (component). The variables and methods can be accessed through EL expressions.

  • The IUserServiceLocal is annotated by @EJB so that the conatiner can manage the object’s creation and destruction.
  • The users varable of List type preserving the result of querying all users in the database.
  • The user object is defined in the notebookDomain module, and here it is used to receive the data that the user inputs.
  • The register() method will save the user object to the database and calls another method to list all of users.
  • The getAllUsers() is to query all users in the database and return a String representing the name of result page.

Now let’s create some pages. First, create a register.xhtml file in WebContent folder with following html code:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:jsf="http://xmlns.jcp.org/jsf"
      xmlns:f="http://xmlns.jcp.org/jsf/core">

    <h:form>
        <label for="username">Username: </label>
        <h:inputText id="usernmae" value="#{userBackBean.user.username}" /><br />
        <label for="password">Password: </label>
        <h:inputSecret id="password" value="#{userBackBean.user.password}" /><br />
        <label for="date_of_birth">Date of birth: </label>
        <input type="date" jsf:id="date_of_birth" value="#{userBackBean.user.dateOfBirth}">
            <f:convertDateTime pattern="yyyy-MM-dd"/>
        </input>
        <br />
        <label for="email">Email: </label>
        <input type="email" jsf:id="email" value="#{userBackBean.user.email}" /><br />
        <label for="phone">Phone number: </label>
        <h:inputText  value="#{userBackBean.user.phone}" /><br />

        <h:commandButton value="Submit" action="#{userBackBean.register}" />
    </h:form>
</html>

Notice the syntax to reference properties defined in the back bean, it is pretty obvious and simple. The action attribute in the “ tag invokes the register() method in the UserBackBean class.

Create a page user_list.xhtml for listing users:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:c="http://xmlns.jcp.org/jsp/jstl/core">

    <h:head>
        <title>Qiantu - A simple Notebook</title>
    </h:head>
    <h:body>
        <ul>
            <c:forEach items="#{userBackBean.users}" var="user">
                <li>#{user.username}</li>
            </c:forEach>
        </ul>
    </h:body>
</html>

Here a JSTL tag library is imported. It provides a number of handful tags to manipulate data in the back bean. The <c:forEach> is used to iterate a collection or an array. The items atrribute is the collection to be iterated, and the var attribute is the variable name that you defined for each element in the collection. For each user, the user name is displayed in the <li> tag.

In the index.xhtml page, add the following code before </h:body>:

    <p><h:outputLink value="register.xhtml">Register</h:outputLink></p>
    <h:form>
        <p><h:commandLink action="#{userBackBean.getAllUsers}">List All Users</h:commandLink></p>
    </h:form>

The <h:outputLink> will generate a <a> tag and will redirect to the page that defined by the value attribute.

The <h:commandLink> has to be defined in the <h:form> tag. The difference beweent <h:outputLink> and <h:commandLink> is that the <h:commandLink> do some additional operations before redirect to another page, here it calls the getAllUsers() method of UserBackBean class. The users list variable will have values and the user_list.xhtml page can then access it.

Configure Maven

As we have two additional modules here, we need to change some configurations in the pom.xml.

For the pom.xml in the notebookRoot module, a few common plugins is added in the <pluginManagement> tag to provide a unified management of plugin version and configurations so that you don’t have to specify plugin versions in sub-modules.

<build>
    <pluginManagement>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
            <plugin>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.3</version>
            </plugin>
            <plugin>
                <artifactId>maven-ejb-plugin</artifactId>
                <version>2.3</version>
                <configuration>
                    <ejbVersion>3.2</ejbVersion>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-ear-plugin</artifactId>
                <version>2.10</version>
            </plugin>
        </plugins>
    </pluginManagement>
</build>

In addition, the newly created modules are added to the <dependencyManagement> tag:

<dependency>
    <groupId>com.zxuqian</groupId>
    <artifactId>notebookService</artifactId>
    <version>${project.version}</version>
    <type>ejb</type>
</dependency>
<dependency>
    <groupId>com.zxuqian</groupId>
    <artifactId>notebookServiceClient</artifactId>
    <version>${project.version}</version>
</dependency>

Here the notebookService has a ejb value in its <packaging> tag, so the <type> need to be specified as ejb as well, otherwise maven will not find it.

The pom.xml in the notebookDomain module need some notice:

<build>
    <resources>
      <resource>
        <directory>src</directory>
        <excludes>
          <exclude>**/*.java</exclude>
        </excludes>
      </resource>
    </resources>

    <plugins>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.5.1</version>
        <configuration>
          <source>1.8</source>
          <target>1.8</target>
        </configuration>
      </plugin>
    </plugins>
  </build>

The <resources> tag must be included to define which directory contains resource files. Here all files in src folder except file end with .java will be treated as resource. By doing so, the persistence.xml can be packaged in the jar file.

Other module’s pom.xml file just made some changes on its dependencies, so here I will not show them. You can see it on Github. If the source code has changed, you can view the history and find the right one by tags or commit messages.

Testing

After run install maven goal on notebookRoot module, deploy notebookEAR module by double click wildfly:run in the plugin lifecycles. Open a browser and type the URL:

http://localhost:8080/notebook

Click the Register link,

fill some data and click Submit botton, then you should see the user name list, including the user you just added.

  • Rudy De Busscher

    Hi,

    I have several remarks about the above code (and in general on the serie of the example)

    Although it uses some things of Java EE 7, it is still based on the old style of Java EE, the pre Java EE 5 era

    * Why define different Maven dependencies for Java EE and not just the java:javaee-api:7.0?
    * Why redefine the default web content directory of maven from webapp To WebContent?
    * Why using an EAR deployment when WAR can be used to have the same functionality? (also for your Rest endpoint which you discuss in another
    * Why all these interfaces and implementation classes? Since Java EE 6 (EJB 3.1) you have the EJB No interface concept) DAO interface adds nothing only complexity.
    * Consider using the Boundary concept (Entity – Control – Boundary principal) so that you don’t have the ‘useless’ service class which adds no real functionality except as a pass through the the DAO.
    * Why mixing <h:inputText and This is confusing for your readers.

    * Why using JSF managed beans instead of CDI beans (JSF managed beans are basically deprecated) which are much more powerful.

    Best regards
    Rudy

    • Hi Rudy,
      The application is still using traditional four tier architecture, so it looks like in the pre Java EE 5 era, but the technologies used are still from Java EE 7 specification. About all your questions, let me explain one by one.
      1. Thank you for pointing out the convenient way for managing Java EE 7 dependencies.
      2. The default web content directory is called ‘WebContent’, the ‘webapp’ is generated by the Eclipse plugin, ‘convert to Maven project’, and it introduces additional configurations in pom.xml. To keep it simple and consistent, I decided to use the default one, which is ‘WebContent’.
      3. The EAR here is used to deploy all Java EE components on to the same application server. However, for distribution purpose, you may deploy each component to different servers, that’s why they are developed separately.
      4. The necessity of DAO pattern is still under debate. In my opinion, the existence of DAO pattern is to decouple database logic from service layer. For the service, aka EJB, the Java EE 7 do have the interface concept, for it is used for distribution purpose either. Service interfaces have @Local and @Remote annotations to identify wether the EJB component is deployed on the local server alongside with web client, or deployed on a different server. In addition, local and remote beans may provide different functionalities based on requirements.
      5. I will have a research on the Entity – Control – Boundary pattern. It seems good for RESTful
      web service development.
      6. It’s just a demonstration that you can use HTML5 in JSF.
      7. I will introduce the CDI beans in future blogs.

      Again, thank you so much for the feedback. It will make the blog even better, and I can learn from it as well.