se.inera.intyg.intygstjanst.web.service.impl.CertificateServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for se.inera.intyg.intygstjanst.web.service.impl.CertificateServiceImpl.java

Source

/*
 * Copyright (C) 2016 Inera AB (http://www.inera.se)
 *
 * This file is part of sklintyg (https://github.com/sklintyg).
 *
 * sklintyg is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * sklintyg 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
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package se.inera.intyg.intygstjanst.web.service.impl;

import java.util.HashSet;
import java.util.List;

import org.joda.time.LocalDate;
import org.joda.time.LocalDateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import com.google.common.annotations.VisibleForTesting;

import se.inera.ifv.insuranceprocess.healthreporting.revokemedicalcertificateresponder.v1.RevokeType;
import se.inera.intyg.common.support.integration.module.exception.CertificateAlreadyExistsException;
import se.inera.intyg.common.support.integration.module.exception.CertificateRevokedException;
import se.inera.intyg.common.support.integration.module.exception.InvalidCertificateException;
import se.inera.intyg.common.support.integration.module.exception.MissingConsentException;
import se.inera.intyg.common.support.model.CertificateState;
import se.inera.intyg.common.support.modules.registry.IntygModuleRegistryImpl;
import se.inera.intyg.common.support.modules.support.api.CertificateHolder;
import se.inera.intyg.common.support.modules.support.api.ModuleContainerApi;
import se.inera.intyg.common.support.modules.support.api.dto.Personnummer;
import se.inera.intyg.intygstjanst.persistence.exception.PersistenceException;
import se.inera.intyg.intygstjanst.persistence.model.dao.Certificate;
import se.inera.intyg.intygstjanst.persistence.model.dao.CertificateDao;
import se.inera.intyg.intygstjanst.persistence.model.dao.CertificateStateHistoryEntry;
import se.inera.intyg.intygstjanst.persistence.model.dao.OriginalCertificate;
import se.inera.intyg.intygstjanst.web.exception.RecipientUnknownException;
import se.inera.intyg.intygstjanst.web.integration.converter.ConverterUtil;
import se.inera.intyg.intygstjanst.web.service.CertificateSenderService;
import se.inera.intyg.intygstjanst.web.service.CertificateService;
import se.inera.intyg.intygstjanst.web.service.ConsentService;
import se.inera.intyg.intygstjanst.web.service.MonitoringLogService;
import se.inera.intyg.intygstjanst.web.service.SjukfallCertificateService;
import se.inera.intyg.intygstjanst.web.service.StatisticsService;

/**
 * @author andreaskaltenbach
 */
@Service
public class CertificateServiceImpl implements CertificateService, ModuleContainerApi {

    private static final Logger LOG = LoggerFactory.getLogger(CertificateServiceImpl.class);

    public static final String HVTARGET = "HV";

    @Autowired
    private CertificateDao certificateDao;

    @SuppressWarnings("unused")
    @Autowired
    private IntygModuleRegistryImpl moduleRegistry;

    @Autowired
    private CertificateSenderService senderService;

    @Autowired
    private ConsentService consentService;

    @Autowired
    private StatisticsService statisticsService;

    @Autowired
    private MonitoringLogService monitoringLogService;

    @Autowired
    private SjukfallCertificateService sjukfallCertificateService;

    @Autowired
    @Value("${store.original.certificate}")
    private Boolean shouldStoreOriginalCertificate = true;

    @Override
    @Transactional(readOnly = true)
    public List<Certificate> listCertificatesForCitizen(Personnummer civicRegistrationNumber,
            List<String> certificateTypes, LocalDate fromDate, LocalDate toDate) throws MissingConsentException {
        assertConsent(civicRegistrationNumber);
        return certificateDao.findCertificate(civicRegistrationNumber, certificateTypes, fromDate, toDate, null);
    }

    @Override
    @Transactional(readOnly = true)
    public List<Certificate> listCertificatesForCare(Personnummer civicRegistrationNumber, List<String> careUnits) {
        return certificateDao.findCertificate(civicRegistrationNumber, null, null, null, careUnits);
    }

    @Override
    @Transactional(readOnly = true, noRollbackFor = { PersistenceException.class })
    public Certificate getCertificateForCitizen(Personnummer civicRegistrationNumber, String certificateId)
            throws InvalidCertificateException, CertificateRevokedException, MissingConsentException {

        assertConsent(civicRegistrationNumber);

        Certificate certificate = null;
        try {
            certificate = getCertificateInternal(civicRegistrationNumber, certificateId);
        } catch (PersistenceException e) {
            throw new InvalidCertificateException(certificateId, civicRegistrationNumber);
        }

        if (certificate == null) {
            throw new InvalidCertificateException(certificateId, civicRegistrationNumber);
        }

        if (certificate.isRevoked()) {
            throw new CertificateRevokedException(certificateId);
        }

        return certificate;
    }

