GenericDao.java :  » JPA » generic-dao » com » szczytowski » genericdao » impl » Java Open Source

Java Open Source » JPA » generic dao 
generic dao » com » szczytowski » genericdao » impl » GenericDao.java
package com.szczytowski.genericdao.impl;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.EntityManager;
import javax.persistence.EntityNotFoundException;
import javax.persistence.NoResultException;
import javax.persistence.NonUniqueResultException;

import com.szczytowski.genericdao.api.IActivable;
import com.szczytowski.genericdao.api.IDao;
import com.szczytowski.genericdao.api.IDefaultable;
import com.szczytowski.genericdao.api.IEntity;
import com.szczytowski.genericdao.api.IHiddenable;
import com.szczytowski.genericdao.api.IInheritable;
import com.szczytowski.genericdao.criteria.Criteria;
import com.szczytowski.genericdao.criteria.restriction.Restrictions;

/**
 * Abstract implementation of generic DAO.
 * 
 * @param <T> entity type, it must implements at least <code>IEntity</code>
 * @param <I> entity's primary key, it must be serializable
 * @see IEntity
 * @author Maciej Szczytowski <mszczytowski-genericdao@gmail.com>
 * @since 1.0
 */
public class GenericDao<T extends IEntity<I>, I extends Serializable> implements IDao<T, I> {

  private EntityManager entityManager;

  private Class<IEntity<I>> clazz;

  private boolean isDefaultable;

  private boolean isActivable;

  private boolean isHiddenable;

  private boolean isInheritable;

  /**
   * Default constructor. Use for extend this class.
   */
  @SuppressWarnings(value = "unchecked")
  public GenericDao() {

    Type[] types = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments();

    if (types[0] instanceof ParameterizedType) {
      // If the class has parameterized types, it takes the raw type.
      ParameterizedType type = (ParameterizedType) types[0];
      clazz = (Class<IEntity<I>>) type.getRawType();
    } else {
      clazz = (Class<IEntity<I>>) types[0];
    }
    checkGenericClass();
  }

  /**
   * Constructor with given {@link IEntity} implementation. Use for creting DAO without extending
   * this class.
   * 
   * @param clazz class with will be accessed by DAO methods
   */
  @SuppressWarnings(value = "unchecked")
  public GenericDao(Class<IEntity<I>> clazz) {
    this.clazz = clazz;
    checkGenericClass();
  }

  /**
   * Set entity manager.
   * 
   * @param entityManager entity manager
   */
  public void setEntityManager(EntityManager entityManager) {
    this.entityManager = entityManager;
  }

  @SuppressWarnings(value = "unchecked")
  @Override
  public T load(I id) throws EntityNotFoundException {
    T entity = get(id);
    if (entity == null) {
      throw new EntityNotFoundException("entity " + clazz + "#" + id + " was not found");
    }
    return entity;
  }

  @SuppressWarnings(value = "unchecked")
  @Override
  public T get(I id) {
    return (T) entityManager.find(clazz, id);
  }

  @SuppressWarnings(value = "unchecked")
  @Override
  public List<T> get(I... ids) {
    return findByCriteria(Criteria.forClass(clazz).add(Restrictions.in(IEntity.P_ID, ids)));
  }

  @SuppressWarnings(value = "unchecked")
  @Override
  public List<T> get(IInheritable<T> parent) {
    if (parent == null) {
      return findByCriteria(Criteria.forClass(clazz)
                                    .add(Restrictions.isNull(IInheritable.P_PARENT)));
    } else {
      return findByCriteria(Criteria.forClass(clazz).add(Restrictions.eq(IInheritable.P_PARENT,
                                                                         parent)));
    }
  }

  @SuppressWarnings(value = "unchecked")
  @Override
  public List<T> getAll() {
    return findByCriteria(Criteria.forClass(clazz));
  }

  @SuppressWarnings(value = "unchecked")
  @Override
  public List<T> findByExample(T example) {
    Criteria criteria = Criteria.forClass(clazz);

    Field[] fields = example.getClass().getDeclaredFields();

    for (Field field : fields) {
      if (field.getName().equals(IEntity.P_ID)) {
        continue;
      }
      if (field.getName().equals(IActivable.P_IS_ACTIVE)) {
        continue;
      }
      if (field.getName().equals(IDefaultable.P_IS_DEFAULT)) {
        continue;
      }
      if (field.getName().equals(IHiddenable.P_IS_HIDDEN)) {
        continue;
      }
      if (!field.isAnnotationPresent(Column.class) && !field.isAnnotationPresent(Basic.class)) {
        continue;
      }

      Object value = null;

      try {
        field.setAccessible(true);
        value = field.get(example);
      } catch (IllegalArgumentException e) {
        continue;
      } catch (IllegalAccessException e) {
        continue;
      }

      if (value == null) {
        continue;
      }

      criteria.add(Restrictions.eq(field.getName(), value));
    }

    if (example instanceof IHiddenable) {
      if (((IInheritable) example).getParent() == null) {
        criteria.add(Restrictions.isNull(IInheritable.P_PARENT));
      } else {
        criteria.add(Restrictions.eq(IInheritable.P_PARENT, ((IInheritable) example).getParent()));
      }
    }

    return findByCriteria(criteria);
  }

