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

Java tutorial

Introduction

Here is the source code for org.seedstack.i18n.rest.internal.TranslationJpaFinder.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.translation.TranslationAssembler;
import org.seedstack.i18n.rest.internal.translation.TranslationFinder;
import org.seedstack.i18n.rest.internal.translation.TranslationRepresentation;
import org.apache.commons.lang.StringUtils;
import org.seedstack.business.finder.Range;
import org.seedstack.business.finder.Result;
import org.seedstack.jpa.BaseJpaRangeFinder;
import org.seedstack.seed.core.utils.SeedCheckUtils;

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

/**
 * This class provides methods to find translations.
 *
 * @author pierre.thirouin@ext.mpsa.com
 *         Date: 15/05/2014
 */
public class TranslationJpaFinder extends BaseJpaRangeFinder<TranslationRepresentation>
        implements TranslationFinder {

    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 LOCALE = "locale";
    private static final String ENTITY_ID = "entityId";
    private static final String TRANSLATIONS = "translations";
    private static final String OUTDATED = "outdated";
    private static final String APPROXIMATE = "approximate";
    private static final String VALUE = "value";

    @Inject
    private KeyRepository keyRepository;

    @Inject
    private LocaleService localeService;

    @Inject
    private TranslationAssembler translationAssembler;

    @Inject
    private EntityManager entityManager;

    @Override
    public List<TranslationRepresentation> findTranslations(String localeId) {
        List<Key> keys = keyRepository.loadAll();
        List<TranslationRepresentation> translationRepresentations = new ArrayList<TranslationRepresentation>(
                keys.size());
        String defaultLocale = localeService.getDefaultLocale();
        for (Key key : keys) {
            translationRepresentations
                    .add(translationAssembler.assembleDtoFromAggregate(key.subKey(defaultLocale, localeId)));
        }

        return translationRepresentations;
    }

    @Override
    public TranslationRepresentation findTranslation(String localeId, String keyId) {
        Key key = keyRepository.load(keyId);
        String defaultLocale = localeService.getDefaultLocale();
        SeedCheckUtils.checkIfNotNull(defaultLocale);
        if (key != null) {
            return translationAssembler.assembleDtoFromAggregate(key.subKey(defaultLocale, localeId));
        }
        return null;
    }

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

    @Override
    protected List<TranslationRepresentation> 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();
        }
        List<TranslationRepresentation> translationRepresentations = new ArrayList<TranslationRepresentation>(
                keys.size());
        String defaultLocale = localeService.getDefaultLocale();
        for (Key key : keys) {
            translationRepresentations.add(translationAssembler
                    .assembleDtoFromAggregate(key.subKey(defaultLocale, (String) criteria.get(LOCALE))));
        }

        return translationRepresentations;
    }

    @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();
    }

    /**
     * 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);
            String locale = (String) criteria.get(LOCALE);

            // is the key LIKE searchName
            if (StringUtils.isNotBlank(searchName)) {
                predicates.add(cb.like(k.<String>get(ENTITY_ID), "%" + searchName + "%"));
            }

            // if a default translation is available
            if (isApprox != null || isOutdated != 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), locale));

                // is the key outdated
                if (isOutdated != null) {
                    predicates.add(cb.equal(tln.<Boolean>get(OUTDATED), isOutdated));
                }

                // is the translation approximate
                if (isApprox != null) {
                    predicates.add(cb.equal(tln.<Boolean>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), locale),
                        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()]);
    }
}