fi.vm.sade.osoitepalvelu.kooste.service.search.DefaultSearchService.java Source code

Java tutorial

Introduction

Here is the source code for fi.vm.sade.osoitepalvelu.kooste.service.search.DefaultSearchService.java

Source

/*
 * Copyright (c) 2013 The Finnish National Board of Education - Opetushallitus
 *
 * This program is free software: Licensed under the EUPL, Version 1.1 or - as
 * soon as they will be approved by the European Commission - subsequent versions
 * of the EUPL (the "Licence");
 *
 * You may not use this work except in compliance with the Licence.
 * You may obtain a copy of the Licence at: http://www.osor.eu/eupl/
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * European Union Public Licence for more details.
 */

package fi.vm.sade.osoitepalvelu.kooste.service.search;

import com.google.common.base.Function;
import com.google.common.collect.Collections2;
import com.googlecode.ehcache.annotations.Cacheable;
import com.googlecode.ehcache.annotations.PartialCacheKey;
import fi.vm.sade.auditlog.Audit;
import fi.vm.sade.auditlog.osoitepalvelu.OsoitepalveluOperation;
import fi.vm.sade.osoitepalvelu.kooste.common.route.CamelRequestContext;
import fi.vm.sade.osoitepalvelu.kooste.domain.SearchTargetGroup;
import fi.vm.sade.osoitepalvelu.kooste.service.AbstractService;
import fi.vm.sade.osoitepalvelu.kooste.service.henkilo.HenkiloService;
import fi.vm.sade.osoitepalvelu.kooste.service.koodisto.KoodistoService;
import fi.vm.sade.osoitepalvelu.kooste.service.koodisto.dto.UiKoodiItemDto;
import fi.vm.sade.osoitepalvelu.kooste.service.organisaatio.FilterableOrganisaatio;
import fi.vm.sade.osoitepalvelu.kooste.service.organisaatio.OrganisaatioService;
import fi.vm.sade.osoitepalvelu.kooste.route.dto.*;
import fi.vm.sade.osoitepalvelu.kooste.service.saves.dto.SearchTargetGroupDto;
import fi.vm.sade.osoitepalvelu.kooste.service.saves.dto.SearchTermDto;
import fi.vm.sade.osoitepalvelu.kooste.service.search.dto.HenkiloHakuResultDto;
import fi.vm.sade.osoitepalvelu.kooste.service.search.dto.OrganisaatioResultDto;
import fi.vm.sade.osoitepalvelu.kooste.service.search.dto.SearchResultsDto;
import fi.vm.sade.osoitepalvelu.kooste.service.search.dto.SearchTermsDto;
import fi.vm.sade.osoitepalvelu.kooste.service.search.dto.converter.SearchResultDtoConverter;
import fi.vm.sade.osoitepalvelu.kooste.service.tarjonta.TarjontaService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import static fi.vm.sade.auditlog.osoitepalvelu.LogMessage.builder;
import fi.vm.sade.auditlog.osoitepalvelu.LogMessage;

import java.util.*;
import org.apache.commons.lang.builder.ToStringBuilder;

@Service
@Qualifier("actual")
public class DefaultSearchService extends AbstractService implements SearchService {
    private static final long serialVersionUID = -3383060564957835908L;

    @Autowired
    private OrganisaatioService organisaatioService;

    @Autowired
    private HenkiloService henkiloService;

    @Autowired
    private KoodistoService koodistoService;

    @Autowired
    private TarjontaService tarjontaService;

    @Autowired
    private SearchResultDtoConverter dtoConverter;

    @Autowired
    private Audit audit;

