net.sf.gazpachoquest.services.core.impl.ResearchServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for net.sf.gazpachoquest.services.core.impl.ResearchServiceImpl.java

Source

/*******************************************************************************
 * Copyright (c) 2014 antoniomariasanchez at gmail.com. All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Public License v3.0 which accompanies this distribution, and is
 * available at http://www.gnu.org/licenses/gpl.html
 * 
 * Contributors: antoniomaria - initial API and implementation
 ******************************************************************************/
package net.sf.gazpachoquest.services.core.impl;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import net.sf.gazpachoquest.domain.core.AnonymousInvitation;
import net.sf.gazpachoquest.domain.core.MailMessage;
import net.sf.gazpachoquest.domain.core.MailMessageTemplate;
import net.sf.gazpachoquest.domain.core.PersonalInvitation;
import net.sf.gazpachoquest.domain.core.Questionnaire;
import net.sf.gazpachoquest.domain.core.QuestionnaireAnswers;
import net.sf.gazpachoquest.domain.core.QuestionnaireDefinition;
import net.sf.gazpachoquest.domain.core.Research;
import net.sf.gazpachoquest.domain.core.embeddables.MailMessageTemplateLanguageSettings;
import net.sf.gazpachoquest.domain.i18.MailMessageTemplateTranslation;
import net.sf.gazpachoquest.domain.permission.QuestionnairePermission;
import net.sf.gazpachoquest.domain.permission.ResearchPermission;
import net.sf.gazpachoquest.domain.user.Group;
import net.sf.gazpachoquest.domain.user.User;
import net.sf.gazpachoquest.qbe.SearchParameters;
import net.sf.gazpachoquest.repository.InvitationRepository;
import net.sf.gazpachoquest.repository.MailMessageRepository;
import net.sf.gazpachoquest.repository.QuestionnaireDefinitionRepository;
import net.sf.gazpachoquest.repository.QuestionnaireRepository;
import net.sf.gazpachoquest.repository.ResearchRepository;
import net.sf.gazpachoquest.repository.dynamic.QuestionnaireAnswersRepository;
import net.sf.gazpachoquest.repository.permission.QuestionnairePermissionRepository;
import net.sf.gazpachoquest.repository.permission.ResearchPermissionRepository;
import net.sf.gazpachoquest.repository.user.GroupRepository;
import net.sf.gazpachoquest.repository.user.UserRepository;
import net.sf.gazpachoquest.services.ResearchService;
import net.sf.gazpachoquest.types.EntityStatus;
import net.sf.gazpachoquest.types.InvitationStatus;
import net.sf.gazpachoquest.types.Language;
import net.sf.gazpachoquest.types.MailMessageTemplateType;
import net.sf.gazpachoquest.types.Perm;
import net.sf.gazpachoquest.types.ResearchAccessType;
import net.sf.gazpachoquest.util.RandomTokenGenerator;

import org.apache.commons.lang3.StringUtils;
import org.apache.velocity.app.VelocityEngine;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.velocity.VelocityEngineFactoryBean;
import org.springframework.ui.velocity.VelocityEngineUtils;
import org.springframework.util.Assert;

@Service
public class ResearchServiceImpl extends AbstractPersistenceService<Research> implements ResearchService {

    @Autowired
    private InvitationRepository invitationRepository;

    @Autowired
    private MailMessageRepository mailMessageRepository;

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private GroupRepository groupRepository;

    @Autowired
    private QuestionnaireDefinitionRepository questionnaireDefinitionRepository;

    @Autowired
    private QuestionnaireRepository questionnaireRepository;

    @Autowired
    private RandomTokenGenerator tokenGenerator;

    @Autowired
    private VelocityEngineFactoryBean velocityFactory;

    @Autowired
    private ResearchPermissionRepository researchPermissionRepository;

    @Autowired
    private QuestionnaireAnswersRepository questionnaireAnswersRepository;

    @Autowired
    private QuestionnairePermissionRepository questionnairePermissionRepository;

    @Autowired
    public ResearchServiceImpl(final ResearchRepository repository) {
        super(repository);
    }

    public Research saveOld(Research research) {
        Research existing = null;
        if (research.isNew()) {
            research.setStatus(EntityStatus.DRAFT);
            existing = repository.save(research);
        } else {
            existing = repository.findOne(research.getId());
            existing.setStartDate(research.getStartDate());
            existing.setExpirationDate(research.getExpirationDate());
        }
        return existing;
    }

