Any comments? I tried to make my code modular and testable. I tried to make use of dependency injection without using any frameworks. All the classes are stateless, immutable and thread-safe (I think). I also tried to code to interfaces, not implementations.
Utils
package biz.tugay.sakila.core.utils;
import javax.persistence.EntityManager;
/**
* User: Koray Tugay (koray@tugay.biz)
* Date: 9/13/2016
* Time: 8:26 PM
*/
public interface SakilaEntityManagerFactory {
EntityManager getEntityManager();
void closeFactory();
}
package biz.tugay.sakila.core.utils;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
/**
* User: Koray Tugay (koray@tugay.biz)
* Date: 9/13/2016
* Time: 6:00 PM
*/
public class SakilaEntityManagerFactoryImpl implements SakilaEntityManagerFactory {
private static EntityManagerFactory entityManagerFactory;
public SakilaEntityManagerFactoryImpl(String persistenceUnitName) {
if (entityManagerFactory == null) {
entityManagerFactory = Persistence.createEntityManagerFactory(persistenceUnitName);
}
}
public EntityManager getEntityManager() {
final EntityManager entityManager = entityManagerFactory.createEntityManager();
return entityManager;
}
public void closeFactory() {
entityManagerFactory.close();
}
}
Model Layer
package biz.tugay.sakila.core.model;
import java.io.Serializable;
/**
* User: Koray Tugay (koray@tugay.biz)
* Date: 9/13/2016
* Time: 8:56 PM
*/
public abstract class BaseModelObject implements Serializable {
protected int id;
public abstract int getId();
public abstract void setId(int id);
}
package biz.tugay.sakila.core.model;
import javax.persistence.*;
/**
* User: Koray Tugay (koray@tugay.biz)
* Date: 9/13/2016
* Time: 8:20 PM
*/
@Entity
@Table(name = "actor")
public class Actor extends BaseModelObject {
private String firstname;
private String lastname;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Basic
@Column(name = "first_name")
public String getFirstname() {
return firstname;
}
public void setFirstname(String firstname) {
this.firstname = firstname;
}
@Basic
@Column(name = "last_name")
public String getLastname() {
return lastname;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Actor actor = (Actor) o;
if (firstname != null ? !firstname.equals(actor.firstname) : actor.firstname != null) return false;
return lastname != null ? lastname.equals(actor.lastname) : actor.lastname == null;
}
@Override
public int hashCode() {
int result = firstname != null ? firstname.hashCode() : 0;
result = 31 * result + (lastname != null ? lastname.hashCode() : 0);
return result;
}
}
DAO Layer package biz.tugay.sakila.core.dao;
import biz.tugay.sakila.core.model.BaseModelObject;
import javax.persistence.EntityManager;
import java.util.Collection;
import java.util.List;
/**
* User: Koray Tugay (koray@tugay.biz)
* Date: 9/13/2016
* Time: 8:47 PM
*/
public interface BaseDao<Entity extends BaseModelObject> {
EntityManager entityManager();
Entity get(EntityManager entityManager, int id);
List<Entity> getAll(EntityManager entityManager);
void beginTransaction(EntityManager entityManager);
void insertNew(EntityManager entityManager, Entity entity);
void commit(EntityManager entityManager);
void rollback(EntityManager entityManager);
void flush(EntityManager entityManager);
void close(EntityManager entityManager);
void insertMultiple(EntityManager entityManager, Collection<Entity> actors);
void remove(EntityManager entityManager, Entity e);
void update(EntityManager entityManager, Entity e);
}
package biz.tugay.sakila.core.dao;
import biz.tugay.sakila.core.model.BaseModelObject;
import biz.tugay.sakila.core.utils.SakilaEntityManagerFactory;
import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.persistence.TypedQuery;
import java.util.Collection;
import java.util.List;
/**
* User: Koray Tugay (koray@tugay.biz)
* Date: 9/13/2016
* Time: 8:49 PM
*/
public abstract class BaseDaoImpl<Entity extends BaseModelObject> implements BaseDao<Entity> {
private final SakilaEntityManagerFactory sakilaEntityManagerFactory;
protected final Class<Entity> clazz;
public BaseDaoImpl(SakilaEntityManagerFactory sakilaEntityManagerFactory, Class<Entity> clazz) {
this.sakilaEntityManagerFactory = sakilaEntityManagerFactory;
this.clazz = clazz;
}
@Override
public EntityManager entityManager() {
final EntityManager entityManager = sakilaEntityManagerFactory.getEntityManager();
return entityManager;
}
@Override
public Entity get(EntityManager entityManager, int id) {
final Entity entity = entityManager.find(clazz, id);
return entity;
}
@Override
public List<Entity> getAll(EntityManager entityManager) {
final String modelName = clazz.getSimpleName();
final String query = String.format("From %s", modelName);
final TypedQuery<Entity> typedQuery = entityManager.createQuery(query, clazz);
final List<Entity> resultList = typedQuery.getResultList();
return resultList;
}
public void beginTransaction(EntityManager entityManager) {
final EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
}
@Override
public void insertNew(EntityManager entityManager, Entity entity) {
entityManager.persist(entity);
}
@Override
public void insertMultiple(EntityManager entityManager, Collection<Entity> entityCollection) {
for (Entity entity : entityCollection) {
insertNew(entityManager, entity);
}
}
@Override
public void update(EntityManager entityManager, Entity entity) {
entityManager.merge(entity);
}
@Override
public void remove(EntityManager entityManager, Entity entity) {
final Entity t = get(entityManager, entity.getId());
entityManager.remove(t);
}
@Override
public void commit(EntityManager entityManager) {
entityManager.getTransaction().commit();
}
@Override
public void rollback(EntityManager entityManager) {
entityManager.getTransaction().rollback();
}
@Override
public void flush(EntityManager entityManager) {
entityManager.flush();
}
@Override
public void close(EntityManager entityManager) {
entityManager.close();
}
}
package biz.tugay.sakila.core.dao;
import biz.tugay.sakila.core.model.Actor;
import javax.persistence.EntityManager;
import java.util.Collection;
/**
* User: Koray Tugay (koray@tugay.biz)
* Date: 9/14/2016
* Time: 6:44 PM
*/
public interface ActorDao extends BaseDao<Actor> {
Collection<Actor> byLastname(EntityManager entityManager, String lastname);
}
package biz.tugay.sakila.core.dao;
import biz.tugay.sakila.core.model.Actor;
import biz.tugay.sakila.core.utils.SakilaEntityManagerFactory;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import java.util.Collection;
/**
* User: Koray Tugay (koray@tugay.biz)
* Date: 9/13/2016
* Time: 8:23 PM
*/
public class ActorDaoImpl extends BaseDaoImpl<Actor> implements ActorDao {
public ActorDaoImpl(SakilaEntityManagerFactory sakilaEntityManagerFactory) {
super(sakilaEntityManagerFactory, Actor.class);
}
/* Ignores case! */
@Override
public Collection<Actor> byLastname(EntityManager entityManager, String lastname) {
final String query = "SELECT a FROM Actor a WHERE UPPER(a.lastname) = :lastname";
final TypedQuery<Actor> byLastnameQuery = entityManager.createQuery(query, clazz);
byLastnameQuery.setParameter("lastname", lastname.toUpperCase());
final Collection<Actor> byLastnameResultList = byLastnameQuery.getResultList();
return byLastnameResultList;
}
}
Service Layer package biz.tugay.sakila.core.service;
import biz.tugay.sakila.core.model.BaseModelObject;
import java.util.List;
/**
* User: Koray Tugay (koray@tugay.biz)
* Date: 9/14/2016
* Time: 4:42 PM
*/
public interface BaseService<Entity extends BaseModelObject> {
Entity get(int id);
List<Entity> getAll();
void insertNew(Entity entity);
void delete(Entity entity);
void update(Entity entity);
}
package biz.tugay.sakila.core.service;
import biz.tugay.sakila.core.dao.BaseDao;
import biz.tugay.sakila.core.model.BaseModelObject;
import javax.persistence.EntityManager;
import java.util.List;
/**
* User: Koray Tugay (koray@tugay.biz)
* Date: 9/14/2016
* Time: 4:30 PM
*/
public abstract class BaseServiceImpl<Dao extends BaseDao, Entity extends BaseModelObject> implements BaseService<Entity> {
final Dao dao;
public BaseServiceImpl(Dao dao) {
this.dao = dao;
}
public Entity get(int id) {
final EntityManager entityManager = dao.entityManager();
final BaseModelObject object = dao.get(entityManager, id);
dao.close(entityManager);
return (Entity) object;
}
public final List<Entity> getAll() {
final EntityManager entityManager = dao.entityManager();
final List<Entity> all = dao.getAll(entityManager);
dao.close(entityManager);
return all;
}
public final void insertNew(final Entity entity) {
final EntityManager entityManager = dao.entityManager();
dao.insertNew(entityManager, entity);
dao.beginTransaction(entityManager);
dao.commit(entityManager);
dao.close(entityManager);
}
public final void update(final Entity entity) {
final EntityManager entityManager = dao.entityManager();
dao.beginTransaction(entityManager);
dao.update(entityManager, entity);
dao.commit(entityManager);
dao.close(entityManager);
}
public final void delete(final Entity entity) {
final EntityManager entityManager = dao.entityManager();
dao.beginTransaction(entityManager);
dao.remove(entityManager, entity);
dao.commit(entityManager);
dao.close(entityManager);
}
}
package biz.tugay.sakila.core.service;
import biz.tugay.sakila.core.model.Actor;
import java.util.Collection;
/**
* User: Koray Tugay (koray@tugay.biz)
* Date: 9/14/2016
* Time: 6:38 PM
*/
public interface ActorService extends BaseService<Actor> {
Collection<Actor> byLastname(String lastname);
}
package biz.tugay.sakila.core.service;
import biz.tugay.sakila.core.dao.ActorDao;
import biz.tugay.sakila.core.model.Actor;
import javax.persistence.EntityManager;
import java.util.Collection;
/**
* User: Koray Tugay (koray@tugay.biz)
* Date: 9/14/2016
* Time: 4:04 PM
*/
public final class ActorServiceImpl extends BaseServiceImpl<ActorDao, Actor> implements ActorService {
public ActorServiceImpl(ActorDao actorDAO) {
super(actorDAO);
}
@Override
public final Collection<Actor> byLastname(final String lastname) {
final EntityManager entityManager = dao.entityManager();
final Collection<Actor> byLastname = dao.byLastname(entityManager, lastname);
dao.close(entityManager);
return byLastname;
}
}
Web Layer(JSF Managed Beans)
package biz.tugay.sakila.web;
import javax.faces.context.FacesContext;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
/**
* User: Koray Tugay (koray@tugay.biz)
* Date: 9/14/2016
* Time: 9:52 PM
*/
public class BasePageBacking {
protected <BeanClass> BeanClass getBean(String beanName, Class<BeanClass> clazz) {
final ServletContext servletContext
= (ServletContext) FacesContext.getCurrentInstance().getExternalContext().getContext();
final Object bean = servletContext.getAttribute(beanName);
final BeanClass castBean = clazz.cast(bean);
return castBean;
}
protected HttpServletRequest getRequest() {
return (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
}
}
package biz.tugay.sakila.web.actor;
import biz.tugay.sakila.core.model.Actor;
import biz.tugay.sakila.core.service.ActorService;
import biz.tugay.sakila.web.BaseFormBacking;
import lombok.Getter;
import lombok.Setter;
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
/**
* User: Koray Tugay (koray@tugay.biz)
* Date: 9/15/2016
* Time: 4:29 PM
*/
@ManagedBean
@RequestScoped
public final class ActorFormBacking extends BaseFormBacking {
@Getter
@Setter
private Actor actor;
private final ActorService actorService;
@SuppressWarnings("unused")
// Invoked by JSF!
public ActorFormBacking() {
actorService = getBean("actorService", ActorService.class);
actor = new Actor();
}
@PostConstruct
// Invoked by JSF!
public final void init() {
final String actorId = getRequest().getParameter("actorId");
if (actorId != null) {
id = Integer.parseInt(actorId);
actor = actorService.get(id);
}
}
public final String insertNewActor() {
actorService.insertNew(actor);
return "actorInserted";
}
public final String updateActor(final int id) {
actor.setId(id);
actorService.update(actor);
return "actorUpdated";
}
public final String deleteActor(Actor actor) {
actorService.delete(actor);
return "actorDeleted";
}
// For unit tests
public ActorFormBacking(ActorService actorService) {
this.actorService = actorService;
}
}
Initializing the application when the server starts:
package biz.tugay.sakila.web.listener;
import biz.tugay.sakila.core.dao.ActorDao;
import biz.tugay.sakila.core.dao.ActorDaoImpl;
import biz.tugay.sakila.core.service.ActorService;
import biz.tugay.sakila.core.service.ActorServiceImpl;
import biz.tugay.sakila.core.utils.SakilaEntityManagerFactory;
import biz.tugay.sakila.core.utils.SakilaEntityManagerFactoryImpl;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
/**
* User: Koray Tugay (koray@tugay.biz)
* Date: 9/14/2016
* Time: 5:31 PM
*/
@WebListener
public class SakilaApplicationServletContextListenerImpl implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
final ServletContext servletContext = sce.getServletContext();
final SakilaEntityManagerFactory sakilaEntityManagerFactory = new SakilaEntityManagerFactoryImpl("SakilaPU");
servletContext.setAttribute("sakilaEntityManagerFactory", sakilaEntityManagerFactory);
final ActorDao actorDao = new ActorDaoImpl(sakilaEntityManagerFactory);
servletContext.setAttribute("actorDao", actorDao);
final ActorService actorService = new ActorServiceImpl(actorDao);
servletContext.setAttribute("actorService", actorService);
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
final ServletContext servletContext = sce.getServletContext();
final SakilaEntityManagerFactory sakilaEntityManagerFactory = (SakilaEntityManagerFactory) servletContext.getAttribute("sakilaEntityManagerFactory");
sakilaEntityManagerFactory.closeFactory();
}
}
The source code is also available on GitHub.