Skip to main content
4 of 4
edited title
Vogel612
  • 25.3k
  • 7
  • 58
  • 141

Listing Books nicely - a tour through a webapp

In this exercise, I do not want to use any container such as Spring or Glassfish. I am deploying my application to Tomcat. I only use JPA. What I want to achieve is to follow best practices and OOP concepts correctly, and a good separation of concerns and layering.

I have a database table like this:

mysql> DESCRIBE book;
+-------------+--------------+------+-----+---------+
| Field       | Type         | Null | Key | Default |
+-------------+--------------+------+-----+---------+
| isbn        | varchar(13)  | NO   | PRI | NULL    |
| name        | varchar(64)  | NO   | UNI | NULL    |
| publishDate | date         | YES  |     | NULL    |
| price       | decimal(8,2) | YES  |     | NULL    |
| publisher   | varchar(6)   | YES  | MUL | NULL    |
+-------------+--------------+------+-----+---------+

and here is my Entity:

@Entity
@Table(name = "book")
public class Book {

    @Id
    private String isbn;

    @Basic
    private String name;

    @Basic
    private Date publishDate;

    @Basic
    private double price;

    @Basic
    private String publisher;
    
    // Getters, Setters...

This is my PersistenceUtil class:

package biz.tugay.books10Aug.dao;
/* User: [email protected] Date: 10/08/15 Time: 22:22 */

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

public class PersistenceUtil {

    private static EntityManagerFactory entityManagerFactory;

    public static void initalizeEntityManagerFactory() {
        if (entityManagerFactory == null || !entityManagerFactory.isOpen()) {
            entityManagerFactory = Persistence.createEntityManagerFactory("bookshop");
        }
    }

    public static EntityManagerFactory getEntityManagerFactory() {
        return entityManagerFactory;
    }

    public static EntityManager getEntityManager() {
        if (entityManagerFactory == null || !entityManagerFactory.isOpen()) {
            initalizeEntityManagerFactory();
        }
        EntityManager entityManager = entityManagerFactory.createEntityManager();
        return entityManager;
    }

    public static void closeEntityManagerFactory() {
        entityManagerFactory.close();
    }

}

and in my web application I have a ContextListener:

package biz.tugay.books10Aug.web;
/* User: [email protected] Date: 10/08/15 Time: 22:24 */

import biz.tugay.books10Aug.dao.PersistenceUtil;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;

@WebListener
public class BookShopServletContextListener implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        PersistenceUtil.initalizeEntityManagerFactory();
    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        PersistenceUtil.closeEntityManagerFactory();
    }

}

#1 Is this the right way to initialise Persistence Context? Or should this be responsibility of DAO / Service classes?

My DAO Layer:

package biz.tugay.books10Aug.dao;
/* User: [email protected] Date: 10/08/15 Time: 22:50 */

import biz.tugay.books10Aug.model.Book;

public interface BookDao {
    public void persist(Book book);
    public Book getWithIsbn(String isbn);
}

and the implementation:

package biz.tugay.books10Aug.dao;
/* User: [email protected] Date: 10/08/15 Time: 22:54 */

import biz.tugay.books10Aug.model.Book;

import javax.persistence.EntityManager;

public class BookDaoImpl implements BookDao {

    private EntityManager entityManager;

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

    @Override
    public void persist(Book book) {
        entityManager.persist(book);
    }

    @Override
    public Book getWithIsbn(String isbn) {
        Book book = entityManager.find(Book.class, isbn);
        return book;
    }

}

#2 Is it ok that the DAO Layer requires an EntityManager and assumes that its transaction has already begun? Should it be the DAOs responsibility to obtain the EntityManager and/or begin/commit transaction?

Here is my Service Layer:

package biz.tugay.books10Aug.service;
/* User: [email protected] Date: 11/08/15 Time: 00:12 */

import biz.tugay.books10Aug.model.Book;

import java.util.Date;

public interface BookService {

    public void createBook(String isbn, String name, Date publishDate, double price, String publisher);

    public Book getWithIsbn(String isbn);

}

and the implementation:

package biz.tugay.books10Aug.service;
/* User: [email protected] Date: 11/08/15 Time: 00:12 */

import biz.tugay.books10Aug.dao.BookDao;
import biz.tugay.books10Aug.dao.BookDaoImpl;
import biz.tugay.books10Aug.dao.PersistenceUtil;
import biz.tugay.books10Aug.model.Book;

import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import java.util.Date;

public class BookServiceImpl implements BookService {

    private BookDao bookDao;
    private EntityManager entityManager;

    public BookServiceImpl() {
        EntityManager entityManager = PersistenceUtil.getEntityManager();
        bookDao = new BookDaoImpl(entityManager);
        this.entityManager = entityManager;
    }

    @Override
    public void createBook(String isbn, String name, Date publishDate, double price, String publisher) {
        Book book = new Book();
        book.setIsbn(isbn);
        book.setName(name);
        book.setPublishDate(publishDate);
        book.setPrice(price);
        book.setPublisher(publisher);
        EntityTransaction transaction = entityManager.getTransaction();
        transaction.begin();
        bookDao.persist(book);
        transaction.commit();
    }

    @Override
    public Book getWithIsbn(String isbn) {
        EntityTransaction transaction = entityManager.getTransaction();
        transaction.begin();
        Book withIsbn = bookDao.getWithIsbn(isbn);
        transaction.commit();
        return withIsbn;
    }

}

#3 Again, I have the same questions on my mind. Is this class a mess like this? It does not have any dependencies, it obtains its EntityManager from the PersistenceUtil class in the Constructor. Is this ok? How about the entityManager field and starting / committing transactions which surrounds DAO calls?

And finally I have a view like this:

<form action="<c:url value="/book"/>" method="post">
    <label for="isbn">
        isbn:
    </label>
    <input type="text" name="isbn" id="isbn"/>
    <input type="submit"/>
</form>

and a Servlet:

@WebServlet(urlPatterns = "/book")
public class BookServlet extends HttpServlet {

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        BookService bookService = new BookServiceImpl();
        String isbn = req.getParameter("isbn");
        Book withIsbn = bookService.getWithIsbn(isbn);
        req.setAttribute("book", withIsbn);
        req.getRequestDispatcher("/isbn.jsp").forward(req,resp);
    }
}

#4 Is it ok that the Servlet initialises a Service object for each call? Or should it have a private static Service object?(I think not, but I am not sure thus asking..)

As I said, (just for learning purposes) I want to make such a basic web app which is maintainable and which follows OOP principles, without using any other frameworks such as Spring.

Koray Tugay
  • 1.5k
  • 5
  • 20
  • 44