Chapter 18. Designing client/server applications

 

In this chapter

  • Patterns for client/server architecture
  • Writing and testing a persistence layer
  • Integrating EJBs with JPA

Most JPA developers build client/server applications with a Java-based server accessing the database tier through Hibernate. Knowing how the EntityManager and system transactions work, you could probably come up with your own server architecture. You’d have to figure out where to create the EntityManager, when and how to close it, and how to set transaction boundaries.

You may be wondering what the relationship is between requests and responses from and to your client, and the persistence context and transactions on the server. Should a single system transaction handle each client request? Can several consecutive requests hold a persistence context open? How does detached entity state fit into this picture? Can you and should you serialize entity data between client and server? How will these decisions affect your client design?

Before we start answering these questions, we have to mention that we won’t talk about any specific frameworks besides JPA and EJB in this chapter. There are several reasons the code examples use EJBs in addition to JPA:

18.1. Creating a persistence layer

Path: /apps/app-model/src/main/java/org/jpwh/dao/GenericDAOImpl.java

public abstract class GenericDAOImpl<T, ID extends Serializable>
  implements GenericDAO<T, ID> {
<enter/>
  @PersistenceContext
    protected EntityManager em;
<enter/>
    protected final Class<T> entityClass;
<enter/>
    protected GenericDAOImpl(Class<T> entityClass) {
        this.entityClass = entityClass;
    }
<enter/>
    public void setEntityManager(EntityManager em) {
        this.em = em;
    }
<enter/>
    // ...
<enter/>
}

Path: /apps/app-model/src/main/java/org/jpwh/dao/GenericDAOImpl.java

public abstract class GenericDAOImpl<T, ID extends Serializable>
    implements GenericDAO<T, ID> {
<enter/>
    // ...
<enter/>
    public T findById(ID id) {
        return findById(id, LockModeType.NONE);
    }
<enter/>
    public T findById(ID id, LockModeType lockModeType) {
        return em.find(entityClass, id, lockModeType);
    }
<enter/>
    public T findReferenceById(ID id) {
        return em.getReference(entityClass, id);
    }
<enter/>
    public List<T> findAll() {
        CriteriaQuery<T> c =
            em.getCriteriaBuilder().createQuery(entityClass);
        c.select(c.from(entityClass));
        return em.createQuery(c).getResultList();
    }
<enter/>
    public Long getCount() {
        CriteriaQuery<Long> c =
           em.getCriteriaBuilder().createQuery(Long.class);
        c.select(em.getCriteriaBuilder().count(c.from(entityClass)));
        return em.createQuery(c).getSingleResult();
    }
<enter/>
    // ...
}

Path: /apps/app-model/src/main/java/org/jpwh/dao/GenericDAOImpl.java

public abstract class GenericDAOImpl<T, ID extends Serializable>
    implements GenericDAO<T, ID> {
<enter/>
    // ...
<enter/>
    public T makePersistent(T instance) {
        // merge() handles transient AND detached instances
        return em.merge(instance);
    }
<enter/>
    public void makeTransient(T instance) {
        em.remove(instance);
    }
<enter/>
    public void checkVersion(T entity, boolean forceUpdate) {
        em.lock(
            entity,
            forceUpdate
                ? LockModeType.OPTIMISTIC_FORCE_INCREMENT
                : LockModeType.OPTIMISTIC
        );
    }
}

Path: /apps/app-model/src/main/java/org/jpwh/dao/ItemDAOImpl.java

@Stateless
public class ItemDAOImpl extends GenericDAOImpl<Item, Long>
    implements ItemDAO {
<enter/>
    public ItemDAOImpl() {
        super(Item.class);
    }
<enter/>
    // ...
}

Path: /apps/app-model/src/main/java/org/jpwh/dao/BidDAOImpl.java

@Stateless
public class BidDAOImpl extends GenericDAOImpl<Bid, Long>
    implements BidDAO {
<enter/>
    public BidDAOImpl() {
        super(Bid.class);
    }
}

18.2. Building a stateless server

Path: /apps/app-stateless-server/src/test/java/org/jpwh/test/stateless/AuctionServiceTest.java