  @SuppressWarnings(value = "unchecked")
  @Override
  public void setAsDefault(IDefaultable object) {
    if (object.getExample() != null) {
      List<T> objects = findByExample((T) object.getExample());
      for (T o : objects) {
        if (object != o) {
          ((IDefaultable) o).setDefault(false);
          entityManager.merge(o);
        }
      }
    }
    object.setDefault(true);

    if (((T) object).getId() != null) {
      entityManager.merge(object);
    } else {
      entityManager.persist(object);
    }
  }

  @Override
  public void save(final T object) {
    if (object.getId() != null) {
      entityManager.merge(object);
    } else {
      entityManager.persist(object);
    }
  }

  @Override
  public void save(final T... objects) {
    for (T object : objects) {
      if (object.getId() != null) {
        entityManager.merge(object);
      } else {
        entityManager.persist(object);
      }
    }
  }

  @Override
  public void delete(final I id) throws UnsupportedOperationException {
    delete(load(id));
  }

  @Override
  public void delete(final I... ids) throws UnsupportedOperationException {
    deleteAll(get(ids), true);
  }

  @Override
  public void delete(final T object) throws UnsupportedOperationException {
    if (isDefaultable) {
      checkIfDefault(object);
    }
    if (isHiddenable) {
      ((IHiddenable) object).setHidden(true);
      entityManager.merge(object);
    } else {
      entityManager.remove(object);
    }
  }

  @Override
  public void delete(final T... objects) throws UnsupportedOperationException {
    deleteAll(Arrays.asList(objects), true);
  }

  @Override
  public void deleteAll() throws UnsupportedOperationException {
    deleteAll(getAll(), false);
  }

  private void deleteAll(final Collection<T> objects, boolean checkIdDefault)
    throws UnsupportedOperationException
  {
    if (checkIdDefault) {
      if (isDefaultable) {
        for (T object : objects) {
          checkIfDefault(object);
        }
      }
    }
    if (isHiddenable) {
      for (T object : objects) {
        ((IHiddenable) object).setHidden(true);
        entityManager.merge(object);
      }
    } else {
      for (T object : objects) {
        entityManager.remove(object);
      }
    }
  }

  private void checkIfDefault(T entity) {
    if (((IDefaultable) entity).isDefault()) {
      throw new UnsupportedOperationException("can't delete default entity " + clazz + "#"
                                              + entity.getId());
    }
  }

  private void checkGenericClass() {
    for (Class i : clazz.getInterfaces()) {
      if (i == IDefaultable.class) {
        isDefaultable = true;
      } else if (i == IActivable.class) {
        isActivable = true;
      } else if (i == IHiddenable.class) {
        isHiddenable = true;
      } else if (i == IInheritable.class) {
        isInheritable = true;
      }
    }
  }

  @Override
  public void refresh(final T entity) {
    entityManager.refresh(entity);
  }

  @Override
  public void flushAndClear() {
    entityManager.flush();
    entityManager.clear();
  }

  /**
   * Retrieve objects using criteria. It is equivalent to <code>criteria.list(entityManager)</code>.
   * 
   * @param criteria criteria which will be executed
   * @return list of founded objects
   * @see javax.persistence.Query#getResultList()
   */
  @SuppressWarnings(value = "unchecked")
  protected List findByCriteria(Criteria criteria) {
    return criteria.list(entityManager);
  }

  /**
   * Retrieve an unique object using criteria. It is equivalent to
   * <code>criteria.uniqueResult(entityManager)</code>.
   * 
   * @param criteria criteria which will be executed
   * @return retrieved object
   * @throws NoResultException - if there is no result
   * @throws NonUniqueResultException - if more than one result
   * @see javax.persistence.Query#getSingleResult()
   */
  protected Object findUniqueByCriteria(Criteria criteria)
    throws NonUniqueResultException,
      NoResultException
  {
    return criteria.uniqueResult(entityManager);
  }

  @Override
  public boolean isActivable() {
    return isActivable;
  }

  @Override
  public boolean isDefaultable() {
    return isDefaultable;
  }

  @Override
  public boolean isHiddenable() {
    return isHiddenable;
  }

  @Override
  public boolean isInheritable() {
    return isInheritable;
  }

  /**
   * Get entity manager.
   * 
   * @return entity manager
   */
  protected EntityManager getEntityManager() {
    return entityManager;
  }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.