All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.eclecticlogic.pedal.dm.AbstractDAO Maven / Gradle / Ivy

/**
 * Copyright (c) 2014 Eclectic Logic LLC
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 */
package com.eclecticlogic.pedal.dm;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Optional;

import javax.persistence.EntityManager;
import javax.persistence.LockModeType;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import javax.persistence.metamodel.Attribute;
import javax.persistence.metamodel.EntityType;
import javax.persistence.metamodel.SingularAttribute;

import com.eclecticlogic.pedal.ProviderAccess;
import com.eclecticlogic.pedal.Transaction;
import com.eclecticlogic.pedal.dm.internal.MetamodelUtil;
import com.eclecticlogic.pedal.dm.internal.SelectImpl;
import com.eclecticlogic.pedal.dm.internal.UpdateImpl;
import com.google.common.collect.Lists;

public abstract class AbstractDAO implements DAO, DAOMeta {

    private Transaction transaction;
    private EntityManager entityManager;
    private DateTimeProvider dateTimeProvider;
    private ProviderAccess providerAccess;
    private boolean insertDateTimeAware, insertDateAware, updateDateTimeAware, updateDateAware, updateDTRequired;


    /**
     * Subclasses should override this and call this via a @PostContruct annotation or other means. 
     */
    protected void init() {
        if (dateTimeProvider != null) {
            setupInsertDateTimeFlags();
            setupUpdateDateTimeFlags();
        }
    }


    protected void setDateTimeProvider(DateTimeProvider dateTimeProvider) {
        this.dateTimeProvider = dateTimeProvider;
    }


    private void setupUpdateDateTimeFlags() {
        Attribute attr = null;
        try {
            attr = getEntityType().getAttribute(dateTimeProvider.getUpdatedDateProperty());
        } catch (IllegalArgumentException e) {
            // noop. This is thrown if the attribute doesn't exist.
        }
        if (attr != null) {
            Temporal temporalAnnotation = null;
            Member member = attr.getJavaMember();
            if (member instanceof Field && ((Field) member).isAnnotationPresent(Temporal.class)) {
                temporalAnnotation = ((Field) member).getAnnotation(Temporal.class);
            } else if (member instanceof Method && ((Method) member).isAnnotationPresent(Temporal.class)) {
                temporalAnnotation = ((Method) member).getAnnotation(Temporal.class);
            }
            if (temporalAnnotation != null) {
                updateDateTimeAware = temporalAnnotation.value() == TemporalType.TIMESTAMP;
                updateDateAware = temporalAnnotation.value() == TemporalType.DATE;
            }
            updateDTRequired = !((SingularAttribute) attr).isOptional();
        }
    }


    private void setupInsertDateTimeFlags() {
        Attribute attr = null;
        try {
            attr = getEntityType().getAttribute(dateTimeProvider.getInsertedDateProperty());
        } catch (IllegalArgumentException e) {
            // noop. This is thrown if the attribute doesn't exist.
        }
        if (attr != null) {
            Temporal temporalAnnotation = null;
            Member member = attr.getJavaMember();
            if (member instanceof Field && ((Field) member).isAnnotationPresent(Temporal.class)) {
                temporalAnnotation = ((Field) member).getAnnotation(Temporal.class);
            } else if (member instanceof Method && ((Method) member).isAnnotationPresent(Temporal.class)) {
                temporalAnnotation = ((Method) member).getAnnotation(Temporal.class);
            }
            if (temporalAnnotation != null) {
                insertDateTimeAware = temporalAnnotation.value() == TemporalType.TIMESTAMP;
                insertDateAware = temporalAnnotation.value() == TemporalType.DATE;
            }
        }
    }


    protected EntityManager getEntityManager() {
        return entityManager;
    }


    /**
     * This method can be overridden as-is with an added @PersistenceContext annotation to have Spring supply the entity manager. 
     * @param entityManager
     */
    public void setEntityManager(EntityManager entityManager) {
        this.entityManager = entityManager;
    }


    protected Transaction getTransaction() {
        return transaction;
    }


    public void setTransaction(Transaction transaction) {
        this.transaction = transaction;
    }


    protected ProviderAccess getProviderAccess() {
        return providerAccess;
    }


    public void setProviderAccess(ProviderAccess providerAccess) {
        this.providerAccess = providerAccess;
    }


    /**
     * @return The name of the entity's database table. This returns the overridden name if orm.xml modifies it. 
     */
    protected String getTableName() {
        return getProviderAccess().getTableName(getEntityClass());
    }


    @Override
    public EntityType getEntityType() {
        return getEntityManager().getEntityManagerFactory().getMetamodel().entity(getEntityClass());
    }


    @SuppressWarnings("unchecked")
    @Override
    public E create(final E entity) {
        return getTransaction().exec(
                () -> {
                    if (insertDateTimeAware) {
                        Attribute attr = (Attribute) getEntityType().getAttribute(
                                dateTimeProvider.getInsertedDateProperty());
                        MetamodelUtil.set(attr, entity, dateTimeProvider.fromCurrentDateTime());
                    } else if (insertDateAware) {
                        Attribute attr = (Attribute) getEntityType().getAttribute(
                                dateTimeProvider.getInsertedDateProperty());
                        MetamodelUtil.set(attr, entity, dateTimeProvider.fromCurrentDate());
                    }
                    if (updateDTRequired) {
                        setUpdateDateTimeIfRequired(entity);
                    }
                    getEntityManager().persist(entity);
                    return entity;
                });
    }


