<commit_before>/*
 * 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.storage.dao;

import java.util.List;
import java.util.logging.Logger;

import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.hibernate.CacheMode;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Subqueries;
import org.osiam.resources.exceptions.ResourceNotFoundException;
import org.osiam.resources.helper.FilterParser;
import org.osiam.resources.scim.SCIMSearchResult;
import org.osiam.storage.entities.InternalIdSkeleton;

public abstract class InternalIdSkeletonDao {

    protected static final Logger LOGGER = Logger.getLogger(InternalIdSkeletonDao.class.getName()); // NOSONAR used in child classes

    @PersistenceContext
    protected EntityManager em; // NOSONAR used in child classes

    @Inject
    protected FilterParser filterParser;

    protected <T extends InternalIdSkeleton> T getInternalIdSkeleton(String id) {
        Query query = em.createNamedQuery("getById");
        query.setParameter("id", id);
        return getSingleInternalIdSkeleton(query, id);
    }

    @SuppressWarnings("unchecked")
    protected <T extends InternalIdSkeleton> T getSingleInternalIdSkeleton(Query query, String identifier) {
        List result = query.getResultList();
        if (result.isEmpty()) {
            throw new ResourceNotFoundException("Resource " + identifier + " not found.");
        }
        return (T) result.get(0);
    }

    protected <T> SCIMSearchResult<T> search(Class<T> clazz, String filter, int count, int startIndex, String sortBy,
                                             String sortOrder) {
        // create subquery criteria for all possible (internal) ids that match the filter (used by result and total count queries)
        DetachedCriteria idsOnlyCriteria = DetachedCriteria.forClass(clazz);
        createAliasesForCriteria(idsOnlyCriteria);
        if (filter != null && !filter.isEmpty()) {
            idsOnlyCriteria.add(filterParser.parse(filter, clazz).buildCriterion());
        }
        idsOnlyCriteria.setProjection(Projections.distinct(Projections.id()));

        List<T> results = getResults(idsOnlyCriteria, clazz, count, startIndex, sortBy, sortOrder);
        long totalResult = getTotalResults(idsOnlyCriteria, clazz);

        int newStartIndex = startIndex <1 ? 1 :startIndex;

        return new SCIMSearchResult<T>(results, totalResult, count, newStartIndex, getCoreSchema());
    }


    private <T> List<T> getResults(DetachedCriteria idsOnlyCriteria, Class<T> clazz, int count, int startIndex, String sortBy,
            String sortOrder) {
	    Criteria criteria = ((Session) em.getDelegate()).createCriteria(clazz);

        criteria.setReadOnly(true);
        criteria.setCacheMode(CacheMode.GET);
        criteria.setCacheable(true);

        criteria.add(Subqueries.propertyIn("internalId", idsOnlyCriteria));
        setSortOrder(sortBy, sortOrder, criteria);
        criteria.setMaxResults(count);
        criteria.setFirstResult(startIndex-1);//-1 due to scim spec and default of 1 instead of 0

        // FIXME: The next line should not be necessary, but it is ...
        criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);

        return criteria.list();
    }

    private void setSortOrder(String sortBy, String sortOrder, Criteria criteria) {
        if (sortOrder.equalsIgnoreCase("descending")) {
            criteria.addOrder(Order.desc(sortBy));
        } else {
            criteria.addOrder(Order.asc(sortBy));
        }
    }

    private <T> long getTotalResults(DetachedCriteria idsOnlyCriteria, Class<T> clazz) {
        Criteria countCriteria = ((Session) em.getDelegate()).createCriteria(clazz);

        countCriteria.setReadOnly(true);
        countCriteria.setCacheMode(CacheMode.GET);
        countCriteria.setCacheable(true);

        countCriteria.add(Subqueries.propertyIn("internalId", idsOnlyCriteria));
        countCriteria.setProjection(Projections.rowCount());
        Object totalResultAsObject = countCriteria.uniqueResult();

        return totalResultAsObject != null ? (long) totalResultAsObject : 0;
    }

    protected abstract void createAliasesForCriteria(DetachedCriteria criteria);
    protected abstract String getCoreSchema();
}<commit_msg>[enhancment] first steps taken to migrate to jpa 2 criteria api<commit_after>/*
 * 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.storage.dao;

import java.util.List;
import java.util.logging.Logger;

import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
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.Root;
import javax.persistence.criteria.Subquery;

import org.hibernate.CacheMode;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Subqueries;
import org.osiam.resources.exceptions.ResourceNotFoundException;
import org.osiam.resources.helper.FilterParser;
import org.osiam.resources.scim.SCIMSearchResult;
import org.osiam.storage.entities.InternalIdSkeleton;
import org.osiam.storage.entities.InternalIdSkeleton_;

public abstract class InternalIdSkeletonDao {

    protected static final Logger LOGGER = Logger.getLogger(InternalIdSkeletonDao.class.getName()); // NOSONAR used in child classes

    @PersistenceContext
    protected EntityManager em; // NOSONAR used in child classes

    @Inject
    protected FilterParser filterParser;

    protected <T extends InternalIdSkeleton> T getInternalIdSkeleton(String id) {
        Query query = em.createNamedQuery("getById");
        query.setParameter("id", id);
        return getSingleInternalIdSkeleton(query, id);
    }

    @SuppressWarnings("unchecked")
    protected <T extends InternalIdSkeleton> T getSingleInternalIdSkeleton(Query query, String identifier) {
        List result = query.getResultList();
        if (result.isEmpty()) {
            throw new ResourceNotFoundException("Resource " + identifier + " not found.");
        }
        return (T) result.get(0);
    }

    protected <T extends InternalIdSkeleton> SCIMSearchResult<T> search(Class<T> clazz, String filter, int count,
            int startIndex, String sortBy, String sortOrder) {

        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(InternalIdSkeleton_.internalId));

        // TODO: add predicates
        /*if (filter != null && !filter.isEmpty()) {
            idsOnlyCriteria.add(filterParser.parse(filter, clazz).buildCriterion());
        }*/

        List<T> results = getResults(idsOnlyCriteria, clazz, count, startIndex, sortBy, sortOrder);
        long totalResult = getTotalResults(idsOnlyCriteria, clazz);

        Expression<?> sortByField = resourceRoot.get(sortBy);
        Order order;
        if (sortOrder.equalsIgnoreCase("descending")) {
            order = cb.desc(sortByField);
        } else {
            order = cb.asc(sortByField);
        }
        resourceQuery.orderBy(order);

        return new SCIMSearchResult<T>(results, totalResult, count, newStartIndex, getCoreSchema());
    }
        List<T> results = q.getResultList();

    private <T> List<T> getResults(DetachedCriteria idsOnlyCriteria, Class<T> clazz, int count, int startIndex, String sortBy,
            String sortOrder) {
	    Criteria criteria = ((Session) em.getDelegate()).createCriteria(clazz);

        long totalResult = getTotalResults(clazz, filter);

        ///////////////////////////////////////////////////////////////////////////////////

        int newStartIndex = startIndex < 1 ? 1 : startIndex;

        return new SCIMSearchResult<T>(results, totalResult, count, newStartIndex, Constants.CORE_SCHEMA);
    }

    private <T extends InternalIdSkeleton> long getTotalResults(Class<T> clazz, String filter) {

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

        // TODO: add predicates
        /*if (filter != null && !filter.isEmpty()) {
            idsOnlyCriteria.add(filterParser.parse(filter, clazz).buildCriterion());
        }*/

        resourceQuery.select(cb.count(resourceRoot));

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

        return total;
    }

    protected abstract void createAliasesForCriteria(DetachedCriteria criteria);
    protected abstract String getCoreSchema();
}
{'fraction_non_alphanumeric': 0.09590714722052535, 'fraction_numerical': 0.0017453529976437735, 'mean_word_length': 3.70250307755437, 'pattern_counts': {'":': 0, '<': 38, '<?xml version=': 0, '>': 36, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7659174', 'n_tokens_mistral': 3058, 'n_tokens_neox': 2954, 'n_words': 893}