    @Override
    @Transactional(readOnly = true, noRollbackFor = { PersistenceException.class })
    public Certificate getCertificateForCare(String certificateId) throws InvalidCertificateException {

        Certificate certificate = null;
        try {
            certificate = getCertificateInternal(null, certificateId);
        } catch (PersistenceException e) {
            throw new InvalidCertificateException(certificateId, null);
        }

        if (certificate == null) {
            throw new InvalidCertificateException(certificateId, null);
        }

        return certificate;
    }

    @Override
    @Transactional
    public SendStatus sendCertificate(Personnummer civicRegistrationNumber, String certificateId,
            String recipientId)
            throws InvalidCertificateException, CertificateRevokedException, RecipientUnknownException {

        Certificate certificate = null;
        try {
            certificate = getCertificateInternal(civicRegistrationNumber, certificateId);
        } catch (PersistenceException e) {
            throw new InvalidCertificateException(certificateId, civicRegistrationNumber);
        }

        if (certificate == null) {
            throw new InvalidCertificateException(certificateId, civicRegistrationNumber);
        }

        if (certificate.isRevoked()) {
            throw new CertificateRevokedException(certificateId);
        }

        if (certificate.isAlreadySent(recipientId)) {
            return SendStatus.ALREADY_SENT;
        }

        // Do send the certificate
        senderService.sendCertificate(certificate, recipientId);

        // Update the certificate
        setCertificateState(civicRegistrationNumber, certificateId, recipientId, CertificateState.SENT, null);

        return SendStatus.OK;
    }

    @Override
    @Transactional(noRollbackFor = { InvalidCertificateException.class, PersistenceException.class })
    public void setCertificateState(Personnummer civicRegistrationNumber, String certificateId, String target,
            CertificateState state, LocalDateTime timestamp) throws InvalidCertificateException {
        try {
            certificateDao.updateStatus(certificateId, civicRegistrationNumber, state, target, timestamp);
        } catch (PersistenceException e) {
            throw new InvalidCertificateException(certificateId, civicRegistrationNumber);
        }
    }

    @Override
    @Transactional(propagation = Propagation.MANDATORY, noRollbackFor = { InvalidCertificateException.class,
            CertificateRevokedException.class })
    public Certificate revokeCertificate(Personnummer civicRegistrationNumber, String certificateId,
            RevokeType revokeData) throws InvalidCertificateException, CertificateRevokedException {
        Certificate certificate = null;
        try {
            certificate = getCertificateInternal(civicRegistrationNumber, certificateId);
        } catch (PersistenceException e) {
            throw new InvalidCertificateException(certificateId, civicRegistrationNumber);
        }

        if (certificate == null) {
            throw new InvalidCertificateException(certificateId, civicRegistrationNumber);
        }

        if (certificate.isRevoked()) {
            throw new CertificateRevokedException(certificateId);
        }

        setCertificateState(civicRegistrationNumber, certificateId, HVTARGET, CertificateState.CANCELLED, null);

        if (revokeData != null) {
            sendRevokeMessagesToRecipients(certificate, revokeData);
        }

        return certificate;
    }

    @Override
    @Transactional(noRollbackFor = { PersistenceException.class })
    public void setArchived(String certificateId, Personnummer civicRegistrationNumber, String archivedState)
            throws InvalidCertificateException {
        try {
            certificateDao.setArchived(certificateId, civicRegistrationNumber, archivedState);
        } catch (PersistenceException e) {
            throw new InvalidCertificateException(certificateId, civicRegistrationNumber);
        }
    }

    @Override
    @Transactional
    public void certificateReceived(CertificateHolder certificateHolder)
            throws CertificateAlreadyExistsException, InvalidCertificateException {
        LOG.debug("Certificate received {}", certificateHolder.getId());
        Certificate certificate = storeCertificate(certificateHolder);
        LOG.debug("Certificate stored {}", certificateHolder.getId());
        monitoringLogService.logCertificateRegistered(certificate.getId(), certificate.getType(),
                certificate.getCareUnitId());

        if (certificateHolder.isWireTapped()) {
            Personnummer personnummer = certificateHolder.getCivicRegistrationNumber();
            String certificateId = certificateHolder.getId();
            final String recipient = "FK";
            setCertificateState(personnummer, certificateId, recipient, CertificateState.SENT, new LocalDateTime());
            monitoringLogService.logCertificateSentAndNotifiedByWiretapping(certificate.getId(),
                    certificate.getType(), certificate.getCareUnitId(), recipient);
        }

        statisticsService.created(certificate);

        /**
         * TODO INTYG-2042: This code below should be uncommented and used immediately when the statistics service has
         * been updated accordingly.
         * String transformedXml = certificateReceivedForStatistics(certificateHolder);
         * statisticsService.created(transformedXml, certificate.getId(), certificate.getType(),
         * certificate.getCareUnitId());
         **/

        sjukfallCertificateService.created(certificate);

    }