    @Override
    @Cacheable(cacheName = "osoitepalveluSearchResultsCache")
    public SearchResultsDto find(@PartialCacheKey SearchTermsDto terms, CamelRequestContext context)
            throws TooFewSearchConditionsForOrganisaatiosException, TooFewSearchConditionsForHenkilosException,
            TooFewSearchConditionsForKoulutusException, OrganisaatioTyyppiMissingForOrganisaatiosException {

        logger.info("Starting search by {}", getLoggedInUserOidOrNull());

        SearchResultsDto results = new SearchResultsDto();

        boolean searchHenkilos = terms.containsAnyTargetGroup(SearchTargetGroup.GroupType.getHenkiloHakuTypes()),
                returnOrgansiaatios = terms.containsAnyTargetGroup(
                        SearchTargetGroup.GroupType.getOrganisaatioPalveluTypes(),
                        SearchTargetGroup.TargetType.ORGANISAATIO),
                searchKoulutuksenTarjoajat = terms
                        .containsAnyTargetGroup(SearchTargetGroup.GroupType.getKoulutusHakuTypes());

        OrganisaatioYhteystietoCriteriaDto organisaatioCriteria = produceOrganisaatioCriteria(terms);
        boolean anyOrganisaatioRelatedConditionsUsed = organisaatioCriteria.getNumberOfUsedConditions() > 0,
                searchOrganisaatios = returnOrgansiaatios
                        || (searchHenkilos && anyOrganisaatioRelatedConditionsUsed);

        List<OrganisaatioYhteystietoHakuResultDto> organisaatioYhteystietoResults = new ArrayList<OrganisaatioYhteystietoHakuResultDto>();

        logger.debug("searchKoulutuksenTarjoajat == " + searchKoulutuksenTarjoajat);

        if (searchKoulutuksenTarjoajat) {
            OrganisaatioYhteystietoCriteriaDto ktOrgCriteria = produceOrganisaatioCriteria(terms);

            // Otetaan organisaatiotyypit "KOULUTUKSEN_TARJOAJAT" optioista
            ktOrgCriteria.setOrganisaatioTyyppis(
                    parseOrganisaatioTyyppis(terms, SearchTargetGroup.GroupType.KOULUTUKSEN_TARJOAJAT));

            logger.debug("Koulutuksen tarjoajat, Organisaatiotyypit: " + ktOrgCriteria.getOrganisaatioTyyppis());

            // Luodaan koulutuskriteerit
            KoulutusCriteriaDto koulutusCriteria = produceKoulutusCriteria(terms);

            List<String> oidList = tarjontaService.findOrganisaatios(koulutusCriteria, context);

            if (oidList.isEmpty()) {
                logger.info(
                        "Oid list of KOULUTUKSEN_TARJOAJA empty --> no organisations found with koulutus criteria!");
            } else {
                // Haetaan koulutusten tarjoajaorganisaatioiden yhteystiedot
                ktOrgCriteria.setOidList(oidList);

                List<OrganisaatioYhteystietoHakuResultDto> ktOrgYhteystietoResults;

                ktOrgYhteystietoResults = organisaatioService.findOrganisaatioYhteystietos(ktOrgCriteria,
                        terms.getLocale(), context);

                // Listn koulutusten tarjoajaorganisaatioiden yhteystiedot muiden organisaatioyhteystietojen joukkoon
                organisaatioYhteystietoResults.addAll(ktOrgYhteystietoResults);

                logger.debug(
                        "Organisaatioiden haku kriteerit: " + ToStringBuilder.reflectionToString(ktOrgCriteria));
                logger.debug("Koulutuksen tarjoajat, organisaatioiden yhteystiedot size: "
                        + ktOrgYhteystietoResults.size());

                // Convert to result DTOs (with e.g. postinumeros):
                List<OrganisaatioResultDto> convertedResults = dtoConverter.convert(ktOrgYhteystietoResults,
                        new ArrayList<OrganisaatioResultDto>(), OrganisaatioResultDto.class, terms.getLocale());
                results.addOrganisaatios(convertedResults);
            }
        }

        logger.debug("searchOrganisaatios == " + searchOrganisaatios);

        if (searchOrganisaatios) {
            SearchTargetGroup.TargetType[] targetTypes;
            if (returnOrgansiaatios) {
                // Only the ones with target group and ORGANISAATIO-type selected:
                // (and apply other possible constraints):
                targetTypes = new SearchTargetGroup.TargetType[] { SearchTargetGroup.TargetType.ORGANISAATIO };
            } else {
                // No ORGANISAATIO types selected but possibly a number of organisaatio kind target groups present,
                // use them to filter organisaatios by which to return henkilos as well
                // (as other possible filterin constaints):
                targetTypes = new SearchTargetGroup.TargetType[0];
            }
            organisaatioCriteria.setOrganisaatioTyyppis(parseOrganisaatioTyyppis(terms, targetTypes));

            // When searching henkils we don't want to limit the search.
            if (!searchHenkilos) {
                ensureAtLeastOneConditionUsed(organisaatioCriteria);
            }

            List<OrganisaatioYhteystietoHakuResultDto> orgYhteystietoResults;

            orgYhteystietoResults = organisaatioService.findOrganisaatioYhteystietos(organisaatioCriteria,
                    terms.getLocale(), context);

            organisaatioYhteystietoResults.addAll(orgYhteystietoResults);

            if (returnOrgansiaatios) {
                // Convert to result DTOs (with e.g. postinumeros):
                List<OrganisaatioResultDto> convertedResults = dtoConverter.convert(orgYhteystietoResults,
                        new ArrayList<OrganisaatioResultDto>(), OrganisaatioResultDto.class, terms.getLocale());
                results.addOrganisaatios(convertedResults);
            }
        }

        logger.debug("searchHenkilos == " + searchHenkilos);

        if (searchHenkilos) {
            List<String> organisaatioOids = oids(organisaatioYhteystietoResults);
            List<HenkiloDetailsDto> henkiloDetails = findHenkilos(terms, context, organisaatioOids);
            // Searching individuals may contain sensitive content so it is logged.
            logRead(henkiloDetails);

            List<HenkiloHakuResultDto> henkiloResults = dtoConverter.convert(henkiloDetails,
                    new ArrayList<HenkiloHakuResultDto>(), HenkiloHakuResultDto.class, terms.getLocale());
            results.setHenkilos(henkiloResults);
        }

        logger.debug("Search end by {}", getLoggedInUserOidOrNull());

        return results;
    }

