org.osiam.resource_server.storage.dao.ResourceDao.java Source code

Java tutorial

Introduction

Here is the source code for org.osiam.resource_server.storage.dao.ResourceDao.java

Source

/*
 * Copyright (C) 2013 tarent AG
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

package org.osiam.resource_server.storage.dao;

import java.util.List;
import java.util.Set;

import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.NonUniqueResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Order;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.criteria.Subquery;
import javax.persistence.metamodel.SingularAttribute;

import org.antlr.v4.runtime.tree.ParseTree;
import org.osiam.resource_server.resources.exceptions.OsiamException;
import org.osiam.resource_server.resources.exceptions.ResourceNotFoundException;
import org.osiam.resource_server.storage.entities.GroupEntity;
import org.osiam.resource_server.storage.entities.ResourceEntity;
import org.osiam.resource_server.storage.entities.ResourceEntity_;
import org.osiam.resource_server.storage.query.FilterParser;
import org.springframework.stereotype.Repository;

@Repository
public class ResourceDao {

    @PersistenceContext
    private EntityManager em;

    public <T extends ResourceEntity> SearchResult<T> search(Class<T> clazz, ParseTree filterTree, int count,
            int startIndex, String sortBy, String sortOrder, FilterParser<T> filterParser) {

        CriteriaBuilder cb = em.getCriteriaBuilder();

        CriteriaQuery<T> resourceQuery = cb.createQuery(clazz);
        Root<T> resourceRoot = resourceQuery.from(clazz);

        Subquery<Long> internalIdQuery = resourceQuery.subquery(Long.class);
        Root<T> internalIdRoot = internalIdQuery.from(clazz);
        internalIdQuery.select(internalIdRoot.get(ResourceEntity_.internalId));

        if (filterTree != null && filterTree.getChildCount() > 0) {
            Predicate predicate = filterParser.createPredicateAndJoin(filterTree, internalIdRoot);
            internalIdQuery.where(predicate);
        }

        resourceQuery.select(resourceRoot)
                .where(cb.in(resourceRoot.get(ResourceEntity_.internalId)).value(internalIdQuery));

        // TODO: evaluate if a User-/GroupDao supplied default sortBy field is possible
        Expression<?> sortByField = resourceRoot.get(ResourceEntity_.id);

        if (sortBy != null && !sortBy.isEmpty()) {
            sortByField = filterParser.createSortByField(sortBy, resourceRoot);
        }

        // default order is ascending
        Order order = cb.asc(sortByField);

        if (sortOrder.equalsIgnoreCase("descending")) {
            order = cb.desc(sortByField);
        }

        resourceQuery.orderBy(order);

        TypedQuery<T> query = em.createQuery(resourceQuery);
        query.setFirstResult(startIndex);
        query.setMaxResults(count);

        List<T> results = query.getResultList();

        long totalResult = getTotalResults(clazz, internalIdQuery);

        return new SearchResult<>(results, totalResult);
    }

    private <T extends ResourceEntity> long getTotalResults(Class<T> clazz, Subquery<Long> internalIdQuery) {

        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<Long> resourceQuery = cb.createQuery(Long.class);
        Root<T> resourceRoot = resourceQuery.from(clazz);

        resourceQuery.select(cb.count(resourceRoot))
                .where(cb.in(resourceRoot.get(ResourceEntity_.internalId)).value(internalIdQuery));

        Long total = em.createQuery(resourceQuery).getSingleResult();

        return total;
    }

    /**
     * Retrieves a single {@link ResourceEntity} by the given id.
     * 
     * @param id
     *        the id of the resource to retrieve it by
     * @param clazz
     *        the concrete resource entity class to retrieve (may also be {@link ResourceEntity})
     * @return The matching {@link ResourceEntity}
     * @throws ResourceNotFoundException
     *         if no {@link ResourceEntity} with the given id could be found
     */
    public <T extends ResourceEntity> T getById(String id, Class<T> clazz) {
        return getByAttribute(ResourceEntity_.id, id, clazz);
    }

    /**
     * Retrieves a single {@link ResourceEntity} by the given attribute and value.
     * 
     * @param attribute
     *        The attribute of the resource entity to retrieve it by
     * @param value
     *        The value of the attribute to compare it to
     * @param clazz
     *        The concrete resource entity class to retrieve (may also be {@link ResourceEntity})
     * @return The matching {@link ResourceEntity}
     * @throws ResourceNotFoundException
     *         If no {@link ResourceEntity} could be found
     * @throws OsiamException
     *         If more than 1 {@link ResourceEntity} was found
     */
    public <T extends ResourceEntity, V> T getByAttribute(SingularAttribute<? super T, V> attribute, V value,
            Class<T> clazz) {

        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<T> cq = cb.createQuery(clazz);
        Root<T> resource = cq.from(clazz);

        cq.select(resource).where(cb.equal(resource.get(attribute), value));

        TypedQuery<T> q = em.createQuery(cq);

        try {
            return q.getSingleResult();
        } catch (NoResultException nre) {
            throw new ResourceNotFoundException(
                    String.format("Resource with attribute '%s' set to '%s' not found", attribute.getName(), value),
                    nre);
        } catch (NonUniqueResultException nure) {
            throw new OsiamException(String.format("Muliple resources with attribute '%s' set to '%s' found",
                    attribute.getName(), value), nure);
        }
    }

    public <T extends ResourceEntity, V> boolean isUniqueAttributeAlreadyTaken(String attributeValue, String id,
            SingularAttribute<? super T, V> attribute, Class<T> clazz) {
        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<Long> cq = cb.createQuery(Long.class);
        Root<T> resource = cq.from(clazz);

        cq.select(cb.countDistinct(resource));

        Predicate predicate = cb.equal(resource.get(attribute), attributeValue);
        if (id != null) {
            Predicate ignoreId = cb.notEqual(resource.get(ResourceEntity_.id), id);
            predicate = cb.and(predicate, ignoreId);
        }
        cq.where(predicate);

        TypedQuery<Long> countQuery = em.createQuery(cq);

        return countQuery.getSingleResult() > 0;
    }

    public boolean isExternalIdAlreadyTaken(String externalId, String id) {
        return isUniqueAttributeAlreadyTaken(externalId, id, ResourceEntity_.externalId, ResourceEntity.class);
    }

    public boolean isExternalIdAlreadyTaken(String externalId) {
        return isExternalIdAlreadyTaken(externalId, null);
    }

    /**
     * Removes a {@link ResourceEntity} from the database by its id
     * 
     * @param id
     *        id of the {@link ResourceEntity}
     * @throws ResourceNotFoundException
     *         if no {@link ResourceEntity} could be found with the given id
     * @throws IllegalArgumentException
     *         if the instance is not a managed {@link ResourceEntity}
     */
    public void delete(String id) {
        ResourceEntity resourceEntity = getById(id, ResourceEntity.class);

        Set<GroupEntity> groups = resourceEntity.getGroups();
        for (GroupEntity group : groups) {
            group.removeMember(resourceEntity);
        }

        em.remove(resourceEntity);
    }

    public <T extends ResourceEntity> T update(T resourceEntity) {
        return em.merge(resourceEntity);
    }

    public <T extends ResourceEntity> void create(T resourceEntity) {
        em.persist(resourceEntity);
    }

}