concrete facade for JPA controller classes from abstract, generic facade

2.7k views Asked by At

I have a few classes very like the following LinkFacade. How can I make a "generic" facade to eliminate, or at least reduce, the methods duplicated across the different "facade" classes?

Example "facade":

package net.bounceme.dur.jpa.facades;

import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import net.bounceme.dur.jpa.controllers.LinkJpaController;
import net.bounceme.dur.jpa.entities.Link;
import net.bounceme.dur.jpa.exceptions.NonexistentEntityException;

public class LinkFacade {

    private final static Logger log = Logger.getLogger(LinkFacade.class.getName());
    private final EntityManagerFactory emf = Persistence.createEntityManagerFactory("SeleniumIteratorPU");
    private final LinkJpaController controller = new LinkJpaController(emf);

    public LinkFacade() {
    }

    public void create(Link link) {
        controller.create(link);
    }

    public void edit(Link link) {
        try {
            controller.edit(link);
        } catch (NonexistentEntityException ex) {
            Logger.getLogger(LinkFacade.class.getName()).log(Level.SEVERE, null, ex);
        } catch (Exception ex) {
            Logger.getLogger(LinkFacade.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void destroy(int id) {
        try {
            controller.destroy(id);
        } catch (NonexistentEntityException ex) {
            Logger.getLogger(LinkFacade.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public List<Link> findEntities() {
        return controller.findLinkEntities();
    }

    public void findEntity(int id) {
        controller.findLink(id);
    }

    public int getCount() {
        return controller.getLinkCount();
    }

}

The methods in these classes are quite repetitive. How can I abstract, if that's being used correctly, these methods in a generic class such as:

package net.bounceme.dur.jpa.facades;

import java.util.List;
import java.util.logging.Logger;
import javax.persistence.EntityManager;

public abstract class AbstractFacade<T> {

    private final static Logger log = Logger.getLogger(AbstractFacade.class.getName());
    private final Class<T> entityClass;

    public AbstractFacade(Class<T> entityClass) {
        this.entityClass = entityClass;
    }

    protected abstract EntityManager getEntityManager();

    public void create(T entity) {
    }

    public void edit(T entity) {
    }

    public void remove(T entity) {
    }

    public T find(Object id) {
    }

    public List<T> findAll() {
    }

    public List<T> findRange(int[] range) {
    }

    public int count() {
    }

}

The corresponding JpaController which correlates with this "facade":

package net.bounceme.dur.jpa.controllers;

import net.bounceme.dur.jpa.entities.Feed;
import net.bounceme.dur.jpa.entities.Link;
import net.bounceme.dur.jpa.exceptions.NonexistentEntityException;
import java.io.Serializable;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Query;
import javax.persistence.EntityNotFoundException;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;

public class LinkJpaController implements Serializable {

    public LinkJpaController(EntityManagerFactory emf) {
        this.emf = emf;
    }
    private EntityManagerFactory emf = null;

    public EntityManager getEntityManager() {
        return emf.createEntityManager();
    }

    public void create(Link link) {
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            Feed feedId = link.getFeedId();
            if (feedId != null) {
                feedId = em.getReference(feedId.getClass(), feedId.getId());
                link.setFeedId(feedId);
            }
            em.persist(link);
            if (feedId != null) {
                feedId.getLinkCollection().add(link);
                feedId = em.merge(feedId);
            }
            em.getTransaction().commit();
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public void edit(Link link) throws NonexistentEntityException, Exception {
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            Link persistentLink = em.find(Link.class, link.getId());
            Feed feedIdOld = persistentLink.getFeedId();
            Feed feedIdNew = link.getFeedId();
            if (feedIdNew != null) {
                feedIdNew = em.getReference(feedIdNew.getClass(), feedIdNew.getId());
                link.setFeedId(feedIdNew);
            }
            link = em.merge(link);
            if (feedIdOld != null && !feedIdOld.equals(feedIdNew)) {
                feedIdOld.getLinkCollection().remove(link);
                feedIdOld = em.merge(feedIdOld);
            }
            if (feedIdNew != null && !feedIdNew.equals(feedIdOld)) {
                feedIdNew.getLinkCollection().add(link);
                feedIdNew = em.merge(feedIdNew);
            }
            em.getTransaction().commit();
        } catch (Exception ex) {
            String msg = ex.getLocalizedMessage();
            if (msg == null || msg.length() == 0) {
                Integer id = link.getId();
                if (findLink(id) == null) {
                    throw new NonexistentEntityException("The link with id " + id + " no longer exists.");
                }
            }
            throw ex;
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public void destroy(Integer id) throws NonexistentEntityException {
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            Link link;
            try {
                link = em.getReference(Link.class, id);
                link.getId();
            } catch (EntityNotFoundException enfe) {
                throw new NonexistentEntityException("The link with id " + id + " no longer exists.", enfe);
            }
            Feed feedId = link.getFeedId();
            if (feedId != null) {
                feedId.getLinkCollection().remove(link);
                feedId = em.merge(feedId);
            }
            em.remove(link);
            em.getTransaction().commit();
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public List<Link> findLinkEntities() {
        return findLinkEntities(true, -1, -1);
    }

    public List<Link> findLinkEntities(int maxResults, int firstResult) {
        return findLinkEntities(false, maxResults, firstResult);
    }

    private List<Link> findLinkEntities(boolean all, int maxResults, int firstResult) {
        EntityManager em = getEntityManager();
        try {
            CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
            cq.select(cq.from(Link.class));
            Query q = em.createQuery(cq);
            if (!all) {
                q.setMaxResults(maxResults);
                q.setFirstResult(firstResult);
            }
            return q.getResultList();
        } finally {
            em.close();
        }
    }

    public Link findLink(Integer id) {
        EntityManager em = getEntityManager();
        try {
            return em.find(Link.class, id);
        } finally {
            em.close();
        }
    }

    public int getLinkCount() {
        EntityManager em = getEntityManager();
        try {
            CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
            Root<Link> rt = cq.from(Link.class);
            cq.select(em.getCriteriaBuilder().count(rt));
            Query q = em.createQuery(cq);
            return ((Long) q.getSingleResult()).intValue();
        } finally {
            em.close();
        }
    }

}

What should the concrete facade look like?

see also:

https://stackoverflow.com/a/5636924/262852

http://en.wikipedia.org/wiki/Facade_pattern

1

There are 1 answers

0
thomas.mc.work On

You are right with the assumption that these parts are repetitive and therefore evitable. Netbeans shows you a way to realize it when you use the wizard to create JSF Pages form Entity Classes. The result looks like this:

AbstractFacade.java:

public abstract class AbstractFacade<T> {
    private final Class<T> entityClass;

    public AbstractFacade(Class<T> entityClass) {
        this.entityClass = entityClass;
    }

    protected abstract EntityManager getEntityManager();

    public void create(T entity) {
        getEntityManager().persist(entity);
    }

    public T edit(T entity) {
        return getEntityManager().merge(entity);
    }

    public void remove(T entity) {
        getEntityManager().remove(getEntityManager().merge(entity));
    }

    // some more find helper methods ...
}

ConcreteEntityFacade.java:

public class ConcreteEntityFacade extends AbstractFacade<ConcreteEntity> {
    @PersistenceContext
    private EntityManager em;

    @Override
    protected EntityManager getEntityManager() {
        return em;
    }

    public ConcreteEntityFacade() {
        super(ConcreteEntity.class);
    }
}

I hope that helps.