    protected OrganisaatioYhteystietoCriteriaDto produceOrganisaatioCriteria(SearchTermsDto terms) {
        OrganisaatioYhteystietoCriteriaDto organisaatioCriteria = new OrganisaatioYhteystietoCriteriaDto();
        organisaatioCriteria.setKuntaList(resolveKuntaKoodis(terms));
        organisaatioCriteria.setKieliList(terms.findTerms(SearchTermDto.TERM_ORGANISAATION_KIELIS));
        organisaatioCriteria.setOppilaitostyyppiList(terms.findTerms(SearchTermDto.TERM_OPPILAITOSTYYPPIS));
        organisaatioCriteria.setVuosiluokkaList(terms.findTerms(SearchTermDto.TERM_VUOSILUOKKAS));
        organisaatioCriteria.setYtunnusList(terms.findTerms(SearchTermDto.TERM_KOULTUKSENJARJESTAJAS));
        return organisaatioCriteria;
    }

    protected void ensureAtLeastOneConditionUsed(OrganisaatioYhteystietoCriteriaDto organisaatioCriteria)
            throws TooFewSearchConditionsForOrganisaatiosException,
            OrganisaatioTyyppiMissingForOrganisaatiosException {
        organisaatioCriteria.setUseOrganisaatioTyyppi(true);

        logger.info("Organisaatio criteria tyypit:" + organisaatioCriteria.getOrganisaatioTyyppis());

        if (organisaatioCriteria.getOrganisaatioTyyppis().isEmpty()) {
            // If organisaatiotyyppi is missing, require it:
            throw new OrganisaatioTyyppiMissingForOrganisaatiosException();
        }
    }

    protected KoulutusCriteriaDto produceKoulutusCriteria(SearchTermsDto terms) {
        KoulutusCriteriaDto criteria = new KoulutusCriteriaDto();

        // Koulutuslaji --> There can be only one koulutuslaji
        if (terms.findTerms(SearchTermDto.TERM_KOULUTUSLAJIS).size() == 1
                && terms.findTerms(SearchTermDto.TERM_KOULUTUSLAJIS).get(0).isEmpty() == false) {
            criteria.setKoulutuslaji(terms.findTerms(SearchTermDto.TERM_KOULUTUSLAJIS).get(0));
        }
        if (terms.findTerms(SearchTermDto.TERM_KOULUTUSLAJIS).size() > 1) {
            logger.error("Too many terms for koulutuslaji, only one can be defined!");
        }

        // Opetuskieli
        criteria.setOpetuskielet(terms.findTerms(SearchTermDto.TERM_OPETUSKIELIS));

        // Koulutustyyppi
        criteria.setKoulutustyyppis(terms.findTerms(SearchTermDto.TERM_KOULUTUSTYYPPIS));

        // Koulutusala
        criteria.setKoulutusalakoodis(terms.findTerms(SearchTermDto.TERM_KOULUTUSALAS));

        // Opintoala
        criteria.setOpintoalakoodis(terms.findTerms(SearchTermDto.TERM_OPINTOALAS));

        // Koulutus
        criteria.setKoulutuskoodis(terms.findTerms(SearchTermDto.TERM_KOULUTUS));

        return criteria;
    }