    /**
     * TODO INTYG-2042: This code should be uncommented and used immediately when the statistics service has been
     * updated accordingly.
     * private String certificateReceivedForStatistics(CertificateHolder certificateHolder)
     * throws CertificateAlreadyExistsException, InvalidCertificateException {
     * try {
     * ModuleApi moduleApi = moduleRegistry.getModuleApi(certificateHolder.getType());
     * String resultXml = moduleApi.transformToStatisticsService(certificateHolder.getOriginalCertificate());
     * return resultXml;
     * } catch (ModuleNotFoundException | ModuleException e) {
     * LOG.error("Module not found for certificate of type {}", certificateHolder.getType());
     * throw Throwables.propagate(e);
     * }
     * }
     **/

    @VisibleForTesting
    Certificate storeCertificate(CertificateHolder certificateHolder)
            throws CertificateAlreadyExistsException, InvalidCertificateException {
        Certificate certificate = ConverterUtil.toCertificate(certificateHolder);

        // ensure that certificate does not exist yet
        try {
            checkForExistingCertificate(certificate.getId(), certificate.getCivicRegistrationNumber());
        } catch (PersistenceException e) {
            throw new InvalidCertificateException(certificate.getId(), certificate.getCivicRegistrationNumber());
        }

        // add initial RECEIVED state using current time as receiving timestamp
        CertificateStateHistoryEntry state = new CertificateStateHistoryEntry(HVTARGET, CertificateState.RECEIVED,
                new LocalDateTime());
        certificate.addState(state);
        certificateDao.store(certificate);
        storeOriginalCertificate(certificateHolder.getOriginalCertificate(), certificate);
        return certificate;
    }

    @Override
    @Transactional(readOnly = true, noRollbackFor = { PersistenceException.class })
    public CertificateHolder getCertificate(String certificateId, Personnummer personId, boolean checkConsent)
            throws InvalidCertificateException {
        if (checkConsent && personId != null && !consentService.isConsent(personId)) {
            throw new MissingConsentException(personId);
        }

        Certificate certificate = null;
        try {
            certificate = getCertificateInternal(personId, certificateId);
        } catch (PersistenceException e) {
            throw new InvalidCertificateException(certificateId, personId);
        }

        if (certificate == null) {
            throw new InvalidCertificateException(certificateId, personId);
        }

        return ConverterUtil.toCertificateHolder(certificate);
    }

    private void assertConsent(Personnummer civicRegistrationNumber) throws MissingConsentException {
        if (civicRegistrationNumber == null || StringUtils.isEmpty(civicRegistrationNumber.getPersonnummer())) {
            throw new IllegalArgumentException("Invalid/missing civicRegistrationNumber");
        }

        if (!consentService.isConsent(civicRegistrationNumber)) {
            throw new MissingConsentException(civicRegistrationNumber);
        }
    }

    private void checkForExistingCertificate(String certificateId, Personnummer personnummer)
            throws CertificateAlreadyExistsException, PersistenceException {
        if (certificateDao.getCertificate(personnummer, certificateId) != null) {
            throw new CertificateAlreadyExistsException(certificateId);
        }
    }

    private Certificate getCertificateInternal(Personnummer civicRegistrationNumber, String certificateId)
            throws PersistenceException {
        return certificateDao.getCertificate(civicRegistrationNumber, certificateId);
    }

    private void sendRevokeMessagesToRecipients(Certificate certificate, RevokeType revokeData) {
        HashSet<String> recipientsFound = new HashSet<>();

        for (CertificateStateHistoryEntry event : certificate.getStates()) {
            if (event.getState().equals(CertificateState.SENT)) {
                String recipient = event.getTarget();
                if (recipientsFound.add(recipient)) {
                    senderService.sendCertificateRevocation(certificate, recipient, revokeData);
                }
            }
        }
    }

    /**
     *
     * @param utlatandeXml
     *            the received certificate utlatande xml
     * @param certificate
     *            the {@link Certificate} generated from the utlatandeXml, or <code>null</code> if unknown.
     */
    private void storeOriginalCertificate(String utlatandeXml, Certificate certificate) {
        if (shouldStoreOriginalCertificate) {
            OriginalCertificate original = new OriginalCertificate(LocalDateTime.now(), utlatandeXml, certificate);
            certificateDao.storeOriginalCertificate(original);
        }
    }

}