    @Override
    public List create(Collection entities) {
        return getTransaction().exec(() -> {
            List list = new ArrayList<>();
            for (E e : entities) {
                list.add(create(e));
            }
            return list;
        });
    }


    @Override
    public Optional findById(final P id) {
        return getTransaction().exec(() -> {
            return Optional.ofNullable(getEntityManager().find(getEntityClass(), id));
        });
    }


    @Override
    public List findById(final Collection ids) {
        // The in-clause doesn't like empty collections.
        if (!ids.isEmpty()) {
            return getTransaction().exec((context) -> {
                CriteriaBuilder builder = getEntityManager().getCriteriaBuilder();
                CriteriaQuery cq = builder.createQuery(getEntityClass());
                Root root = cq.from(getEntityClass());
                cq.select(root).where(root.get(getIdProperty()).in(ids));
                TypedQuery query = getEntityManager().createQuery(cq);
                return query.getResultList();
            });
        } else {
            return Lists.newArrayList();
        }
    }


    /**
     * @return Name of the primary key (id) java bean property.
     */
    protected String getIdProperty() {
        for (SingularAttribute attr : getEntityType().getSingularAttributes()) {
            if (attr.isId()) {
                return attr.getName();
            }
        }
        return null;
    }


    @SuppressWarnings("unchecked")
    private void setUpdateDateTimeIfRequired(final E entity) {
        if (updateDateTimeAware) {
            Attribute attr = (Attribute) getEntityType().getAttribute(
                    dateTimeProvider.getUpdatedDateProperty());
            MetamodelUtil.set(attr, entity, dateTimeProvider.fromCurrentDateTime());
        } else if (updateDateAware) {
            Attribute attr = (Attribute) getEntityType().getAttribute(
                    dateTimeProvider.getUpdatedDateProperty());
            MetamodelUtil.set(attr, entity, dateTimeProvider.fromCurrentDate());
        }
    }


    @Override
    public E update(final E entity) {
        return getTransaction().exec(() -> {
            setUpdateDateTimeIfRequired(entity);
            E t = getEntityManager().merge(entity);
            getEntityManager().persist(t);
            return t;
        });
    }


    @Override
    public List update(final Collection entities) {
        return getTransaction().exec(() -> {
            List list = new ArrayList<>();
            for (E e : entities) {
                list.add(update(e));
            }
            return list;
        });
    }


    @Override
    public E delete(final E entity) {
        return getTransaction().exec(() -> {
            E mergedObject = getEntityManager().merge(entity);
            getEntityManager().remove(mergedObject);
            return mergedObject;
        });
    }


    @Override
    public List delete(final Collection entities) {
        return getTransaction().exec(() -> {
            List list = new ArrayList<>();
            for (E e : entities) {
                list.add(delete(e));
            }
            return list;
        });
    }


    @Override
    public E lock(final E entity, final LockModeType lockMode) {
        return getTransaction().exec(() -> {
            getEntityManager().refresh(entity, lockMode);
            getEntityManager().flush();
            return entity;
        });
    }


    @Override
    public E lockById(P id, LockModeType lockMode) {
        return getTransaction().exec(() -> {
            return getEntityManager().find(getEntityClass(), id, lockMode);
        });
    }


    protected Select select(String query, boolean nativeQuery) {
        SelectImpl select = new SelectImpl(getEntityManager(), getTransaction());
        select.setQuery(query, nativeQuery);
        return select;
    }


    protected Select select(String query) {
        SelectImpl select = new SelectImpl(getEntityManager(), getTransaction());
        select.setQuery(query);
        return select;
    }


    protected Select select(CriteriaQuery query) {
        SelectImpl select = new SelectImpl(getEntityManager(), getTransaction());
        select.setQuery(query);
        return select;
    }


    protected Select select(TypedQuery query) {
        SelectImpl select = new SelectImpl(getEntityManager(), getTransaction());
        select.setQuery(query);
        return select;
    }


    protected Update update(String query, boolean nativeQuery) {
        UpdateImpl update = new UpdateImpl(getEntityManager(), getTransaction());
        update.setQuery(query, nativeQuery);
        return update;
    }


    protected Update update(String query) {
        UpdateImpl update = new UpdateImpl(getEntityManager(), getTransaction());
        update.setQuery(query);
        return update;
    }


    protected Update update(TypedQuery query) {
        UpdateImpl update = new UpdateImpl(getEntityManager(), getTransaction());
        update.setQuery(query);
        return update;
    }


    protected TypedQuery getFindAllQuery() {
        CriteriaBuilder builder = getEntityManager().getCriteriaBuilder();
        CriteriaQuery criteriaQuery = builder.createQuery(getEntityClass());
        Root root = criteriaQuery.from(getEntityClass());
        criteriaQuery.select(root);
        return getEntityManager().createQuery(criteriaQuery);
    }


    @Override
    public List findAll() {
        return getFindAllQuery().getResultList();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy