org.seedstack.i18n.rest.internal.KeyJpaFinder.java Source code

Java tutorial

Introduction

Here is the source code for org.seedstack.i18n.rest.internal.KeyJpaFinder.java

Source

/**
 * Copyright (c) 2013-2015, The SeedStack authors <http://seedstack.org>
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */
package org.seedstack.i18n.rest.internal;

import org.seedstack.i18n.LocaleService;
import org.seedstack.i18n.internal.domain.model.key.Key;
import org.seedstack.i18n.internal.domain.model.key.KeyRepository;
import org.seedstack.i18n.internal.domain.model.key.Translation;
import org.seedstack.i18n.rest.internal.key.KeyAssembler;
import org.seedstack.i18n.rest.internal.key.KeyFinder;
import org.seedstack.i18n.rest.internal.key.KeyRepresentation;
import org.apache.commons.lang.StringUtils;
import org.seedstack.business.finder.Range;
import org.seedstack.business.finder.Result;
import org.seedstack.jpa.BaseJpaRangeFinder;

import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.criteria.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * KeyFinder implementation for JPA.
 *
 * @author pierre.thirouin@ext.mpsa.com
 *         Date: 13/05/2014
 */
public class KeyJpaFinder extends BaseJpaRangeFinder<KeyRepresentation> implements KeyFinder {

    private static final String IS_APPROX = "isApprox";
    private static final String IS_MISSING = "isMissing";
    private static final String IS_OUTDATED = "isOutdated";
    private static final String SEARCH_NAME = "searchName";
    private static final String ENTITY_ID = "entityId";
    private static final String OUTDATED = "outdated";
    private static final String TRANSLATIONS = "translations";
    private static final String LOCALE = "locale";
    private static final String APPROXIMATE = "approximate";
    private static final String VALUE = "value";

    @Inject
    private EntityManager entityManager;

    @Inject
    private LocaleService localeService;

    @Inject
    private KeyAssembler keyAssembler;

    @Inject
    private KeyRepository keyRepository;

    @Override
    protected List<KeyRepresentation> computeResultList(Range range, Map<String, Object> criteria) {
        CriteriaBuilder cb = entityManager.getCriteriaBuilder();
        CriteriaQuery<Key> q = cb.createQuery(Key.class);
        Root<Key> k = q.from(Key.class);
        Predicate[] predicates = getPredicates(criteria, q, cb, k);
        q.select(k);
        if (predicates.length > 0) {
            q.where(cb.and(predicates));
        }
        List<Key> keys;
        // Get all the keys with their default translation
        if (range != null) {
            keys = entityManager.createQuery(q).setFirstResult((int) range.getOffset())
                    .setMaxResults((int) range.getSize()).getResultList();
        } else {
            keys = entityManager.createQuery(q).getResultList();
        }

        return assembleRepresentationsFromEntities(keys);
    }

    private List<KeyRepresentation> assembleRepresentationsFromEntities(List<Key> keys) {
        List<KeyRepresentation> keyRepresentations = new ArrayList<KeyRepresentation>(keys.size());
        String defaultLocale = localeService.getDefaultLocale();
        for (Key key : keys) {
            keyRepresentations.add(keyAssembler.assembleDtoFromAggregate(key.subKey(defaultLocale)));
        }
        return keyRepresentations;
    }

    /**
     * Extracts predicates from criteria.
     *
     * @param criteria criteria
     * @param cb       criteria builder
     * @param k        root key
     * @return list of predicate
     */
    private Predicate[] getPredicates(Map<String, Object> criteria, CriteriaQuery q, CriteriaBuilder cb,
            Root<Key> k) {
        List<Predicate> predicates = new ArrayList<Predicate>();
        if (criteria != null) {
            // extract criteria from the map
            Boolean isApprox = (Boolean) criteria.get(IS_APPROX);
            Boolean isMissing = (Boolean) criteria.get(IS_MISSING);
            Boolean isOutdated = (Boolean) criteria.get(IS_OUTDATED);
            String searchName = (String) criteria.get(SEARCH_NAME);

            // is the key LIKE searchName
            if (StringUtils.isNotBlank(searchName)) {
                predicates.add(cb.like(k.<String>get(ENTITY_ID), "%" + searchName + "%"));
            }
            // is the key outdated
            if (isOutdated != null) {
                predicates.add(cb.equal(k.<Boolean>get(OUTDATED), isOutdated));
            }

            // if a default translation is available
            String defaultLocale = localeService.getDefaultLocale();
            if (defaultLocale != null && isApprox != null) {
                // join translation table
                Join<Key, Translation> tln = k.join(TRANSLATIONS, JoinType.LEFT);
                // WHERE locale = default locale
                predicates.add(cb.equal(tln.get(ENTITY_ID).get(LOCALE), defaultLocale));

                // is the translation approximate
                predicates.add(cb.equal(tln.get(APPROXIMATE), isApprox));
            }

            // is the translation missing
            if (isMissing != null) {
                // SubQuery to find all the key which get a translation for the default locale
                //noinspection unchecked
                Subquery<String> subquery = q.subquery(String.class);
                Root<Key> fromKey = subquery.from(Key.class);
                subquery.select(fromKey.<String>get(ENTITY_ID));
                Join join = fromKey.join(TRANSLATIONS, JoinType.LEFT);
                subquery.where(cb.and(cb.equal(join.get(ENTITY_ID).get(LOCALE), defaultLocale),
                        cb.notEqual(join.get(VALUE), "")));
                // Find all keys not in the above subquery, ie. all the keys missing
                predicates.add(cb.not(cb.in(k.get(ENTITY_ID)).value(subquery)));
            }
        }
        return predicates.toArray(new Predicate[predicates.size()]);
    }

    @Override
    protected long computeFullRequestSize(Map<String, Object> criteria) {
        CriteriaBuilder cb = entityManager.getCriteriaBuilder();
        CriteriaQuery<Long> q = cb.createQuery(Long.class);
        Root<Key> k = q.from(Key.class);
        q.select(cb.count(k));
        if (criteria != null) {
            q.where(cb.and(getPredicates(criteria, q, cb, k)));
        }
        return entityManager.createQuery(q).getSingleResult();
    }

    @Override
    public List<KeyRepresentation> findAllKeys() {
        List<Key> keys = keyRepository.loadAll();
        return assembleRepresentationsFromEntities(keys);
    }

    @Override
    public KeyRepresentation findKey(String name) {
        Key key = keyRepository.load(name);
        if (key != null) {
            return keyAssembler.assembleDtoFromAggregate(key.subKey(localeService.getDefaultLocale()));
        } else {
            return null;
        }
    }

    @Override
    public Result<KeyRepresentation> findAllKeys(Range range, Map<String, Object> criteria) {
        return find(range, criteria);
    }

    @Override
    public List<KeyRepresentation> findAllKeys(Map<String, Object> criteria) {
        return computeResultList(null, criteria);
    }
}