import java.util.ArrayList;
import java.util.List;
-import org.codehaus.plexus.util.StringUtils;
+import org.apache.commons.lang3.StringUtils;
-import eu.etaxonomy.cdm.common.CdmUtils;
+import eu.etaxonomy.cdm.common.UTF8;
import eu.etaxonomy.cdm.model.agent.Person;
import eu.etaxonomy.cdm.model.agent.Team;
import eu.etaxonomy.cdm.model.agent.TeamOrPersonBase;
import eu.etaxonomy.cdm.model.common.CdmBase;
import eu.etaxonomy.cdm.model.common.Language;
-import eu.etaxonomy.cdm.model.common.Representation;
import eu.etaxonomy.cdm.model.name.TaxonName;
import eu.etaxonomy.cdm.model.reference.Reference;
import eu.etaxonomy.cdm.model.taxon.Taxon;
import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;
import eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType;
+import eu.etaxonomy.cdm.model.term.Representation;
import eu.etaxonomy.cdm.ref.TypedEntityReference;
import eu.etaxonomy.cdm.strategy.cache.TagEnum;
import eu.etaxonomy.cdm.strategy.cache.TaggedText;
+import eu.etaxonomy.cdm.strategy.cache.TaggedTextBuilder;
+import eu.etaxonomy.cdm.strategy.cache.agent.PersonDefaultCacheStrategy;
+import eu.etaxonomy.cdm.strategy.cache.agent.TeamDefaultCacheStrategy;
/**
+ * Formatter for TaxonRelationships.
+ *
* @author a.mueller
* @since 13.08.2018
- *
*/
public class TaxonRelationshipFormatter {
+ private static final String DOUBTFUL_TAXON_MARKER = "?" + UTF8.NARROW_NO_BREAK;
private static final String REL_SEC = ", rel. sec. ";
private static final String ERR_SEC = ", err. sec. ";
private static final String SYN_SEC = ", syn. sec. ";
private static final String AUCT = "auct.";
private static final String SENSU_SEPARATOR = " sensu ";
private static final String SEC_SEPARATOR = " sec. ";
+ private static final String PRO_PARTE_SEPARATOR = ", ";
private static final String DETAIL_SEPARATOR = ": ";
private static final String INVERT_SYMBOL = "<-"; //TODO
private static final String UNDEFINED_SYMBOL = "??"; //TODO
- public List<TaggedText> getTaggedText(TaxonRelationship taxonRelationship, boolean reverse, List<Language> languages) {
+ private static TaxonRelationshipFormatter instance;
+
+// ************************* FACTORY ************************/
+
+ public static TaxonRelationshipFormatter NewInstance(){
+ return new TaxonRelationshipFormatter();
+ }
+
+ public static TaxonRelationshipFormatter INSTANCE(){
+ if (instance == null){
+ instance = NewInstance();
+ }
+ return instance;
+ }
+
+// ******************* CONSTRUCTOR ************************/
+
+ private TaxonRelationshipFormatter(){}
+
+// ********************** METHODS ***************************/
+
+ public List<TaggedText> getTaggedText(TaxonRelationship taxonRelationship, boolean inverse, List<Language> languages) {
+ return getTaggedText(taxonRelationship, inverse, languages, false);
+ }
+
+ public List<TaggedText> getTaggedText(TaxonRelationship taxonRelationship, boolean inverse,
+ List<Language> languages, boolean withoutName) {
if (taxonRelationship == null){
return null;
}
TaxonRelationshipType type = taxonRelationship.getType();
- boolean isMisapplied = type == null ? false : type.isAnyMisappliedName() && reverse;
+ boolean isMisapplied = (type == null ? false : type.isMisappliedName() && inverse);
boolean isSynonym = type == null? false : type.isAnySynonym();
- Taxon relatedTaxon = reverse? taxonRelationship.getFromTaxon()
+ Taxon relatedTaxon = inverse? taxonRelationship.getFromTaxon()
: taxonRelationship.getToTaxon();
if (relatedTaxon == null){
return null;
}
+
+ String doubtfulTaxonStr = relatedTaxon.isDoubtful() ? DOUBTFUL_TAXON_MARKER : "";
+ String doubtfulRelationStr = taxonRelationship.isDoubtful() ? "?" : "";
+
TaxonName name = relatedTaxon.getName();
- List<TaggedText> tags = new ArrayList<>();
+ TaggedTextBuilder builder = new TaggedTextBuilder();
//rel symbol
- String symbol = getSymbol(type, reverse, languages);
- tags.add(TaggedText.NewInstance(TagEnum.symbol, symbol));
-
- //whitespace
- tags.add(TaggedText.NewWhitespaceInstance());
+ String symbol = doubtfulRelationStr + getSymbol(type, inverse, languages);
+ builder.add(TagEnum.symbol, symbol);
//name
- if (isMisapplied){
- //starting quote
- String startQuote = QUOTE_START;
- tags.add(TaggedText.NewSeparatorInstance(startQuote));
-
- //name cache
- List<TaggedText> nameCacheTags = getNameCacheTags(name);
- tags.addAll(nameCacheTags);
-
- //end quote
- String endQuote = QUOTE_END;
- tags.add(TaggedText.NewSeparatorInstance(endQuote));
+ if (!withoutName){
+ if (isMisapplied){
+ //starting quote
+ String startQuote = " " + doubtfulTaxonStr + QUOTE_START;
+ builder.addSeparator(startQuote);
+
+ //name cache
+ List<TaggedText> nameCacheTags = getNameCacheTags(name);
+ builder.addAll(nameCacheTags);
+
+ //end quote
+ String endQuote = QUOTE_END;
+ builder.add(TagEnum.postSeparator, endQuote);
+ }else{
+ builder.addSeparator(" " + doubtfulTaxonStr);
+ //name full title cache
+ List<TaggedText> nameCacheTags = getNameTitleCacheTags(name);
+ builder.addAll(nameCacheTags);
+ }
}else{
- //name title cache
- //TODO fullTitle?
- List<TaggedText> nameCacheTags = getNameTitleCacheTags(name);
- tags.addAll(nameCacheTags);
+ if (isNotBlank(doubtfulTaxonStr)){
+ builder.addSeparator(" " + doubtfulTaxonStr);
+ }
}
-
- //sensu (+ Separatoren?)
+ //sec/sensu (+ Separatoren?)
if (isNotBlank(relatedTaxon.getAppendedPhrase())){
- tags.add(TaggedText.NewWhitespaceInstance());
- tags.add(TaggedText.NewInstance(TagEnum.appendedPhrase, relatedTaxon.getAppendedPhrase()));
+ builder.addWhitespace();
+ builder.add(TagEnum.appendedPhrase, relatedTaxon.getAppendedPhrase());
}
- List<TaggedText> secTags = getSensuTags(relatedTaxon.getSec(), relatedTaxon.getSecMicroReference(), isMisapplied);
+ List<TaggedText> secTags = getReferenceTags(relatedTaxon.getSec(), relatedTaxon.getSecMicroReference(),
+ /* isMisapplied,*/ false);
if (!secTags.isEmpty()) {
- tags.add(TaggedText.NewSeparatorInstance(isMisapplied? SENSU_SEPARATOR : SEC_SEPARATOR));
- tags.addAll(secTags);
+ builder.addSeparator(isMisapplied? SENSU_SEPARATOR : SEC_SEPARATOR);
+ builder.addAll(secTags);
}else if (isBlank(relatedTaxon.getAppendedPhrase())) {
if (isMisapplied){
- tags.add(TaggedText.NewWhitespaceInstance());
+ builder.addWhitespace();
//TODO type unclear sensuReference(?)
- tags.add(TaggedText.NewInstance(TagEnum.authors, AUCT));
+ builder.add(TagEnum.appendedPhrase, AUCT);
}else{
- tags.add(TaggedText.NewSeparatorInstance(SEC_SEPARATOR + UNKNOWN_SEC));
+ builder.addSeparator(SEC_SEPARATOR + UNKNOWN_SEC);
}
}
// //, non author
if (isMisapplied && name != null){
- if (name.getCombinationAuthorship() != null){
- tags.add(TaggedText.NewSeparatorInstance(NON_SEPARATOR));
- //TODO add nom. ref. author tags
- }else if (isNotBlank(name.getAuthorshipCache())){
- tags.add(TaggedText.NewSeparatorInstance(NON_SEPARATOR));
- tags.add(TaggedText.NewInstance(TagEnum.authors, name.getAuthorshipCache().trim()));
+ if (isNotBlank(name.getAuthorshipCache())){
+ builder.addSeparator(NON_SEPARATOR);
+ builder.add(TagEnum.authors, name.getAuthorshipCache().trim());
+ }
+ }
+
+ //p.p.
+ if (isMisapplied) {
+ if (isProParteMAN(type, inverse)) {
+ builder.addSeparator(PRO_PARTE_SEPARATOR);
+ symbol = "p.p.";
+ builder.add(TagEnum.symbol, symbol);
+ } else if (isPartialMAN(type, inverse)) {
+ builder.addSeparator(PRO_PARTE_SEPARATOR);
+ symbol = "part.";
+ builder.add(TagEnum.symbol, symbol);
}
}
- //TODO tagEnum for relSec?
- List<TaggedText> relSecTags = getSensuTags /*getCitationTags*/(taxonRelationship.getCitation(),
- taxonRelationship.getCitationMicroReference(), false);
+ //rel sec
+ List<TaggedText> relSecTags = getReferenceTags(taxonRelationship.getCitation(),
+ taxonRelationship.getCitationMicroReference(),true);
if (!relSecTags.isEmpty()){
- TaggedText relSecSeparatorToag = TaggedText.NewSeparatorInstance(isSynonym ? SYN_SEC : isMisapplied ? ERR_SEC : REL_SEC);
- tags.add(relSecSeparatorToag);
- tags.addAll(relSecTags);
+ builder.addSeparator(isSynonym ? SYN_SEC : isMisapplied ? ERR_SEC : REL_SEC);
+ builder.addAll(relSecTags);
}
- return tags;
+ return builder.getTaggedText();
}
- private List<TaggedText> getSensuTags(Reference ref, String detail, boolean isSensu) {
+ private List<TaggedText> getReferenceTags(Reference ref, String detail, /*boolean isSensu,*/ boolean isRelation) {
List<TaggedText> result = new ArrayList<>();
String secRef;
if (ref != null){
- TeamOrPersonBase<?> author = ref.getAuthorship();
+ TeamOrPersonBase<?> author = CdmBase.deproxy(ref.getAuthorship());
+
//TODO distinguish linked and unlinked usage,
// if reference is not linked short citation should only be used
// if both author and year exists, also initials should be added in this case
if (ref.isProtectedTitleCache() == false &&
author != null &&
isNotBlank(author.getTitleCache())){
- //TODO move to authorFormatter
- String familyNames = getFamilyNames(author);
- if (isNotBlank(familyNames)){
- secRef = familyNames;
+ if (author.isInstanceOf(Person.class)){
+ secRef = PersonDefaultCacheStrategy.INSTANCE().getFamilyTitle((Person)author);
}else{
- secRef = ref.getAuthorship().getTitleCache();
+ //#9624
+ secRef = TeamDefaultCacheStrategy.INSTANCE_ET_AL_2().getFamilyTitle((Team)author);
}
if (isNotBlank(ref.getYear())){
secRef += " " + ref.getYear();
}else{
secRef = ref.getTitleCache();
}
- TagEnum secType = isSensu? TagEnum.sensuReference : TagEnum.secReference;
+ TagEnum secType = /*isSensu? TagEnum.sensuReference : */ isRelation? TagEnum.relSecReference : TagEnum.secReference;
TaggedText refTag = TaggedText.NewInstance(secType, secRef);
- refTag.setEntityReference(new TypedEntityReference<>(CdmBase.deproxy(ref.getClass()), ref.getUuid(), secRef));
+ refTag.setEntityReference(new TypedEntityReference<>(CdmBase.deproxy(ref).getClass(), ref.getUuid()));
result.add(refTag);
}
if (isNotBlank(detail)){
result.add(TaggedText.NewSeparatorInstance(DETAIL_SEPARATOR));
- //TODO do we need a sensu micro reference??
- TagEnum detailType = isSensu? TagEnum.sensuMicroReference : TagEnum.secMicroReference;
+ TagEnum detailType = /*isSensu? TagEnum.sensuMicroReference : */ isRelation? TagEnum.relSecMicroReference :TagEnum.secMicroReference;
TaggedText microTag = TaggedText.NewInstance(detailType, detail);
result.add(microTag);
}
return result;
}
- /**
- * @param author
- * @return
- */
- private String getFamilyNames(TeamOrPersonBase<?> author) {
- if (author.isInstanceOf(Person.class)){
- Person person = CdmBase.deproxy(author, Person.class);
- return isNotBlank(person.getFamilyName())? person.getFamilyName() : null;
- }else{
- Team team = CdmBase.deproxy(author, Team.class);
- String result = null;
- int n = team.getTeamMembers().size();
- int index = 0;
- if (team.isHasMoreMembers()){
- n++;
- }
- for (Person member : team.getTeamMembers()){
- String name = isNotBlank(member.getFamilyName())? member.getFamilyName(): member.getTitleCache();
- String separator = index < n ? ", " : " & ";
- result = CdmUtils.concat(separator, result, name);
- index++;
- }
- if (team.isHasMoreMembers()){
- //TODO or et al.???
- result += " & al.";
- }
- return result;
- }
- }
-
-
- /**
- * @param sec
- * @param secMicroReference
- * @return
- */
- private List<TaggedText> getCitationTags(Reference ref, String secMicroReference) {
- List<TaggedText> result = new ArrayList<>();
- String secRef;
-
- if (ref != null){
- //copied from TaxonBaseDefaultCacheStrategy
- if (ref.isProtectedTitleCache() == false &&
- ref.getCacheStrategy() != null &&
- ref.getAuthorship() != null &&
- isNotBlank(ref.getAuthorship().getTitleCache()) &&
- isNotBlank(ref.getYear())){
- secRef = ref.getCacheStrategy().getCitation(ref);
- }else{
- secRef = ref.getTitleCache();
- }
- //TODO do we need a sensuReference type?
- TaggedText refTag = TaggedText.NewInstance(TagEnum.secReference, secRef);
- refTag.setEntityReference(new TypedEntityReference<>(ref.getClass(), ref.getUuid(), secRef));
- result.add(refTag);
- }
- if (isNotBlank(secMicroReference)){
- result.add(TaggedText.NewSeparatorInstance(DETAIL_SEPARATOR));
- TaggedText microTag = TaggedText.NewInstance(TagEnum.secMicroReference, secMicroReference);
- result.add(microTag);
- }
- return result;
- }
-
-
- /**
- * @param name
- * @return
- */
private List<TaggedText> getNameCacheTags(TaxonName name) {
- List<TaggedText> result = name.getCacheStrategy().getTaggedName(name);
+ List<TaggedText> result = name.cacheStrategy().getTaggedName(name);
return result;
}
private List<TaggedText> getNameTitleCacheTags(TaxonName name) {
//TODO full title?
- List<TaggedText> result = name.getCacheStrategy().getTaggedTitle(name);
+ List<TaggedText> result = name.cacheStrategy().getTaggedFullTitle(name);
return result;
}
-
/**
* @param type the taxon relationship type
- * @param reverse is the relationship used reverse
+ * @param inverse is the relationship used inverse
* @param languages list of preferred languages
* @return the symbol for the taxon relationship
*/
- private String getSymbol(TaxonRelationshipType type, boolean reverse, List<Language> languages) {
+ private String getSymbol(TaxonRelationshipType type, boolean inverse, List<Language> languages) {
if (type == null){
return UNDEFINED_SYMBOL;
}
//symbol
- String symbol = reverse? type.getInverseSymbol():type.getSymbol();
+ String symbol = inverse? type.getInverseSymbol():type.getSymbol();
if (isNotBlank(symbol)){
+ //handle p.p. MAN specific #10082
+ if (isProParteMAN(type, inverse) || isPartialMAN(type, inverse)) {
+ return TaxonRelationshipType.MISAPPLIED_NAME_FOR().getInverseSymbol();
+ }
return symbol;
}
boolean isSymmetric = type.isSymmetric();
//symmetric inverted symbol
- String invertedSymbol = reverse? type.getSymbol() : type.getInverseSymbol();
+ String invertedSymbol = inverse? type.getSymbol() : type.getInverseSymbol();
if (isSymmetric && isNotBlank(invertedSymbol)){
return invertedSymbol;
}
//abbrev label
- Representation representation = reverse? type.getPreferredRepresentation(languages): type.getPreferredInverseRepresentation(languages);
+ Representation representation = inverse? type.getPreferredRepresentation(languages): type.getPreferredInverseRepresentation(languages);
String abbrevLabel = representation.getAbbreviatedLabel();
if (isNotBlank(abbrevLabel)){
return abbrevLabel;
}
//symmetric inverted abbrev label
- Representation invertedRepresentation = reverse? type.getPreferredInverseRepresentation(languages):type.getPreferredRepresentation(languages);
+ Representation invertedRepresentation = inverse? type.getPreferredInverseRepresentation(languages):type.getPreferredRepresentation(languages);
String invertedAbbrevLabel = invertedRepresentation.getAbbreviatedLabel();
if (isSymmetric && isNotBlank(invertedAbbrevLabel)){
return invertedAbbrevLabel;
return UNDEFINED_SYMBOL;
}
+ private boolean isPartialMAN(TaxonRelationshipType type, boolean inverse) {
+ return inverse && type.getUuid().equals(TaxonRelationshipType.uuidPartialMisappliedNameFor);
+ }
+
+ private boolean isProParteMAN(TaxonRelationshipType type, boolean inverse) {
+ return inverse && type.getUuid().equals(TaxonRelationshipType.uuidProParteMisappliedNameFor);
+ }
+
private boolean isNotBlank(String str) {
return StringUtils.isNotBlank(str);
}