org.obiba.mica.study.service.HarmonizationStudyService.java Source code

Java tutorial

Introduction

Here is the source code for org.obiba.mica.study.service.HarmonizationStudyService.java

Source

/*
 * Copyright (c) 2018 OBiBa. All rights reserved.
 *
 * This program and the accompanying materials
 * are made available under the terms of the GNU Public License v3.0.
 *
 * 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 org.obiba.mica.study.service;

import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import org.joda.time.DateTime;
import org.obiba.mica.core.domain.AbstractGitPersistable;
import org.obiba.mica.core.repository.EntityStateRepository;
import org.obiba.mica.dataset.HarmonizationDatasetRepository;
import org.obiba.mica.dataset.HarmonizationDatasetStateRepository;
import org.obiba.mica.dataset.domain.HarmonizationDataset;
import org.obiba.mica.dataset.domain.StudyDataset;
import org.obiba.mica.file.FileStoreService;
import org.obiba.mica.micaConfig.service.MicaConfigService;
import org.obiba.mica.network.NetworkRepository;
import org.obiba.mica.study.ConstraintException;
import org.obiba.mica.study.HarmonizationStudyRepository;
import org.obiba.mica.study.HarmonizationStudyStateRepository;
import org.obiba.mica.study.domain.HarmonizationStudy;
import org.obiba.mica.study.domain.HarmonizationStudyState;
import org.obiba.mica.study.domain.Population;
import org.obiba.mica.study.domain.Study;
import org.obiba.mica.study.event.DraftStudyUpdatedEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.inject.Inject;
import javax.validation.constraints.NotNull;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.toList;

@Service
@Validated
public class HarmonizationStudyService extends AbstractStudyService<HarmonizationStudyState, HarmonizationStudy> {

    private static final Logger log = LoggerFactory.getLogger(HarmonizationStudyService.class);

    private static final String SEPARATOR = ":";

    @Inject
    private HarmonizationStudyRepository harmonizationStudyRepository;

    @Inject
    private HarmonizationStudyStateRepository harmonizationStudyStateRepository;

    @Inject
    private HarmonizationDatasetStateRepository harmonizationDatasetStateRepository;

    @Inject
    private HarmonizationDatasetRepository harmonizationDatasetRepository;

    @Inject
    private NetworkRepository networkRepository;

    @Inject
    private FileStoreService fileStoreService;

    @Inject
    private MicaConfigService micaConfigService;

    @Override
    protected void saveInternal(final HarmonizationStudy study, String comment, boolean cascade) {
        log.info("Saving harmonization study: {}", study.getId());

        // checks if population and dce are still the same
        String studyId = study.getId();
        if (studyId != null) {
            List<String> list = populationsAffected(study, harmonizationStudyRepository.findOne(study.getId()));
            if (list != null && list.size() > 0) {
                checkPopulationMissingConstraints(studyId, list);
            }
        }

        if (study.getLogo() != null && study.getLogo().isJustUploaded()) {
            fileStoreService.save(study.getLogo().getId());
            study.getLogo().setJustUploaded(false);
        }

        ImmutableSet<String> invalidRoles = ImmutableSet.copyOf(Sets.difference(study.membershipRoles(),
                Sets.newHashSet(micaConfigService.getConfig().getRoles())));

        invalidRoles.forEach(study::removeRole);

        HarmonizationStudyState studyState = findEntityState(study, HarmonizationStudyState::new);

        if (!study.isNew())
            ensureGitRepository(studyState);

        studyState.incrementRevisionsAhead();
        harmonizationStudyStateRepository.save(studyState);

        study.setLastModifiedDate(DateTime.now());

        if (cascade)
            harmonizationStudyRepository.saveWithReferences(study);
        else
            harmonizationStudyRepository.save(study);

        gitService.save(study, comment);
        eventBus.post(new DraftStudyUpdatedEvent(study));
    }

    @Override
    public String getTypeName() {
        return "harmonization-study";
    }

    public Map<String, List<String>> getPotentialUnpublishingConflicts(HarmonizationStudy study) {
        List<HarmonizationDataset> datasets = findAllPublishedDatasetsByStudy(study.getId());
        if (!datasets.isEmpty()) {
            return new HashMap<String, List<String>>() {
                {
                    put("harmonizationDataset",
                            datasets.stream().map(HarmonizationDataset::getId).collect(Collectors.toList()));
                }
            };
        }

        return Maps.newHashMap();
    }

    /**
     * Get all published {@link StudyDataset}s of a given {@link Study}.
     *
     * @return List of {@link StudyDataset}s
     */
    public List<HarmonizationDataset> findAllPublishedDatasetsByStudy(@NotNull String studyId) {
        return harmonizationDatasetRepository.findByHarmonizationTableStudyId(studyId).stream()
                .filter(ds -> harmonizationDatasetStateRepository.findOne(ds.getId()).isPublished())
                .collect(Collectors.toList());
    }

    /**
     * @param study
     * @param publishing
     * @return
     */
    public Map<String, List<String>> getPotentialConflicts(HarmonizationStudy study, boolean publishing) {
        if (study.getId() != null) {
            HarmonizationStudy oldStudy = publishing ? study : harmonizationStudyRepository.findOne(study.getId());
            if (oldStudy != null) {
                List<String> populationUIDs = publishing ? toListOfPopulationUids(study)
                        : populationsAffected(study, oldStudy);

                if (populationUIDs != null) {
                    List<String> networkIds = networkRepository.findByStudyIds(study.getId()).stream()
                            .map(AbstractGitPersistable::getId).collect(toList());
                    List<String> harmoDatasetIds = findHarmonizedDatasetDependencies(study.getId(), populationUIDs);

                    if (!harmoDatasetIds.isEmpty() || !networkIds.isEmpty()) {
                        return new HashMap<String, List<String>>() {
                            {
                                put("harmonizationDataset", harmoDatasetIds);
                                put("network", networkIds);
                            }
                        };
                    }
                }
            }
        }

        return null;
    }

    private List<String> populationsAffected(HarmonizationStudy study, HarmonizationStudy oldStudy) {
        if (oldStudy != null) {
            List<String> newPopIDs = study.getPopulations().stream().map(Population::getId).collect(toList());
            List<String> oldPopIDs = oldStudy.getPopulations().stream().map(Population::getId).collect(toList());

            boolean isChangeSignificant = newPopIDs.size() <= oldPopIDs.size() && !newPopIDs.containsAll(oldPopIDs);
            if (isChangeSignificant) {
                oldPopIDs.removeAll(newPopIDs);
                return oldPopIDs;
            } else
                return null;
        } else
            return null;
    }

    @Override
    public List<String> findAllIds() {
        return harmonizationStudyRepository.findAllExistingIds().stream().map(Study::getId).collect(toList());
    }

    @Override
    protected MongoRepository<HarmonizationStudy, String> getRepository() {
        return harmonizationStudyRepository;
    }

    @Override
    protected EntityStateRepository<HarmonizationStudyState> getEntityStateRepository() {
        return harmonizationStudyStateRepository;
    }

    @Override
    protected Class<HarmonizationStudy> getType() {
        return HarmonizationStudy.class;
    }

    private List<String> findHarmonizedDatasetDependencies(String studyId, List<String> concatenatedIds) {
        return concatenatedIds.stream()
                .map(populationId -> harmonizationDatasetRepository
                        .findByHarmonizationTableStudyIdAndHarmonizationTablePopulationId(studyId, populationId))
                .reduce(Lists.newArrayList(), StudyService::listAddAll).stream().map(AbstractGitPersistable::getId)
                .distinct().collect(toList());
    }

    private void checkPopulationMissingConstraints(String studyId, List<String> popIDs) {
        List<String> harmoDatasetIds = findHarmonizedDatasetDependencies(studyId, popIDs);

        if (!harmoDatasetIds.isEmpty()) {
            Map<String, List<String>> conflicts = new HashMap<String, List<String>>() {
                {
                    put("harmonizationDataset", harmoDatasetIds);
                }
            };

            throw new ConstraintException(conflicts);
        }
    }

    /**
     * @param study
     */
    protected void checkStudyConstraints(HarmonizationStudy study) {
        List<String> networkIds = networkRepository.findByStudyIds(study.getId()).stream().map(n -> n.getId())
                .collect(toList());

        if (!networkIds.isEmpty()) {
            Map<String, List<String>> conflicts = new HashMap<String, List<String>>() {
                {
                    put("network", networkIds);
                }
            };

            throw new ConstraintException(conflicts);
        }
    }

    private List<String> toListOfPopulationUids(HarmonizationStudy study) {
        return study.getPopulations().stream().map(Population::getId).collect(toList());
    }

}