    @Override
    @Transactional(readOnly = false)
    public Research save(Research research) {
        Research existing = null;
        if (research.isNew()) {
            research.setStatus(EntityStatus.DRAFT);
            existing = repository.save(research);

            String token = tokenGenerator.generate();
            AnonymousInvitation anonymousInvitation = AnonymousInvitation.with().research(research).token(token)
                    .status(InvitationStatus.ACTIVE).build();
            invitationRepository.save(anonymousInvitation);

            ResearchPermission permission = ResearchPermission.with().addPerm(Perm.READ).addPerm(Perm.UPDATE)
                    .addPerm(Perm.DELETE).user(getAuthenticatedUser()).target(research).build();
            researchPermissionRepository.save(permission);

        } else {
            existing = repository.findOne(research.getId());
            existing.setStartDate(research.getStartDate());
            existing.setExpirationDate(research.getExpirationDate());
        }
        return existing;
    }

    @Override
    @Transactional(readOnly = false)
    public void changeStatus(Integer researchId, EntityStatus newStatus) {
        Research research = repository.findOne(researchId);

        if (research.getStatus().equals(newStatus)) {
            return;
        }
        research.setStatus(newStatus);

        for (Questionnaire questionnaire : research.getQuestionnaires()) {
            questionnaire.setStatus(newStatus);
        }
    }

    @Override
    @Transactional(readOnly = false)
    public void addRespondent(Integer researchId, User respondent) {
        Assert.state(!respondent.isNew(), "Persist respondent before using inside a research.");

        Research research = repository.findOne(researchId);
        Assert.state(research.getType().equals(ResearchAccessType.BY_INVITATION),
                "Tracked participants are not supported in anonymous researches");

        QuestionnaireDefinition questionnaireDefinition = research.getQuestionnaireDefinition();

        Questionnaire questionnaire = Questionnaire.with().status(research.getStatus()).research(research)
                .questionnaireDefinition(questionnaireDefinition).respondent(respondent).build();
        questionnaire = questionnaireRepository.save(questionnaire);

        // Create answers holder
        QuestionnaireAnswers questionnaireAnswers = new QuestionnaireAnswers();
        questionnaireAnswers = questionnaireAnswersRepository
                .save(questionnaire.getQuestionnaireDefinition().getId(), questionnaireAnswers);
        questionnaire.setAnswersId(questionnaireAnswers.getId());

        // Grant permissions over questionnaire to respondent
        QuestionnairePermission permission = QuestionnairePermission.with().addPerm(Perm.READ).addPerm(Perm.UPDATE)
                .user(respondent).target(questionnaire).build();
        questionnairePermissionRepository.save(permission);

        String token = tokenGenerator.generate();
        PersonalInvitation personalInvitation = PersonalInvitation.with().research(research).token(token)
                .status(InvitationStatus.ACTIVE).respondent(respondent).build();
        invitationRepository.save(personalInvitation);

        // Add the respondent to respondents groups
        Group example = Group.with().name("Respondents").build();
        Group respondentsGroup = groupRepository.findOneByExample(example, new SearchParameters())
                .orElseThrow(() -> new EmptyResultDataAccessException(
                        String.format("No %s entity with name %s found!", Group.class, "Respondents"), 1));
        if (groupRepository.isUserInGroup(respondent.getId(), "Respondents") == 0) {
            respondentsGroup.assignUser(respondent);
        }
    }

