Name cache strategy for infrageneric names and rank species group
[cdmlib.git] / cdmlib-model / src / main / java / eu / etaxonomy / cdm / strategy / cache / name / NonViralNameDefaultCacheStrategy.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.Iterator;
13 import java.util.List;
14 import java.util.Set;
15 import java.util.UUID;
16
17 import org.apache.log4j.Logger;
18
19 import eu.etaxonomy.cdm.common.CdmUtils;
20 import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
21 import eu.etaxonomy.cdm.model.agent.INomenclaturalAuthor;
22 import eu.etaxonomy.cdm.model.agent.Team;
23 import eu.etaxonomy.cdm.model.common.Language;
24 import eu.etaxonomy.cdm.model.common.Representation;
25 import eu.etaxonomy.cdm.model.name.NomenclaturalStatus;
26 import eu.etaxonomy.cdm.model.name.NomenclaturalStatusType;
27 import eu.etaxonomy.cdm.model.name.NonViralName;
28 import eu.etaxonomy.cdm.model.name.Rank;
29 import eu.etaxonomy.cdm.model.reference.INomenclaturalReference;
30 import eu.etaxonomy.cdm.model.reference.ReferenceBase;
31 import eu.etaxonomy.cdm.strategy.exceptions.UnknownCdmTypeException;
32
33
34 /**
35 * This class is a default implementation for the INonViralNameCacheStrategy<T extends NonViralName> interface.
36 * The method actually implements a cache strategy for botanical names so no method has to be overwritten by
37 * a subclass for botanic names.
38 * Where differing from this Default BotanicNameCacheStrategy other subclasses should overwrite the existing methods
39 * e.g. a CacheStrategy for zoological names should overwrite getAuthorAndExAuthor
40 * @author a.mueller
41 */
42 /**
43 * @author AM
44 *
45 * @param <T>
46 */
47 public class NonViralNameDefaultCacheStrategy<T extends NonViralName> extends NameCacheStrategyBase<T> implements INonViralNameCacheStrategy<T> {
48 private static final Logger logger = Logger.getLogger(NonViralNameDefaultCacheStrategy.class);
49
50 final static UUID uuid = UUID.fromString("1cdda0d1-d5bc-480f-bf08-40a510a2f223");
51
52 protected String NameAuthorSeperator = " ";
53 protected String BasionymStart = "(";
54 protected String BasionymEnd = ")";
55 protected String ExAuthorSeperator = " ex ";
56 protected CharSequence BasionymAuthorCombinationAuthorSeperator = " ";
57
58 @Override
59 public UUID getUuid(){
60 return uuid;
61 }
62
63
64 /**
65 * Factory method
66 * @return NonViralNameDefaultCacheStrategy A new instance of NonViralNameDefaultCacheStrategy
67 */
68 public static NonViralNameDefaultCacheStrategy NewInstance(){
69 return new NonViralNameDefaultCacheStrategy();
70 }
71
72 /**
73 * Constructor
74 */
75 protected NonViralNameDefaultCacheStrategy(){
76 super();
77 }
78
79 /* **************** GETTER / SETTER **************************************/
80
81 /**
82 * String that separates the NameCache part from the AuthorCache part
83 * @return
84 */
85 public String getNameAuthorSeperator() {
86 return NameAuthorSeperator;
87 }
88
89
90 public void setNameAuthorSeperator(String nameAuthorSeperator) {
91 NameAuthorSeperator = nameAuthorSeperator;
92 }
93
94
95 /**
96 * String the basionym author part starts with e.g. '('.
97 * This should correspond with the {@link NonViralNameDefaultCacheStrategy#getBasionymEnd() basionymEnd} attribute
98 * @return
99 */
100 public String getBasionymStart() {
101 return BasionymStart;
102 }
103
104
105 public void setBasionymStart(String basionymStart) {
106 BasionymStart = basionymStart;
107 }
108
109
110 /**
111 * String the basionym author part ends with e.g. ')'.
112 * This should correspond with the {@link NonViralNameDefaultCacheStrategy#getBasionymStart() basionymStart} attribute
113 * @return
114 */
115 public String getBasionymEnd() {
116 return BasionymEnd;
117 }
118
119
120 public void setBasionymEnd(String basionymEnd) {
121 BasionymEnd = basionymEnd;
122 }
123
124
125 /**
126 * String to seperate ex author from author.
127 * @return
128 */
129 public String getExAuthorSeperator() {
130 return ExAuthorSeperator;
131 }
132
133
134 public void setExAuthorSeperator(String exAuthorSeperator) {
135 ExAuthorSeperator = exAuthorSeperator;
136 }
137
138
139 /**
140 * String that seperates the basionym/original_combination author part from the combination author part
141 * @return
142 */
143 public CharSequence getBasionymAuthorCombinationAuthorSeperator() {
144 return BasionymAuthorCombinationAuthorSeperator;
145 }
146
147
148 public void setBasionymAuthorCombinationAuthorSeperator(
149 CharSequence basionymAuthorCombinationAuthorSeperator) {
150 BasionymAuthorCombinationAuthorSeperator = basionymAuthorCombinationAuthorSeperator;
151 }
152
153
154 //** *****************************************************************************************/
155
156
157 /* (non-Javadoc)
158 * @see eu.etaxonomy.cdm.strategy.INameCacheStrategy#getNameCache()
159 */
160 @Override
161 public String getTitleCache(T nonViralName) {
162 if (nonViralName == null){
163 return null;
164 }
165 String result = "";
166 //Autonym
167 if (isAutonym(nonViralName)){
168 String speciesPart = getSpeciesNameCache(nonViralName);
169 //TODO should this include basionym authors and ex authors
170 INomenclaturalAuthor author = nonViralName.getCombinationAuthorTeam();
171 String authorPart = "";
172 if (author != null){
173 authorPart = CdmUtils.Nz(author.getNomenclaturalTitle());
174 }
175 INomenclaturalAuthor basAuthor = nonViralName.getBasionymAuthorTeam();
176 String basAuthorPart = "";
177 if (basAuthor != null){
178 basAuthorPart = CdmUtils.Nz(basAuthor.getNomenclaturalTitle());
179 }
180 if (! "".equals(basAuthorPart)){
181 authorPart = "("+ basAuthorPart +")" + authorPart;
182 }
183 String infraSpeciesPart = (CdmUtils.Nz(nonViralName.getInfraSpecificEpithet()));
184
185 String infraSpeciesSeparator = "";
186 if (nonViralName.getRank() == null || !nonViralName.getRank().isInfraSpecific()){
187 //TODO handle exception
188 logger.warn("Rank for autonym does not exist or is not lower than species !!");
189 }else{
190 infraSpeciesSeparator = nonViralName.getRank().getAbbreviation();
191 }
192
193 result = CdmUtils.concat(" ", new String[]{speciesPart, authorPart, infraSpeciesSeparator, infraSpeciesPart});
194 result = result.trim().replace("null", "");
195 }else{ //not Autonym
196 String nameCache = CdmUtils.Nz(getNameCache(nonViralName));
197 if (nameIncludesAuthorship(nonViralName)){
198 String authorCache = CdmUtils.Nz(getAuthorshipCache(nonViralName));
199 result = CdmUtils.concat(NameAuthorSeperator, nameCache, authorCache);
200 }else{
201 result = nameCache;
202 }
203 }
204 return result;
205 }
206
207 protected boolean nameIncludesAuthorship(NonViralName nonViralName){
208 Rank rank = nonViralName.getRank();
209 if (rank != null && rank.isSpeciesAggregate()){
210 return false;
211 }else{
212 return true;
213 }
214 }
215
216
217 @Override
218 public String getFullTitleCache(T nonViralName) {
219 //null
220 if (nonViralName == null){
221 return null;
222 }
223 //full title cache
224 if (nonViralName.isProtectedFullTitleCache() == true) {
225 return nonViralName.getFullTitleCache();
226 }
227
228 String result = "";
229 //title cache
230 String titleCache = getTitleCache(nonViralName);
231
232 String microReference = nonViralName.getNomenclaturalMicroReference();
233 ReferenceBase<?> ref = nonViralName.getNomenclaturalReference();
234 String referenceBaseCache = null;
235 if (ref != null){
236 INomenclaturalReference nomRef = HibernateProxyHelper.deproxy(ref, INomenclaturalReference.class);
237 referenceBaseCache = nomRef.getNomenclaturalCitation(microReference);
238 }
239
240 //make nomenclatural status
241 String ncStatusCache = "";
242 Set<NomenclaturalStatus> ncStati = nonViralName.getStatus();
243 Iterator<NomenclaturalStatus> iterator = ncStati.iterator();
244 while (iterator.hasNext()) {
245 NomenclaturalStatus ncStatus = (NomenclaturalStatus)iterator.next();
246 NomenclaturalStatusType statusType = ncStatus.getType();
247 Language lang = Language.LATIN();
248 Representation repr = statusType.getRepresentation(lang);
249 ncStatusCache = ", " + repr.getAbbreviatedLabel();
250 }
251 String refConcat = " ";
252 if (referenceBaseCache != null && ! referenceBaseCache.trim().startsWith("in ")){
253 refConcat = ", ";
254 }
255 result = CdmUtils.concat(refConcat, titleCache, referenceBaseCache);
256 result = CdmUtils.concat("", result, ncStatusCache);
257 return result;
258 }
259
260
261 /**
262 * Generates and returns the "name cache" (only scientific name without author teams and year).
263 * @see eu.etaxonomy.cdm.strategy.cache.name.INameCacheStrategy#getNameCache(eu.etaxonomy.cdm.model.name.TaxonNameBase)
264 */
265 public String getNameCache(T nonViralName) {
266 if (nonViralName == null){
267 return null;
268 }
269 String result;
270 Rank rank = nonViralName.getRank();
271
272 if (rank == null){
273 result = getRanklessNameCache(nonViralName);
274 }else if (rank.isInfraSpecific()){
275 result = getInfraSpeciesNameCache(nonViralName);
276 }else if (rank.isSpecies()){
277 result = getSpeciesNameCache(nonViralName);
278 }else if (rank.isInfraGeneric()){
279 result = getInfraGenusNameCache(nonViralName);
280 }else if (rank.isGenus()){
281 result = getGenusOrUninomialNameCache(nonViralName);
282 }else if (rank.isSupraGeneric()){
283 result = getGenusOrUninomialNameCache(nonViralName);
284 }else{
285 logger.warn("Name Strategy for Name (UUID: " + nonViralName.getUuid() + ") not yet implemented");
286 result = "";
287 }
288 return result;
289 }
290
291
292 /* (non-Javadoc)
293 * @see eu.etaxonomy.cdm.strategy.cache.INonViralNameCacheStrategy#getAuthorCache(eu.etaxonomy.cdm.model.name.NonViralName)
294 */
295 public String getAuthorshipCache(T nonViralName) {
296 if (nonViralName == null){
297 return null;
298 }
299 //cache protected
300 if (nonViralName.isProtectedAuthorshipCache() == true) {
301 return nonViralName.getAuthorshipCache();
302 }
303 return getNonCacheAuthorshipCache(nonViralName);
304
305 }
306
307 /**
308 * Returns the authorshipcache string for the atomized authorship fields. Does not use the authorshipfield.
309 * @throws NullPointerException if nonViralName is null.
310 * @param nonViralName
311 * @return
312 */
313 protected String getNonCacheAuthorshipCache(T nonViralName){
314 String result = "";
315 INomenclaturalAuthor combinationAuthor = nonViralName.getCombinationAuthorTeam();
316 INomenclaturalAuthor exCombinationAuthor = nonViralName.getExCombinationAuthorTeam();
317 INomenclaturalAuthor basionymAuthor = nonViralName.getBasionymAuthorTeam();
318 INomenclaturalAuthor exBasionymAuthor = nonViralName.getExBasionymAuthorTeam();
319 String basionymPart = "";
320 String authorPart = "";
321 //basionym
322 if (basionymAuthor != null || exBasionymAuthor != null){
323 basionymPart = BasionymStart + getAuthorAndExAuthor(basionymAuthor, exBasionymAuthor) + BasionymEnd;
324 }
325 if (combinationAuthor != null || exCombinationAuthor != null){
326 authorPart = getAuthorAndExAuthor(combinationAuthor, exCombinationAuthor);
327 }
328 result = CdmUtils.concat(BasionymAuthorCombinationAuthorSeperator, basionymPart, authorPart);
329 return result;
330 }
331
332 /**
333 * Returns the AuthorCache part for a combination of an author and an ex author. This applies on combination authors
334 * as well as on basionym/orginal combination authors.
335 * @param author the author
336 * @param exAuthor the ex-author
337 * @return
338 */
339 protected String getAuthorAndExAuthor(INomenclaturalAuthor author, INomenclaturalAuthor exAuthor){
340 String result = "";
341 String authorString = "";
342 String exAuthorString = "";
343 if (author != null){
344 authorString = CdmUtils.Nz(author.getNomenclaturalTitle());
345 }
346 if (exAuthor != null){
347 exAuthorString = CdmUtils.Nz(exAuthor.getNomenclaturalTitle());
348 }
349 if (exAuthorString.length() > 0 ){
350 exAuthorString = exAuthorString + ExAuthorSeperator;
351 }
352 result = exAuthorString + authorString;
353 return result;
354
355 }
356
357
358 /* (non-Javadoc)
359 * @see eu.etaxonomy.cdm.strategy.INameCacheStrategy#getTaggedName(eu.etaxonomy.cdm.model.common.CdmBase)
360 */
361 @Override
362 public List<Object> getTaggedName(T nonViralName) {
363 List<Object> tags = new ArrayList<Object>();
364 tags.add(nonViralName.getGenusOrUninomial());
365 if (nonViralName.isSpecies() || nonViralName.isInfraSpecific()){
366 tags.add(nonViralName.getSpecificEpithet());
367 }
368
369 // No autonym
370 if (nonViralName.isInfraSpecific() && ! nonViralName.getSpecificEpithet().equals(nonViralName.getInfraSpecificEpithet())){
371 tags.add(nonViralName.getRank());
372 tags.add(nonViralName.getInfraSpecificEpithet());
373 }
374
375 if (nonViralName.isInfraGeneric()){
376 //TODO choose right strategy or generic approach?
377 // --- strategy 1 ---
378 tags.add(nonViralName.getRank());
379 tags.add(nonViralName.getInfraGenericEpithet());
380 // --- strategy 2 ---
381 // tags.add('('+nvn.getInfraGenericEpithet()+')');
382 }
383 Team authorTeam = Team.NewInstance();
384 authorTeam.setProtectedTitleCache(true);
385 authorTeam.setTitleCache(nonViralName.getAuthorshipCache());
386 tags.add(authorTeam);
387
388 // Name is an autonym. Rank and infraspecific eitheton follow the author
389 if (nonViralName.isInfraSpecific() && nonViralName.getSpecificEpithet().equals(nonViralName.getInfraSpecificEpithet())){
390 tags.add(nonViralName.getRank());
391 tags.add(nonViralName.getInfraSpecificEpithet());
392 }
393
394 if(! "".equals(nonViralName.getAppendedPhrase())){
395 tags.add(nonViralName.getAppendedPhrase());
396 }
397
398 return tags;
399 }
400
401
402 /************** PRIVATES ****************/
403
404 protected String getRanklessNameCache(NonViralName nonViralName){
405 String result = "";
406 result = (result + (nonViralName.getGenusOrUninomial())).trim().replace("null", "");
407 result += " " + (CdmUtils.Nz(nonViralName.getSpecificEpithet())).trim();
408 result += " " + (CdmUtils.Nz(nonViralName.getInfraSpecificEpithet())).trim();
409 result = result.trim().replace("null", "");
410 //result += " (rankless)";
411 result = addAppendedPhrase(result, nonViralName);
412 return result;
413 }
414
415
416 protected String getGenusOrUninomialNameCache(NonViralName nonViralName){
417 String result;
418 result = CdmUtils.Nz(nonViralName.getGenusOrUninomial());
419 result = addAppendedPhrase(result, nonViralName);
420 return result;
421 }
422
423 protected String getInfraGenusNameCache(NonViralName nonViralName){
424 String result;
425 Rank rank = nonViralName.getRank();
426 if (rank.isSpeciesAggregate()){
427 return getSpeciesAggregateCache(nonViralName);
428 }
429 String infraGenericMarker = "xxx.";
430 if (rank != null){
431 try {
432 infraGenericMarker = rank.getInfraGenericMarker();
433 } catch (UnknownCdmTypeException e) {
434 infraGenericMarker = "'unhandled infrageneric rank'";
435 }
436 }
437 result = CdmUtils.Nz(nonViralName.getGenusOrUninomial());
438 result += " " + infraGenericMarker + " " + (CdmUtils.Nz(nonViralName.getInfraGenericEpithet())).trim().replace("null", "");
439 result = addAppendedPhrase(result, nonViralName);
440 return result;
441 }
442
443 // aggr.|agg.|group
444 protected String getSpeciesAggregateCache(NonViralName nonViralName){
445 String result;
446 result = CdmUtils.Nz(nonViralName.getGenusOrUninomial());
447 result += " " + CdmUtils.Nz(nonViralName.getSpecificEpithet()).trim().replace("null", "");
448 String marker;
449 try {
450 marker = nonViralName.getRank().getInfraGenericMarker();
451 } catch (UnknownCdmTypeException e) {
452 marker = "'unknown aggregat type'";
453 }
454 result += " " + marker;
455 result = addAppendedPhrase(result, nonViralName);
456 return result;
457 }
458
459 protected String getSpeciesNameCache(NonViralName nonViralName){
460 String result;
461 result = CdmUtils.Nz(nonViralName.getGenusOrUninomial());
462 result += " " + CdmUtils.Nz(nonViralName.getSpecificEpithet()).trim().replace("null", "");
463 result = addAppendedPhrase(result, nonViralName);
464 return result;
465 }
466
467
468 protected String getInfraSpeciesNameCache(NonViralName nonViralName){
469 String result;
470 result = CdmUtils.Nz(nonViralName.getGenusOrUninomial());
471 result += " " + (CdmUtils.Nz(nonViralName.getSpecificEpithet()).trim()).replace("null", "");
472 if (! isAutonym(nonViralName)){
473 result += " " + (nonViralName.getRank().getAbbreviation()).trim().replace("null", "");
474 }
475 result += " " + (CdmUtils.Nz(nonViralName.getInfraSpecificEpithet())).trim().replace("null", "");
476 result = addAppendedPhrase(result, nonViralName);
477 return result;
478 }
479
480
481 /**
482 * @param name
483 * @return true, if name has Rank, Rank is below species and species epithet equals infraSpeciesEpithtet, else false
484 */
485 protected boolean isAutonym(NonViralName nonViralName){
486 if (nonViralName != null && nonViralName.getRank() != null && nonViralName.getSpecificEpithet() != null && nonViralName.getInfraSpecificEpithet() != null &&
487 nonViralName.getRank().isInfraSpecific() && nonViralName.getSpecificEpithet().trim().equals(nonViralName.getInfraSpecificEpithet().trim())){
488 return true;
489 }else{
490 return false;
491 }
492 }
493
494 protected String addAppendedPhrase(String resultString, NonViralName nonViralName){
495 String appendedPhrase = nonViralName ==null ? null : nonViralName.getAppendedPhrase();
496 if (resultString == null){
497 return appendedPhrase;
498 }else if(appendedPhrase == null || "".equals(appendedPhrase.trim())) {
499 return resultString;
500 }else if ("".equals(resultString)){
501 return resultString + appendedPhrase;
502 }else {
503 return resultString + " " + appendedPhrase;
504 }
505 }
506
507
508 public String getLastEpithet(T taxonNameBase) {
509 Rank rank = taxonNameBase.getRank();
510 if(rank.isGenus() || rank.isSupraGeneric()) {
511 return taxonNameBase.getGenusOrUninomial();
512 } else if(rank.isInfraGeneric()) {
513 return taxonNameBase.getInfraGenericEpithet();
514 } else if(rank.isSpecies()) {
515 return taxonNameBase.getSpecificEpithet();
516 } else {
517 return taxonNameBase.getInfraSpecificEpithet();
518 }
519 }
520 }