001/* 002 * Copyright 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.dwc.terms; 017 018import java.lang.annotation.Annotation; 019import java.util.Arrays; 020import java.util.List; 021import java.util.Map; 022import java.util.regex.Pattern; 023import java.util.stream.Collectors; 024import java.util.stream.Stream; 025 026/** 027 * Utility methods for {@link Term} 028 */ 029public class Terms { 030 031 private static final Pattern NULL_PATTERN = Pattern.compile("^\\s*(\\\\N|\\\\?NULL)\\s*$"); 032 private static final List<Term> VOCABULARY_BACKED_TERMS = findVocabularyBackedTerms(); 033 034 /** 035 * static utility class 036 */ 037 private Terms() { 038 } 039 040 /** 041 * Tries various terms in given order until it finds a non empty value. 042 * 043 * @return value or null 044 */ 045 public static String getValueOfFirst(Map<Term, String> record, Term... terms) { 046 for (Term t : terms) { 047 if (record.containsKey(t)) { 048 String val = clean(record.get(t)); 049 if (val != null) { 050 return val; 051 } 052 } 053 } 054 return null; 055 } 056 057 private static String clean(String str) { 058 if (isTermValueBlank(str)) { 059 return null; 060 } 061 str = str.trim(); 062 if (str.isEmpty()) { 063 return null; 064 } 065 return str; 066 } 067 068 /** 069 * Check if the value provided should be considered "blank" in the context of a {@link Term} value. 070 */ 071 public static boolean isTermValueBlank(String termValue) { 072 return termValue == null || termValue.isEmpty() || NULL_PATTERN.matcher(termValue).find(); 073 } 074 075 /** 076 * Returns all the {@link Term} that are annotated with {@link Vocabulary}. 077 */ 078 public static List<Term> getVocabularyBackedTerms() { 079 return VOCABULARY_BACKED_TERMS; 080 } 081 082 private static List<Term> findVocabularyBackedTerms() { 083 return Stream.of(getTerms(AcefTerm.class), 084 getTerms(AcTerm.class), 085 getTerms(DcTerm.class), 086 getTerms(DwcaTerm.class), 087 getTerms(DwcTerm.class), 088 getTerms(GadmTerm.class), 089 getTerms(GbifInternalTerm.class), 090 getTerms(GbifTerm.class), 091 getTerms(IucnTerm.class), 092 getTerms(XmpRightsTerm.class), 093 getTerms(XmpTerm.class), 094 getTerms(GbifTerm.class)) 095 .flatMap(Arrays::stream) 096 .filter(Terms::isVocabulary) 097 .collect(Collectors.toList()); 098 } 099 100 private static <T extends Term> Term[] getTerms(Class<T> term) { 101 return term.getEnumConstants(); 102 } 103 104 /** 105 * @return true if the term is a handled/annotated as Vocabulary. 106 */ 107 public static boolean isVocabulary(Term term) { 108 return term instanceof Enum && hasTermAnnotation(term, Vocabulary.class); 109 } 110 111 private static boolean hasTermAnnotation(Term term, Class<? extends Annotation> annotation) { 112 try { 113 return term.getClass().getField(((Enum<?>) term).name()).isAnnotationPresent(annotation); 114 } catch (NoSuchFieldException ex) { 115 throw new IllegalArgumentException(ex); 116 } 117 } 118}