    protected List<String> parseOrganisaatioTyyppis(SearchTermsDto terms, SearchTargetGroup.GroupType groupType) {
        List<String> organisaatioTyyppis = new ArrayList<String>();
        SearchTargetGroupDto groupDto = terms.getTargetGroup(groupType);

        if (groupDto == null) {
            return organisaatioTyyppis;
        }

        for (SearchTargetGroup.TargetType option : groupDto.getOptions()) {
            if (Arrays.asList(SearchTargetGroup.TargetType.getOrganisaatioPalveluTypes()).contains(option)) {
                organisaatioTyyppis.addAll(Arrays.asList(option.getOrganisaatioPalveluTyyppiArvo()));
            }
        }
        return organisaatioTyyppis;
    }

    protected List<String> parseOrganisaatioTyyppis(SearchTermsDto terms,
            SearchTargetGroup.TargetType... targetTypes) {
        List<String> organisaatioTyyppis = new ArrayList<String>();
        for (SearchTargetGroupDto groupDto : terms.getTargetGroups()) {
            if (groupDto.containsAnyOption(targetTypes)) {
                SearchTargetGroup.GroupType groupType = groupDto.getType();
                if (groupType.getOrganisaatioPalveluTyyppiArvo() != null) {
                    organisaatioTyyppis.addAll(Arrays.asList(groupType.getOrganisaatioPalveluTyyppiArvo()));
                }
            }
        }
        return organisaatioTyyppis;
    }

    protected List<HenkiloDetailsDto> findHenkilos(SearchTermsDto terms, final CamelRequestContext context,
            List<String> organisaatioOids) throws TooFewSearchConditionsForHenkilosException {
        HenkiloCriteriaDto criteria = new HenkiloCriteriaDto();
        criteria.setOrganisaatioOids(organisaatioOids);
        criteria.setKayttoOikeusRayhmas(terms.findTerms(SearchTermDto.TERM_KAYTTOOIKEUSRYHMAS));

        if (criteria.getNumberOfUsedConditions() < 1) {
            throw new TooFewSearchConditionsForHenkilosException();
        }

        return henkiloService.findHenkilos(criteria, context);
    }

    // Combine fetched henkiloOids into single string and log what was fetched.
    protected void logRead(List<HenkiloDetailsDto> henkiloDetailsList) {

        String henkiloOids = "";
        for (HenkiloDetailsDto henkiloDetails : henkiloDetailsList) {
            henkiloOids += henkiloDetails.getOidHenkilo() + ";";
        }
        LogMessage logMessage = builder().id(getLoggedInUserOidOrNull()).henkiloOidList(henkiloOids)
                .setOperaatio(OsoitepalveluOperation.HENKILO_HAKU).build();
        audit.log(logMessage);
    }

    protected List<String> resolveKuntaKoodis(SearchTermsDto terms) {
        List<String> kuntas = new ArrayList<String>();
        kuntas.addAll(terms.findTerms(SearchTermDto.TERM_KUNTAS));
        for (String maakuntaKoodi : terms.findTerms(SearchTermDto.TERM_MAAKUNTAS)) {
            kuntas.addAll(kuntasForMaakunta(terms.getLocale(), maakuntaKoodi));
        }
        return kuntas;
    }

    protected Collection<? extends String> kuntasForMaakunta(Locale locale, String maakuntaUri) {
        return Collections2.transform(koodistoService.findKuntasByMaakuntaUri(locale, maakuntaUri),
                new Function<UiKoodiItemDto, String>() {
                    public String apply(UiKoodiItemDto koodi) {
                        return koodi.getKoodiUri();
                    }
                });
    }

    protected List<String> oids(List<OrganisaatioYhteystietoHakuResultDto> organisaatioYhteystietoResults) {
        List<String> oidList = new ArrayList<String>(
                Collections2.transform(organisaatioYhteystietoResults, FilterableOrganisaatio.GET_OID));
        // Remove opetushallitus since it's included as root organisation of koulutustoimijas.
        oidList.remove("1.2.246.562.10.00000000001");
        return oidList;
    }

    public void setTarjontaService(TarjontaService tarjontaService) {
        this.tarjontaService = tarjontaService;
    }

    public void setOrganisaatioService(OrganisaatioService organisaatioService) {
        this.organisaatioService = organisaatioService;
    }

    public void setHenkiloService(HenkiloService henkiloService) {
        this.henkiloService = henkiloService;
    }

    public void setKoodistoService(KoodistoService koodistoService) {
        this.koodistoService = koodistoService;
    }

}