org.obiba.mica.core.upgrade.Mica220Upgrade.java Source code

Java tutorial

Introduction

Here is the source code for org.obiba.mica.core.upgrade.Mica220Upgrade.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.core.upgrade;

import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Stream;

import javax.inject.Inject;

import org.obiba.mica.core.domain.TaxonomyEntityWrapper;
import org.obiba.mica.spi.search.TaxonomyTarget;
import org.obiba.mica.micaConfig.domain.StudyConfig;
import org.obiba.mica.micaConfig.repository.StudyConfigRepository;
import org.obiba.mica.micaConfig.repository.TaxonomyConfigRepository;
import org.obiba.mica.micaConfig.service.TaxonomyConfigService;
import org.obiba.opal.core.domain.taxonomy.TaxonomyEntity;
import org.obiba.opal.core.domain.taxonomy.Vocabulary;
import org.obiba.runtime.Version;
import org.obiba.runtime.upgrade.UpgradeStep;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Component;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;

@Component
public class Mica220Upgrade implements UpgradeStep {

    private static final Logger logger = LoggerFactory.getLogger(Mica220Upgrade.class);

    @Inject
    private MongoTemplate mongoTemplate;

    @Inject
    private StudyConfigRepository studyConfigRepository;

    @Inject
    TaxonomyConfigRepository taxonomyConfigRepository;

    @Inject
    TaxonomyConfigService taxonomyConfigService;

    @Override
    public String getDescription() {
        return "Migrate data to mica 2.2.0";
    }

    @Override
    public Version getAppliesTo() {
        return new Version(2, 2, 0);
    }

    @Override
    public void execute(Version currentVersion) {

        try {
            updateBioSamplesAttributes();
        } catch (IOException e) {
            logger.info("Don't need migration to mica 2.2.0", e);
        } catch (Exception e) {
            logger.error("Error when trying to updateBioSamplesAttributes.", e);
        }

        try {
            updateStudyTaxonomyMissingFields();
        } catch (Exception e) {
            logger.error("Error when trying to updateStudyTaxonomyMissingFields.", e);
        }

        try {
            updateFixWrongKeysInStudyTaxonomy();
        } catch (Exception e) {
            logger.error("Error when trying to updateFixWrongKeysInStudyTaxonomy.", e);
        }

        try {
            updateTaxonomiesWithRangeCriteria();
        } catch (Exception e) {
            logger.error("Error when trying to updateTaxonomiesWithRangeCriteria.", e);
        }

        try {
            mergeDefaultTaxonomyWithCurrent();
        } catch (Exception e) {
            logger.error("Error when trying to mergeDefaultTaxonomyWithCurrent.", e);
        }

        try {
            removeUselessClassAttributeInModel();
        } catch (Exception e) {
            logger.error("Error when trying to removeUselessClassAttributeInModel.", e);
        }
    }

    private void removeUselessClassAttributeInModel() {
        mongoTemplate.execute(db -> db.eval(
                "db.study.updateMany({\"model.methods._class\":{$exists:true}}, {$unset:{\"model.methods._class\":\"\"}})"));
    }

    private void updateTaxonomiesWithRangeCriteria() {
        Stream.of("network", "study", "dataset", "variable", "taxonomy")
                .forEach(name -> updateTaxonomyWithRangeCriteria(name));
    }

    private void mergeDefaultTaxonomyWithCurrent() {
        Stream.of("network", "study", "dataset", "variable", "taxonomy")
                .forEach(name -> taxonomyConfigService.mergeWithDefault(TaxonomyTarget.fromId(name)));
    }

    void updateTaxonomyWithRangeCriteria(String name) {
        TaxonomyEntityWrapper taxonomy = taxonomyConfigRepository.findOne(name);
        if (taxonomy == null)
            return;

        taxonomy.getTaxonomy().getVocabularies().stream().filter(v -> v.getName().endsWith("-range"))
                .map(TaxonomyEntity::getAttributes).forEach(attributes -> {
                    attributes.put("alias", attributes.get("field").replaceAll("\\.", "-") + "-range");
                    attributes.put("range", "true");
                });

        taxonomyConfigRepository.save(taxonomy);
    }

    private void updateFixWrongKeysInStudyTaxonomy() {

        TaxonomyEntityWrapper studyTaxonomy = taxonomyConfigRepository.findOne("study");
        if (studyTaxonomy == null)
            return;

        List<Vocabulary> vocabularies = studyTaxonomy.getTaxonomy().getVocabularies();

        vocabularies.stream()
                .filter(vocabulary -> vocabulary.getName().equals("numberOfParticipants-sample-number")
                        || vocabulary.getName().equals("numberOfParticipants-sample-range"))
                .map(TaxonomyEntity::getAttributes).forEach(attributes -> {
                    attributes.put("field", "model." + attributes.get("field"));
                    attributes.put("alias", "model-" + attributes.get("alias"));
                });

        taxonomyConfigRepository.save(studyTaxonomy);
    }

