Merge branch 'release/5.45.0'
[cdmlib.git] / cdmlib-model / src / main / java / eu / etaxonomy / cdm / strategy / cache / name / NameCacheStrategyBase.java
1 /**
2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
5 *
6 * The contents of this file are subject to the Mozilla Public License Version 1.1
7 * See LICENSE.TXT at the top of this package for the full license terms.
8 */
9 package eu.etaxonomy.cdm.strategy.cache.name;
10
11 import java.util.ArrayList;
12 import java.util.Arrays;
13 import java.util.Collection;
14 import java.util.Iterator;
15 import java.util.List;
16 import java.util.UUID;
17
18 import org.apache.logging.log4j.LogManager;
19 import org.apache.logging.log4j.Logger;
20
21 import eu.etaxonomy.cdm.common.CdmUtils;
22 import eu.etaxonomy.cdm.compare.name.NomenclaturalStatusComparator;
23 import eu.etaxonomy.cdm.format.reference.NomenclaturalSourceFormatter;
24 import eu.etaxonomy.cdm.model.common.CdmBase;
25 import eu.etaxonomy.cdm.model.common.Language;
26 import eu.etaxonomy.cdm.model.name.INonViralName;
27 import eu.etaxonomy.cdm.model.name.NomenclaturalStatus;
28 import eu.etaxonomy.cdm.model.name.NomenclaturalStatusType;
29 import eu.etaxonomy.cdm.model.name.TaxonName;
30 import eu.etaxonomy.cdm.model.term.Representation;
31 import eu.etaxonomy.cdm.ref.TypedEntityReferenceFactory;
32 import eu.etaxonomy.cdm.strategy.StrategyBase;
33 import eu.etaxonomy.cdm.strategy.cache.HTMLTagRules;
34 import eu.etaxonomy.cdm.strategy.cache.TagEnum;
35 import eu.etaxonomy.cdm.strategy.cache.TaggedTextFormatter;
36 import eu.etaxonomy.cdm.strategy.cache.TaggedText;
37 import eu.etaxonomy.cdm.strategy.parser.NonViralNameParserImplRegExBase;
38
39 /**
40 * @author AM
41 */
42 public abstract class NameCacheStrategyBase
43 extends StrategyBase
44 implements INameCacheStrategy {
45
46 private static final long serialVersionUID = -2322348388258675517L;
47 private static final Logger logger = LogManager.getLogger();
48
49 final static UUID uuid = UUID.fromString("817ae5b5-3ac2-414b-a134-a9ae86cba040");
50
51 public NameCacheStrategyBase() {
52 super();
53 }
54
55 @Override
56 public String getFullTitleCache(TaxonName taxonName, HTMLTagRules htmlTagRules) {
57 List<TaggedText> tags = getTaggedFullTitle(taxonName);
58 if (tags == null){
59 return null;
60 }else{
61 String result = createString(tags, htmlTagRules);
62 return result;
63 }
64 }
65
66 @Override
67 public String getFullTitleCache(TaxonName taxonName) {
68 return getFullTitleCache(taxonName, null);
69 }
70
71 @Override
72 public List<TaggedText> getNomStatusTags(TaxonName taxonName, boolean includeSeparatorBefore,
73 boolean includeSeparatorAfter) {
74
75 Collection<NomenclaturalStatus> ncStati = taxonName.getStatus();
76 if (ncStati.size() > 1) {
77 //order to have defined behavior
78 ncStati = new ArrayList<>(ncStati);
79 ((List<NomenclaturalStatus>)ncStati).sort(NomenclaturalStatusComparator.SINGLETON());
80 }
81 Iterator<NomenclaturalStatus> iterator = ncStati.iterator();
82 List<TaggedText> nomStatusTags = new ArrayList<>();
83
84 String statusSeparator = ", ";
85 if (includeSeparatorBefore && !ncStati.isEmpty()){
86 nomStatusTags.add(new TaggedText(TagEnum.separator, statusSeparator));
87 }
88 boolean isFirst = true;
89 while (iterator.hasNext()) {
90 NomenclaturalStatus ncStatus = iterator.next();
91 // since the NewInstance method of nomencatural status allows null as parameter
92 // we have to check for null values here
93 String nomStatusStr = "not defined";
94 if(ncStatus.getType() != null){
95 NomenclaturalStatusType statusType = ncStatus.getType();
96 List<Language> prefLangs = Arrays.asList(new Language[]{Language.LATIN(), Language.DEFAULT()});
97 Representation repr = statusType.getPreferredRepresentation(prefLangs);
98 if (repr != null){
99 if(!Language.LATIN().equals(repr.getLanguage())){
100 String message = "No latin representation available for nom. status. " + statusType.getTitleCache();
101 logger.info(message);
102 }
103 nomStatusStr = repr.getAbbreviatedLabel();
104 }else{
105 String message = "No representation available for nom. status. " + statusType.getTitleCache();
106 logger.warn(message);
107 nomStatusStr = statusType.getTitleCache();
108 }
109 }else if(isNotBlank(ncStatus.getRuleConsidered())){
110 nomStatusStr = ncStatus.getRuleConsidered();
111 }
112 if (!isFirst) {
113 nomStatusTags.add(new TaggedText(TagEnum.separator, statusSeparator));
114 }
115 nomStatusTags.add(new TaggedText(TagEnum.nomStatus, nomStatusStr, TypedEntityReferenceFactory.fromTypeAndId(ncStatus.getClass(), ncStatus.getUuid())));
116 isFirst = false;
117 }
118 if (includeSeparatorAfter && !isFirst){
119 nomStatusTags.add(new TaggedText(TagEnum.postSeparator, ","));
120 }
121 return nomStatusTags;
122 }
123
124 @Override
125 public String getNameCache(TaxonName nonViralName) {
126 List<TaggedText> tags = getTaggedName(nonViralName);
127 if (tags == null){
128 return null;
129 }else{
130 String result = createString(tags);
131 return result;
132 }
133 }
134
135 @Override
136 public String getNameCache(TaxonName nonViralName, HTMLTagRules htmlTagRules) {
137 List<TaggedText> tags = getTaggedName(nonViralName);
138 if (tags == null){
139 return null;
140 }else{
141 String result = createString(tags, htmlTagRules);
142 return result;
143 }
144 }
145
146 /**
147 * Generates and returns the title cache of the given name.
148 * The title cache in general includes the name and the authorship and year for some types of names.
149 *
150 * @see eu.etaxonomy.cdm.strategy.INameCacheStrategy#getTitleCache(eu.etaxonomy.cdm.model.common.CdmBase)
151 * @see eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy#getTitleCache(eu.etaxonomy.cdm.model.common.IdentifiableEntity)
152 */
153 @Override
154 public String getTitleCache(TaxonName taxonName) {
155 return getTitleCache(taxonName, null);
156 }
157
158 @Override
159 public String getTitleCache(TaxonName taxonName, HTMLTagRules htmlTagRules) {
160 List<TaggedText> tags = getTaggedTitle(taxonName);
161 if (tags == null){
162 return null;
163 }else{
164 String result = createString(tags, htmlTagRules);
165 return result;
166 }
167 }
168
169 @Override
170 public List<TaggedText> getTaggedTitle(TaxonName taxonName) {
171 if (taxonName == null){
172 return null;
173 }
174 //TODO how to handle protected fullTitleCache here?
175
176 if (taxonName.isProtectedTitleCache()){
177 //protected title cache
178 List<TaggedText> tags = new ArrayList<>();
179 tags.add(new TaggedText(TagEnum.name, taxonName.getTitleCache()));
180 return tags;
181 }else{
182 return doGetTaggedTitle(taxonName);
183 }
184 }
185
186 protected abstract List<TaggedText> doGetTaggedTitle(TaxonName taxonName);
187
188 @Override
189 public List<TaggedText> getTaggedFullTitle(TaxonName taxonName) {
190 List<TaggedText> tags = new ArrayList<>();
191
192 //null
193 if (taxonName == null){
194 return null;
195 }
196
197 //protected full title cache
198 if (taxonName.isProtectedFullTitleCache()){
199 tags.add(new TaggedText(TagEnum.fullName, taxonName.getFullTitleCache()));
200 return tags;
201 }
202
203 //title cache
204 // String titleCache = nonViralName.getTitleCache();
205 List<TaggedText> titleTags = getTaggedTitle(taxonName);
206 tags.addAll(titleTags);
207
208 //reference
209 String referenceCache = NomenclaturalSourceFormatter.INSTANCE().format(taxonName.getNomenclaturalSource());
210 //add to tags
211 if (isNotBlank(referenceCache)){
212 if (! referenceCache.trim().startsWith("in ")){
213 String refConcat = ", ";
214 tags.add(new TaggedText(TagEnum.separator, refConcat));
215 }
216 tags.add(new TaggedText(TagEnum.reference, referenceCache));
217 }
218
219 addOriginalSpelling(tags, taxonName);
220
221 //nomenclatural status
222 tags.addAll(getNomStatusTags(taxonName, true, false));
223 return tags;
224 }
225
226 protected void addOriginalSpelling(List<TaggedText> tags, TaxonName currentName){
227
228 currentName = CdmBase.deproxy(currentName);
229 //Hibernate.initialize(currentName.getRelationsToThisName());
230 TaxonName originalName = currentName.getOriginalSpelling();
231 if (originalName != null){
232 String originalInfo;
233 tags.add(new TaggedText(TagEnum.nameInSourceSeparator, " [as \""));
234 if (!originalName.isNonViral()){
235 originalInfo = originalName.getTitleCache();
236 tags.add(new TaggedText(TagEnum.name, originalInfo));
237 }else{
238 INonViralName originalNvName = CdmBase.deproxy(originalName);
239 originalInfo = makeOriginalInfo(originalNvName, tags);
240 for (String split : originalInfo.split(" ")){
241 if (split.matches(NonViralNameParserImplRegExBase.infraSpeciesMarker)
242 || split.matches(NonViralNameParserImplRegExBase.oldInfraSpeciesMarker)) {
243 tags.add(new TaggedText(TagEnum.rank, split));
244 }else{
245 tags.add(new TaggedText(TagEnum.name, split));
246 }
247 }
248 }
249 tags.add(new TaggedText(TagEnum.nameInSourceSeparator, "\"]"));
250 }else{
251 return;
252 }
253 }
254
255 private String makeOriginalInfo(INonViralName originalName,
256 List<TaggedText> currentNameTags) {
257 //use cache if necessary
258 String cacheToUse = null;
259 if (originalName.isProtectedNameCache() && isNotBlank(originalName.getNameCache())){
260 cacheToUse = originalName.getNameCache();
261 }else if (originalName.isProtectedTitleCache() && isNotBlank(originalName.getTitleCache())){
262 cacheToUse = originalName.getTitleCache();
263 }else if (originalName.isProtectedFullTitleCache() && isNotBlank(originalName.getFullTitleCache())){
264 cacheToUse = originalName.getFullTitleCache();
265 }
266 if (cacheToUse != null){
267 return cacheToUse;
268 }
269 //use atomized data
270 //get originalNameParts array
271 String originalInfo = originalName.getNameCache();
272 if (originalInfo == null){
273 originalInfo = originalName.getTitleCache();
274 }
275 if (originalInfo == null){ //should not happen
276 originalInfo = originalName.getFullTitleCache();
277 }
278 String[] originalNameSplit = originalInfo.split("\\s+");
279
280 //get current name parts
281 String currentNameString = createString(currentNameTags);
282 String[] currentNameSplit = currentNameString.split("\\s+");
283
284 //compute string
285 String result = originalInfo;
286 Integer firstDiff = null;
287 Integer lastDiff = -1;
288 for (int i = 0; i < Math.min(originalNameSplit.length, currentNameSplit.length); i++){
289 if (!originalNameSplit[i].equals(currentNameSplit[i])){
290 lastDiff = i;
291 firstDiff = (firstDiff == null) ? i : firstDiff;
292 }
293 }
294 if (firstDiff != null){
295 result = CdmUtils.concat(" ", Arrays.asList(originalNameSplit).subList(firstDiff, lastDiff+1).toArray(new String[0]));
296 }
297
298 return result;
299 }
300
301 protected String createString(List<TaggedText> tags) {
302 return TaggedTextFormatter.createString(tags);
303 }
304
305 protected String createString(List<TaggedText> tags, HTMLTagRules htmlTagRules) {
306 return TaggedTextFormatter.createString(tags, htmlTagRules);
307 }
308 }