001/*
002 * Copyright 2018 Leibniz-Institut für Analytische Wissenschaften – ISAS – e.V..
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package de.isas.mztab2.validation.handlers;
017
018import de.isas.mztab2.cvmapping.CvMappingUtils;
019import de.isas.mztab2.cvmapping.CvParameterLookupService;
020import de.isas.mztab2.cvmapping.ParameterComparisonResult;
021import de.isas.mztab2.cvmapping.RuleEvaluationResult;
022import de.isas.mztab2.model.Parameter;
023import de.isas.mztab2.validation.CvRuleHandler;
024import info.psidev.cvmapping.CvMappingRule;
025import info.psidev.cvmapping.CvTerm;
026import java.util.LinkedHashMap;
027import java.util.List;
028import java.util.Map;
029import lombok.extern.slf4j.Slf4j;
030import org.apache.commons.jxpath.Pointer;
031import org.apache.commons.lang3.tuple.Pair;
032
033/**
034 * Implements resolution of cv parameters using the provided lookup service.
035 * @author nilshoffmann
036 */
037@Slf4j
038public class ResolvingCvRuleHandler implements CvRuleHandler {
039
040    private final CvParameterLookupService client;
041
042    public ResolvingCvRuleHandler(CvParameterLookupService client) {
043        this.client = client;
044    }
045
046    @Override
047    public RuleEvaluationResult handleRule(CvMappingRule rule,
048        List<Pair<Pointer, Parameter>> filteredSelection) {
049
050        final Map<String, Parameter> allowedParameters = new LinkedHashMap<>();
051        final Map<String, Pair<Pointer, Parameter>> foundParameters = new LinkedHashMap<>();
052
053        log.debug("Evaluating rule " + rule.getId() + " on " + rule.
054            getCvElementPath());
055        if (rule.getCvTermsCombinationLogic() == CvMappingRule.CvTermsCombinationLogic.AND) {
056            if (rule.getCvTerm().
057                size() > 1) {
058                for (CvTerm term : rule.getCvTerm()) {
059                    if (term.isAllowChildren()) {
060                        throw new IllegalArgumentException(
061                            CvMappingUtils.niceToString(rule) + " uses 'AND' combination logic with multiple CvTerms and allowChildren=true! Please change to OR or XOR logic!");
062                    }
063                }
064            }
065        }
066        rule.getCvTerm().
067            forEach((cvTerm) ->
068            {
069                for (Pair<Pointer, Parameter> pair : filteredSelection) {
070                    if (cvTerm.isAllowChildren()) {
071                        log.debug("Resolving children of " + cvTerm.
072                            getTermAccession() + " against " + pair.getValue().
073                                getCvAccession());
074                        //resolve children
075                        try {
076                            ParameterComparisonResult result = client.
077                                isChildOfOrSame(CvMappingUtils.asParameter(
078                                    cvTerm),
079                                    pair.getValue());
080                            switch (result) {
081                                case CHILD_OF:
082                                    log.debug(pair.getValue().
083                                        getCvAccession() + " is a child of " + cvTerm.
084                                            getTermAccession());
085                                    //use key of found parameter, since it is a child of cvTerm / cvTerm is a parent of the child
086                                    allowedParameters.put(pair.getValue().
087                                        getCvAccession().
088                                        toUpperCase(), CvMappingUtils.
089                                            asParameter(
090                                                cvTerm));
091                                    foundParameters.put(pair.getValue().
092                                        getCvAccession().
093                                        toUpperCase(), pair);
094                                    break;
095                                case IDENTICAL:
096                                    if (cvTerm.isUseTerm()) {
097                                        log.debug(pair.getValue().
098                                            getCvAccession() + " is identical to " + cvTerm.
099                                                getTermAccession());
100                                        //use key of found parameter, since both are identical
101                                        allowedParameters.put(pair.getValue().
102                                            getCvAccession().
103                                            toUpperCase(), CvMappingUtils.
104                                                asParameter(cvTerm));
105                                        foundParameters.put(pair.getValue().
106                                            getCvAccession().
107                                            toUpperCase(), pair);
108                                    }
109                                    break;
110                                case NOT_RELATED:
111                                    log.debug(pair.getValue().
112                                        getCvAccession() + " is not related to " + cvTerm.
113                                            getTermAccession());
114                                    //add found parameter as is
115                                    foundParameters.put(pair.getValue().
116                                        getCvAccession().
117                                        toUpperCase(), pair);
118                                    break;
119                            }
120                        } catch (org.springframework.web.client.HttpClientErrorException ex) {
121                            throw new IllegalArgumentException(
122                                "Could not retrieve parents for cv with label '" + pair.
123                                    getValue().
124                                    getCvLabel() + "' and term accession '" + pair.
125                                    getValue().
126                                    getCvAccession() + "' at path " + pair.
127                                    getKey().
128                                    asPath() + "! Please check, whether the cv label and term accession in your file contain a typo or use lowercase/uppercase! Check https://www.ebi.ac.uk/ols/search?q=" + pair.
129                                    getValue().
130                                    getCvAccession() + " for details on the term!",
131                                ex);
132                        }
133                    } else if (cvTerm.isUseTermName()) {
134                        throw new IllegalArgumentException(
135                            "isUseTermName on cvTerm " + cvTerm + " is not supported for rule " + CvMappingUtils.
136                                niceToString(rule) + " at path " + pair.
137                            getKey().
138                            asPath() + "!");
139                    } else {
140                        if (cvTerm.getTermAccession().
141                            toUpperCase().
142                            equals(pair.getValue().
143                                getCvAccession().
144                                toUpperCase())) {
145                            allowedParameters.put(pair.getValue().
146                                getCvAccession().
147                                toUpperCase(), CvMappingUtils.
148                                    asParameter(cvTerm));
149                            foundParameters.put(pair.getValue().
150                                getCvAccession().
151                                toUpperCase(), pair);
152                        }
153                    }
154                }
155            });
156        return new RuleEvaluationResult(rule, filteredSelection,
157            allowedParameters, foundParameters);
158    }
159
160}