    private void updateStudyTaxonomyMissingFields() {
        mongoTemplate.execute(db -> db.eval(addMissingAttributesInStudyTaxonomy()));
    }

    private void updateBioSamplesAttributes() throws IOException {

        List<StudyConfig> studyConfigs = studyConfigRepository.findAll();
        if (studyConfigs.size() != 1)
            return;

        StudyConfig studyConfig = studyConfigs.get(0);

        JsonNode schemaNode = new ObjectMapper().readTree(studyConfig.getSchema());
        if (!propertyExistsInSchema(schemaNode))
            return;

        JsonNode definitionNode = new ObjectMapper().readTree(studyConfig.getDefinition());
        if (!replacePropertyInDefinition(definitionNode))
            return;

        replacePropertyInSchema(schemaNode);

        studyConfig.setSchema(new ObjectMapper().writer().writeValueAsString(schemaNode));
        studyConfig.setDefinition(new ObjectMapper().writer().writeValueAsString(definitionNode));

        studyConfigRepository.save(studyConfig);

        updateAttributeNameInStudies();
    }

    private void updateAttributeNameInStudies() {
        mongoTemplate.execute(db -> db.eval(addBioSamplesAttributeIfNeededQuery()));
        mongoTemplate.execute(db -> db.eval(removeOutdatedBioSamplesAttributeQuery()));
    }

    private void replacePropertyInSchema(JsonNode schemaNode) {
        JsonNode jsonNode = schemaNode.get("properties").get("access").get("items").get("enum");

        for (int i = 0; i < jsonNode.size(); i++) {
            if (jsonNode.get(i).textValue().equals("biosamples")) {
                ((ArrayNode) jsonNode).remove(i);
                ((ArrayNode) jsonNode).add("bio_samples");
                return;
            }
        }
    }

    private boolean replacePropertyInDefinition(JsonNode definitionNode) {
        Iterator<JsonNode> itemsLvl0 = definitionNode.elements();
        while (itemsLvl0.hasNext()) {
            JsonNode itemLvl0 = itemsLvl0.next();
            if (itemLvl0.has("items")) {
                Iterator<JsonNode> itemsLvl1 = itemLvl0.get("items").elements();
                while (itemsLvl1.hasNext()) {
                    JsonNode itemLvl1 = itemsLvl1.next();
                    if (itemLvl1.has("items")) {
                        Iterator<JsonNode> itemsLvl2 = itemLvl1.get("items").elements();
                        while (itemsLvl2.hasNext()) {
                            JsonNode itemLvl2 = itemsLvl2.next();
                            if (itemLvl2.has("titleMap")) {
                                Iterator<JsonNode> titleMaps = itemLvl2.get("titleMap").elements();
                                while (titleMaps.hasNext()) {
                                    JsonNode titleMap = titleMaps.next();
                                    if (titleMap.has("value")
                                            && titleMap.get("value").textValue().equals("biosamples")) {
                                        ((ObjectNode) titleMap).put("value", "bio_samples");
                                        return true;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        return false;
    }

    private boolean propertyExistsInSchema(JsonNode schema) {

        Iterator<JsonNode> values = schema.get("properties").get("access").get("items").get("enum").elements();

        while (values.hasNext()) {
            JsonNode value = values.next();
            if (value.textValue().equals("biosamples"))
                return true;
        }

        return false;
    }

    private String addBioSamplesAttributeIfNeededQuery() {
        return "db.study.updateMany({\"model.access\":\"biosamples\"}, {$push:{\"model.access\":\"bio_samples\"}})";
    }

    private String removeOutdatedBioSamplesAttributeQuery() {
        return "db.study.updateMany({\"model.access\":\"biosamples\"}, {$pull:{\"model.access\":\"biosamples\"}})";
    }

    private String addMissingAttributesInStudyTaxonomy() {
        return "db.taxonomyEntityWrapper.find({" + "    \"_id\": \"study\","
                + "    \"taxonomy.vocabularies.name\": \"access\","
                + "    \"taxonomy.vocabularies.name\": \"start\"," + "    \"taxonomy.vocabularies.name\": \"end\""
                + "}).forEach(function (studyTaxo) {" + ""
                + "    studyTaxo.taxonomy.vocabularies.forEach(function (vocabulary) {" + ""
                + "        if (vocabulary.attributes.field == undefined) {" + ""
                + "            if (vocabulary.name == 'access') {"
                + "                vocabulary.attributes.field = \"model.access\";"
                + "                vocabulary.attributes.alias = \"model-access\";" + "            }" + ""
                + "            if (vocabulary.name == 'start') {"
                + "                vocabulary.attributes.field = \"model.startYear\";"
                + "                vocabulary.attributes.alias = \"model-startYear\";" + "            }" + ""
                + "            if (vocabulary.name == 'end') {"
                + "                vocabulary.attributes.field = \"model.endYear\";"
                + "                vocabulary.attributes.alias = \"model-endYear\";" + "            }" + "        }"
                + "    });" + "" + "    db.taxonomyEntityWrapper.update({'_id': studyTaxo._id}, studyTaxo);"
                + "});";
    }
}