001/* 002 * Copyright 2020-2021 Global Biodiversity Information Facility (GBIF) 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 org.gbif.api.util; 017 018import org.gbif.api.model.common.LinneanClassification; 019import org.gbif.api.model.common.LinneanClassificationKeys; 020import org.gbif.api.vocabulary.Rank; 021 022import java.util.LinkedHashMap; 023import java.util.Objects; 024import java.util.stream.Collectors; 025import java.util.stream.Stream; 026 027import javax.annotation.Nullable; 028import javax.validation.constraints.NotNull; 029 030import org.apache.commons.lang3.StringUtils; 031 032@SuppressWarnings("unused") 033public class ClassificationUtils { 034 035 /** 036 * Concatenates all higher Linnean taxa into a single dwc:higherClassification string, skipping 037 * null values. 038 * 039 * @param lc the LinneanClassification to join into the higher classification string 040 * 041 * @return the concatenated dwc:higherClassification string 042 */ 043 @Nullable 044 public static String getHigherClassification(LinneanClassification lc) { 045 return StringUtils.trimToNull( 046 Stream.of(lc.getKingdom(), lc.getPhylum(), lc.getClazz(), 047 lc.getOrder(), lc.getFamily(), lc.getGenus()) 048 .filter(Objects::nonNull) 049 .collect(Collectors.joining(", "))); 050 } 051 052 /** 053 * Gets a higher taxon property by passing the rank of it. 054 * Only Linnean ranks are supported. 055 * 056 * @param lc the LinneanClassification holding the taxon property to be retrieved 057 * @param rank the higher linnean rank to retrieve 058 * 059 * @return the name of the higher taxon or null if rank doesnt exist 060 */ 061 @Nullable 062 public static String getHigherRank(LinneanClassification lc, Rank rank) { 063 if (rank != null) { 064 switch (rank) { 065 case KINGDOM: 066 return lc.getKingdom(); 067 case PHYLUM: 068 return lc.getPhylum(); 069 case CLASS: 070 return lc.getClazz(); 071 case ORDER: 072 return lc.getOrder(); 073 case FAMILY: 074 return lc.getFamily(); 075 case GENUS: 076 return lc.getGenus(); 077 case SUBGENUS: 078 return lc.getSubgenus(); 079 case SPECIES: 080 return lc.getSpecies(); 081 } 082 } 083 return null; 084 } 085 086 /** 087 * Sets a higher taxon property by passing the rank of it. 088 * 089 * @param lc the LinneanClassification on which to set the new property 090 * @param rank the higher linnean rank to set 091 * @param name the higher ranks name 092 */ 093 public static void setHigherRank(LinneanClassification lc, Rank rank, String name) { 094 if (rank != null) { 095 switch (rank) { 096 case KINGDOM: 097 lc.setKingdom(name); 098 break; 099 case PHYLUM: 100 lc.setPhylum(name); 101 break; 102 case CLASS: 103 lc.setClazz(name); 104 break; 105 case ORDER: 106 lc.setOrder(name); 107 break; 108 case FAMILY: 109 lc.setFamily(name); 110 break; 111 case GENUS: 112 lc.setGenus(name); 113 break; 114 case SUBGENUS: 115 lc.setSubgenus(name); 116 break; 117 case SPECIES: 118 lc.setSpecies(name); 119 break; 120 } 121 } 122 } 123 124 /** 125 * An ordered map with entries for all higher Linnean ranks down to species which are not null. 126 * The map starts with the highest rank, e.g. the kingdom and maps the name usage key to its canonical name. 127 * 128 * @param lc the object that implements both LinneanClassification and LinneanClassificationKeys from which to build 129 * the map 130 * 131 * @return map of higher ranks 132 */ 133 @NotNull 134 public static <T extends LinneanClassification & LinneanClassificationKeys> LinkedHashMap<Integer, String> getHigherClassificationMap( 135 T lc) { 136 return getHigherClassificationBaseMap(lc); 137 } 138 139 /** 140 * An ordered map with entries for all higher Linnean ranks down to the actual direct parent of this usage. 141 * The map starts with the highest rank, e.g. the kingdom and maps the name usage key to its canonical name. 142 * The name usage itself is never included, even though a higher rank might point to the usage itself. 143 * 144 * @param lc the object that implements both LinneanClassification and LinneanClassificationKeys from which to build 145 * the map 146 * 147 * @return map of higher ranks 148 */ 149 @NotNull 150 public static <T extends LinneanClassification & LinneanClassificationKeys> LinkedHashMap<Integer, String> getHigherClassificationMap( 151 T lc, int key, Integer parentKey, String parent) { 152 LinkedHashMap<Integer, String> map = getHigherClassificationBaseMap(lc); 153 154 if (parentKey != null) { 155 map.put(parentKey, parent); 156 } 157 // remove notion to this usage 158 map.remove(key); 159 160 return map; 161 } 162 163 private static <T extends LinneanClassification & LinneanClassificationKeys> LinkedHashMap<Integer, String> getHigherClassificationBaseMap( 164 T lc) { 165 LinkedHashMap<Integer, String> map = new LinkedHashMap<>(); 166 if (lc.getKingdomKey() != null) { 167 map.put(lc.getKingdomKey(), lc.getKingdom()); 168 } 169 if (lc.getPhylumKey() != null) { 170 map.put(lc.getPhylumKey(), lc.getPhylum()); 171 } 172 if (lc.getClassKey() != null) { 173 map.put(lc.getClassKey(), lc.getClazz()); 174 } 175 if (lc.getOrderKey() != null) { 176 map.put(lc.getOrderKey(), lc.getOrder()); 177 } 178 if (lc.getFamilyKey() != null) { 179 map.put(lc.getFamilyKey(), lc.getFamily()); 180 } 181 if (lc.getGenusKey() != null) { 182 map.put(lc.getGenusKey(), lc.getGenus()); 183 } 184 if (lc.getSpeciesKey() != null) { 185 map.put(lc.getSpeciesKey(), lc.getSpecies()); 186 } 187 return map; 188 } 189 190 /** 191 * Gets a higher taxon key by passing the rank of it. 192 * Only Linnean ranks are supported. 193 * 194 * @param lck the classification that holds the taxon key 195 * @param rank the higher linnean rank to retrieve 196 * 197 * @return the key of the higher taxon or null if rank doesnt exist 198 */ 199 @Nullable 200 public static Integer getHigherRankKey(LinneanClassificationKeys lck, Rank rank) { 201 if (rank != null) { 202 switch (rank) { 203 case KINGDOM: 204 return lck.getKingdomKey(); 205 case PHYLUM: 206 return lck.getPhylumKey(); 207 case CLASS: 208 return lck.getClassKey(); 209 case ORDER: 210 return lck.getOrderKey(); 211 case FAMILY: 212 return lck.getFamilyKey(); 213 case GENUS: 214 return lck.getGenusKey(); 215 case SUBGENUS: 216 return lck.getSubgenusKey(); 217 case SPECIES: 218 return lck.getSpeciesKey(); 219 } 220 } 221 return null; 222 } 223 224 /** 225 * Sets a higher taxon property by passing the rank of it. 226 * 227 * @param lck the classification on which to set the taxon property 228 * @param rank the higher rank to set 229 * @param usageKey key of the higher ranks usage 230 */ 231 public static void setHigherRankKey(LinneanClassificationKeys lck, Rank rank, Integer usageKey) { 232 if (rank != null) { 233 switch (rank) { 234 case KINGDOM: 235 lck.setKingdomKey(usageKey); 236 break; 237 case PHYLUM: 238 lck.setPhylumKey(usageKey); 239 break; 240 case CLASS: 241 lck.setClassKey(usageKey); 242 break; 243 case ORDER: 244 lck.setOrderKey(usageKey); 245 break; 246 case FAMILY: 247 lck.setFamilyKey(usageKey); 248 break; 249 case GENUS: 250 lck.setGenusKey(usageKey); 251 break; 252 case SUBGENUS: 253 lck.setSubgenusKey(usageKey); 254 break; 255 case SPECIES: 256 lck.setSpeciesKey(usageKey); 257 break; 258 } 259 } 260 } 261 262 /** 263 * Sets a higher taxon property by passing the rank of it. 264 * 265 * @param lc the object that implements both LinneanClassification and LinneanClassificationKeys on which to set 266 * the taxon property 267 * @param rank the higher linnean rank to set 268 * @param name the higher ranks name 269 * @param usageKey key of the higher ranks usage 270 */ 271 public static <T extends LinneanClassification & LinneanClassificationKeys> void setHigherRank( 272 T lc, Rank rank, String name, Integer usageKey 273 ) { 274 setHigherRank(lc, rank, name); 275 setHigherRankKey(lc, rank, usageKey); 276 } 277 278 /** 279 * @return true if at least one higher rank of the classification is given, i.e. not null or empty 280 */ 281 public static boolean hasContent(LinneanClassification lc) { 282 for (Rank qr : Rank.DWC_RANKS) { 283 if (StringUtils.isNotEmpty(getHigherRank(lc, qr))) { 284 return true; 285 } 286 } 287 return false; 288 } 289 290 /** 291 * Copies all linnean classification based higher taxon keys from one instance to another. 292 */ 293 public static void copyLinneanClassificationKeys(LinneanClassificationKeys source, LinneanClassificationKeys target) { 294 for (Rank r : Rank.DWC_RANKS) { 295 setHigherRankKey(target, r, source.getHigherRankKey(r)); 296 } 297 } 298 299 /** 300 * Copies all linnean classification based higher taxon names from one instance to another. 301 */ 302 public static void copyLinneanClassification(LinneanClassification source, LinneanClassification target) { 303 for (Rank r : Rank.DWC_RANKS) { 304 setHigherRank(target, r, source.getHigherRank(r)); 305 } 306 } 307 308 /** 309 * Utility class. 310 */ 311 private ClassificationUtils() { 312 } 313}