    @Override
    @Transactional(readOnly = false)
    public Research save(Research research, Set<QuestionnaireDefinition> questionnaireDefinitions,
            Set<User> respondents) {
        research = saveOld(research);
        if (ResearchAccessType.BY_INVITATION.equals(research.getType())) {
            for (QuestionnaireDefinition questionnaireDefinition : questionnaireDefinitions) {

                questionnaireDefinition = questionnaireDefinitionRepository
                        .findOne(questionnaireDefinition.getId());

                Map<MailMessageTemplateType, MailMessageTemplate> templates = questionnaireDefinition
                        .getMailTemplates();
                MailMessageTemplate invitationTemplate = templates.get(MailMessageTemplateType.INVITATION);

                Group example = Group.with().name("Respondents").build();
                Group respondentsGroup = groupRepository.findOneByExample(example, new SearchParameters())
                        .orElseThrow(() -> new EmptyResultDataAccessException(
                                String.format("No %s entity with name %s found!", Group.class, "Respondents"), 1));

                for (User respondent : respondents) {
                    Assert.state(!respondent.isNew(), "Persist all respondents before starting a research.");
                    Questionnaire questionnaire = Questionnaire.with().status(EntityStatus.CONFIRMED)
                            .research(research).questionnaireDefinition(questionnaireDefinition)
                            .respondent(respondent).build();
                    questionnaire = questionnaireRepository.save(questionnaire);
                    // Create answers holder
                    QuestionnaireAnswers questionnaireAnswers = new QuestionnaireAnswers();
                    questionnaireAnswers = questionnaireAnswersRepository
                            .save(questionnaire.getQuestionnaireDefinition().getId(), questionnaireAnswers);
                    questionnaire.setAnswersId(questionnaireAnswers.getId());

                    String token = tokenGenerator.generate();

                    respondent = userRepository.findOne(respondent.getId());
                    // Grant permissions over questionnaire to respondent
                    QuestionnairePermission permission = QuestionnairePermission.with().addPerm(Perm.READ)
                            .addPerm(Perm.UPDATE).user(respondent).target(questionnaire).build();
                    questionnairePermissionRepository.save(permission);

                    PersonalInvitation personalInvitation = PersonalInvitation.with().research(research)
                            .token(token).status(InvitationStatus.ACTIVE).respondent(respondent).build();
                    invitationRepository.save(personalInvitation);

                    MailMessage mailMessage = composeMailMessage(invitationTemplate, respondent, token);
                    mailMessageRepository.save(mailMessage);

                    if (groupRepository.isUserInGroup(respondent.getId(), "Respondents") == 0) {
                        respondentsGroup.assignUser(respondent);
                    }
                }
            }
        } else {
            Assert.notEmpty(questionnaireDefinitions, "questionnairDefinitions required");
            Assert.state(questionnaireDefinitions.size() == 1,
                    "Only one questionnairDefinitions supported for Open Access researches");
            String token = tokenGenerator.generate();

            AnonymousInvitation anonymousInvitation = AnonymousInvitation.with().research(research).token(token)
                    .status(InvitationStatus.ACTIVE).build();
            invitationRepository.save(anonymousInvitation);
        }
        ResearchPermission permission = ResearchPermission.with().addPerm(Perm.READ).addPerm(Perm.UPDATE)
                .addPerm(Perm.DELETE).user(getAuthenticatedUser()).target(research).build();
        researchPermissionRepository.save(permission);
        return research;
    }

    private MailMessage composeMailMessage(final MailMessageTemplate mailMessageTemplate, final User respondent,
            final String surveyLinkToken) {

        Map<String, Object> model = new HashMap<>();
        model.put("lastname", StringUtils.defaultIfBlank(respondent.getSurname(), ""));
        model.put("firstname", StringUtils.defaultIfBlank(respondent.getGivenNames(), ""));
        model.put("gender", respondent.getGender());
        model.put("link", "http://localhost:8080/questionaires-ui/token=" + surveyLinkToken);

        Language preferredLanguage = respondent.getPreferredLanguage();

        StringBuilder templateLocation = new StringBuilder().append(mailMessageTemplate.getId());
        if (preferredLanguage != null) {
            templateLocation.append("/");
            templateLocation.append(preferredLanguage);
        }
        VelocityEngine velocityEngine = velocityFactory.getObject();

        String body = VelocityEngineUtils.mergeTemplateIntoString(velocityEngine, templateLocation.toString(),
                "UTF-8", model);

        MailMessageTemplateLanguageSettings languageSettings = mailMessageTemplate.getLanguageSettings();
        if (preferredLanguage != null && !preferredLanguage.equals(mailMessageTemplate.getLanguage())) {
            MailMessageTemplateTranslation preferedTranslation = mailMessageTemplate.getTranslations()
                    .get(preferredLanguage);
            if (preferedTranslation != null) {
                languageSettings = preferedTranslation.getLanguageSettings();
            }
        }
        MailMessage mailMessage = MailMessage.with().subject(languageSettings.getSubject())
                .to(respondent.getEmail()).replyTo(mailMessageTemplate.getReplyTo())
                .from(mailMessageTemplate.getFromAddress()).text(body).build();
        return mailMessage;
    }

}