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.cvmapping; 017 018import de.isas.mztab2.model.Parameter; 019import java.util.LinkedHashMap; 020import java.util.List; 021import java.util.Map; 022import java.util.stream.Collectors; 023import lombok.extern.slf4j.Slf4j; 024import uk.ac.ebi.pride.utilities.ols.web.service.client.OLSClient; 025import uk.ac.ebi.pride.utilities.ols.web.service.config.OLSWsConfig; 026import uk.ac.ebi.pride.utilities.ols.web.service.model.Identifier; 027 028/** 029 * Abstraction over OLSClient to autoconvert Terms to Parameters and to allow 030 * easy matching of Parameters against parent terms and their children. 031 * 032 * @author nilshoffmann 033 */ 034@Slf4j 035public class CvParameterLookupService { 036 037 private final OLSClient client; 038 private final Map<Parameter, List<Parameter>> childCache; 039 private final Map<Parameter, List<Parameter>> parentCache; 040 041 private static <K, V> Map<K, V> lruCache(final int maxSize) { 042 return new LinkedHashMap<K, V>(maxSize * 4 / 3, 0.75f, true) { 043 @Override 044 protected boolean removeEldestEntry(Map.Entry<K, V> eldest) { 045 return size() > maxSize; 046 } 047 }; 048 } 049 050 /** 051 * Create a new instance of the lookup service with default OLS configuration. 052 */ 053 public CvParameterLookupService() { 054 this(new OLSClient(new OLSWsConfig())); 055 } 056 057 /** 058 * Create a new instance of the lookup service with a custom OLSClient. 059 * @param client the custom OLS client 060 */ 061 public CvParameterLookupService(OLSClient client) { 062 this.client = client; 063 this.childCache = lruCache(4096); 064 this.parentCache = lruCache(4096); 065 } 066 067 /** 068 * Create a new instance of the lookup service with a custom OLSWsConfig configuration. 069 * @param config the custom configuration 070 */ 071 public CvParameterLookupService(OLSWsConfig config) { 072 this(new OLSClient(config)); 073 } 074 075 /** 076 * Clears all query result caches (parent and child). 077 */ 078 public void clearCaches() { 079 this.childCache.clear(); 080 this.parentCache.clear(); 081 } 082 083 /** 084 * Resolve all parents of parameter up to an arbitrary depth (actually height, since we go from bottom to top). 085 * Use at your own risk, the OLS service may terminate your connection if the response is too large or takes too long. 086 * @param parameter the parameter to start from 087 * @return a list of all parent parameters for the given parameter 088 * @throws org.springframework.web.client.HttpClientErrorException on http related errors 089 */ 090 public List<Parameter> resolveParents(Parameter parameter) throws org.springframework.web.client.HttpClientErrorException { 091 return resolveParents(parameter, -1); 092 } 093 094 /** 095 * Resolve all parents of a parameter up to a given maximum depth (1 meaning the immediate parents, -1 meaning all). 096 * @param parameter the parameter to start from 097 * @param levels maximum levels to query 098 * @return a list of all parent parameters for the given parameter 099 * @throws org.springframework.web.client.HttpClientErrorException on http related errors 100 */ 101 public List<Parameter> resolveParents(Parameter parameter, int levels) throws org.springframework.web.client.HttpClientErrorException { 102 if (parameter.getCvAccession() == null || parameter.getCvLabel() == null) { 103 throw new IllegalArgumentException( 104 "Parameter must provide cvAccession and cvLabel!"); 105 } 106 if(parentCache.containsKey(parameter)) { 107 log.debug("Cache hit for parameter "+parameter+" in parent cache!"); 108 return parentCache.get(parameter); 109 } 110 Identifier ident = new Identifier(parameter.getCvAccession(), 111 Identifier.IdentifierType.OBO); 112 List<Parameter> parents = client.getTermParents(ident, parameter.getCvLabel(), levels). 113 stream(). 114 map(CvMappingUtils::asParameter). 115 collect(Collectors.toList()); 116 parentCache.put(parameter, parents); 117 return parents; 118 } 119 120 /** 121 * Resolve all children of a parameter up to a given maximum depth (1 meaning immediate children, -1 meaning all). 122 * @param parameter the parameter to start from 123 * @param levels maximum levels to query 124 * @return a list of all child parameters for the given parameter 125 * @throws org.springframework.web.client.HttpClientErrorException on http related errors 126 */ 127 public List<Parameter> resolveChildren(Parameter parameter, int levels) throws org.springframework.web.client.HttpClientErrorException { 128 if (parameter.getCvAccession() == null || parameter.getCvLabel() == null) { 129 throw new IllegalArgumentException( 130 "Parameter must provide cvAccession and cvLabel!"); 131 } 132 if(childCache.containsKey(parameter)) { 133 log.debug("Cache hit for parameter "+parameter+" in child cache!"); 134 return childCache.get(parameter); 135 } 136 Identifier ident = new Identifier(parameter.getCvAccession(), 137 Identifier.IdentifierType.OBO); 138 List<Parameter> children = client.getTermChildren(ident, parameter.getCvLabel(), levels). 139 stream(). 140 map(CvMappingUtils::asParameter). 141 collect(Collectors.toList()); 142 childCache.put(parameter, children); 143 return children; 144 } 145 146 /** 147 * Resolve all children of a parameter up to an arbitrary depth. 148 * Use at your own risk, the OLS service may terminate your connection if the response is too large or takes too long. 149 * @param parameter the parameter to start from 150 * @return a list of all child parameters for the given parameter 151 * @throws org.springframework.web.client.HttpClientErrorException on http related errors 152 */ 153 public List<Parameter> resolveChildren(Parameter parameter) throws org.springframework.web.client.HttpClientErrorException { 154 return resolveChildren(parameter, -1); 155 } 156 157 /** 158 * Compares two parameters for their parent to child relationship. The result can be one of: IDENTICAL, if parent and potential child are the same node, 159 * CHILD_OF, if potentialChild is a child of parent (at least 1 level away), or NOT_RELATED, if there is no path from child to parent. 160 * @param parent the parent term to start from 161 * @param potentialChild the potential child term to check against parent 162 * @return the comparison result 163 * @throws org.springframework.web.client.HttpClientErrorException on http related errors 164 */ 165 public ParameterComparisonResult isChildOfOrSame(Parameter parent, 166 Parameter potentialChild) throws org.springframework.web.client.HttpClientErrorException { 167 if (parent.getCvAccession(). 168 toUpperCase(). 169 equals(potentialChild.getCvAccession(). 170 toUpperCase())) { 171 return ParameterComparisonResult.IDENTICAL; 172 } 173 List<Parameter> parentsOf = resolveParents(potentialChild); 174 boolean result = parentsOf.stream(). 175 anyMatch((potentialParent) -> 176 { 177 return CvMappingUtils.isEqualTo(potentialParent, parent); 178 }); 179 if (result) { 180 return ParameterComparisonResult.CHILD_OF; 181 } 182 return ParameterComparisonResult.NOT_RELATED; 183 } 184 185}