import javax.xml.bind.annotation.XmlType;
import org.apache.log4j.Logger;
-import org.hibernate.annotations.Cascade;
-import org.hibernate.annotations.CascadeType;
+import org.hibernate.envers.Audited;
import eu.etaxonomy.cdm.model.common.AnnotatableEntity;
import eu.etaxonomy.cdm.model.reference.ReferenceBase;
import eu.etaxonomy.cdm.model.taxon.Synonym;
import eu.etaxonomy.cdm.model.taxon.TaxonComparator;
-import eu.etaxonomy.cdm.strategy.cache.name.INameCacheStrategy;
/**
"typifiedNames"
})
@Entity
+@Audited
public class HomotypicalGroup extends AnnotatableEntity {
static Logger logger = Logger.getLogger(HomotypicalGroup.class);
@XmlElement(name = "TypifiedName")
@XmlIDREF
@XmlSchemaType(name = "IDREF")
+ @OneToMany(mappedBy="homotypicalGroup", fetch=FetchType.LAZY)
protected Set<TaxonNameBase> typifiedNames = new HashSet<TaxonNameBase>();
/**
*
* @see #getSpecimenTypeDesignations()
*/
- @OneToMany(mappedBy="homotypicalGroup", fetch=FetchType.LAZY)
public Set<TaxonNameBase> getTypifiedNames() {
return typifiedNames;
}
- /**
- * @see #getTypifiedNames()
- */
- protected void setTypifiedNames(Set<TaxonNameBase> typifiedNames) {
- this.typifiedNames = typifiedNames;
- }
/**
* Adds a new {@link TaxonNameBase taxon name} to the set of taxon names that belong
* @see TaxonNameBase#getTaxa()
* @see taxon.Synonym
*/
- @Transient
public List<Synonym> getSynonymsInGroup(ReferenceBase sec){
List<Synonym> result = new ArrayList();
- for (TaxonNameBase<TaxonNameBase, INameCacheStrategy> n:this.getTypifiedNames()){
- for (Synonym s:n.getSynonyms()){
- if ( (s.getSec() == null && sec == null) ||
- s.getSec().equals(sec)){
- result.add(s);
+ for (TaxonNameBase<?, ?>name : this.getTypifiedNames()){
+ for (Synonym synonym : name.getSynonyms()){
+ if ( (synonym.getSec() == null && sec == null) ||
+ synonym.getSec() != null && synonym.getSec().equals(sec)){
+ result.add(synonym);
}
}
}
Collections.sort(result, new TaxonComparator());
return result;
}
+
+
+ /**
+ * Creates a basionym relationship to all other names in this names homotypical
+ * group.
+ *
+ * @see HomotypicalGroup.setGroupBasionym(TaxonNameBase basionymName)
+ *
+ * @param basionymName
+ * @throws IllegalArgumentException if basionymName is not member in this homotypical group
+ */
+ public void setGroupBasionym(TaxonNameBase basionymName) throws IllegalArgumentException{
+ setGroupBasionym(basionymName, null, null, null);
+ }
+
+ public void setGroupBasionym(TaxonNameBase basionymName, ReferenceBase citation, String microCitation, String ruleConsidered)
+ throws IllegalArgumentException {
+ if (! typifiedNames.contains(basionymName)){
+ throw new IllegalArgumentException("Name to be set as basionym/original combination must be part of the homotypical group but is not");
+ }
+ if (typifiedNames.size() < 2){return;}
+//
+ //Add new relations
+ for (TaxonNameBase name : typifiedNames) {
+ if (!name.equals(basionymName)) {
+ name.addRelationshipFromName(basionymName, NameRelationshipType.BASIONYM(), citation, microCitation, ruleConsidered);
+ }
+ }
+ }
+
+ /**
+ * Removes all basionym relationships between basionymName and any other name
+ * in its homotypic group
+ *
+ * @param basionymName
+ */
+ public static void removeGroupBasionym(TaxonNameBase basionymName) {
+ HomotypicalGroup homotypicalGroup = basionymName.getHomotypicalGroup();
+ Set<NameRelationship> relations = basionymName.getRelationsFromThisName();
+ Set<NameRelationship> removeRelations = new HashSet<NameRelationship>();
+
+ for (NameRelationship relation : relations) {
+
+ // If this is a basionym relation, and toName is in the homotypical group,
+ // remove the relationship.
+ if (relation.getType().isBasionymRelation() &&
+ relation.getToName().getHomotypicalGroup().equals(homotypicalGroup)) {
+ removeRelations.add(relation);
+ }
+ }
+
+ // Removing relations from a set through which we are iterating causes a
+ // ConcurrentModificationException. Therefore, we delete the targeted
+ // relations in a second step.
+ for (NameRelationship relation : removeRelations) {
+ basionymName.removeNameRelationship(relation);
+ }
+ }
+
+
+ /**
+ * Returns all taxon names in the homotypical group that do not have an 'is_basionym_for' (zool.: 'is_original_combination_for')
+ * or a replaced synonym relationship.
+ * @return
+ */
+ @Transient
+ public Set<TaxonNameBase> getUnrelatedNames(){
+ Set<NameRelationship> set = getBasionymOrReplacedSynonymRelations(true, true);
+ Set<TaxonNameBase> result = new HashSet<TaxonNameBase>();
+ result.addAll(this.getTypifiedNames());
+ for (NameRelationship nameRelationship : set){
+ result.remove(nameRelationship.getFromName());
+ result.remove(nameRelationship.getToName());
+ }
+ return result;
+ }
+
+ /**
+ * Returns all taxon names in the homotypical group that are new combinations (have a basionym/original combination
+ * or a replaced synonym).
+ * @return
+ */
+ @Transient
+ public Set<TaxonNameBase> getNewCombinations(){
+ Set<NameRelationship> set = getBasionymOrReplacedSynonymRelations(true, true);
+ Set<TaxonNameBase> result = new HashSet<TaxonNameBase>();
+ for (NameRelationship nameRelationship : set){
+ result.add(nameRelationship.getToName());
+ }
+ return result;
+ }
+
+
+
+ /**
+ * Returns all taxon names in the homotypical group that have an 'is_basionym_for' (zool.: 'is_original_combination_for')
+ * or a replaced synonym relationship.
+ * @return
+ */
+ @Transient
+ public Set<TaxonNameBase> getBasionymsOrReplacedSynonyms(){
+ Set<NameRelationship> set = getBasionymOrReplacedSynonymRelations(true, true);
+ Set<TaxonNameBase> result = new HashSet<TaxonNameBase>();
+ for (NameRelationship nameRelationship : set){
+ result.add(nameRelationship.getFromName());
+ }
+ return result;
+ }
+
+ /**
+ * Returns all taxon names in the homotypical group that have a 'is_basionym_for' (zool.: 'is_original_combination_for') relationship.
+ * @return
+ */
+ @Transient
+ public Set<TaxonNameBase> getBasionyms(){
+ Set<NameRelationship> set = getBasionymOrReplacedSynonymRelations(true, false);
+ Set<TaxonNameBase> result = new HashSet<TaxonNameBase>();
+ for (NameRelationship nameRelationship : set){
+ result.add(nameRelationship.getFromName());
+ }
+ return result;
+ }
+
+ /**
+ * Returns all taxon names in the homotypical group that have a 'is_replaced_synonym_for' relationship.
+ * @return
+ */
+ @Transient
+ public Set<TaxonNameBase> getReplacedSynonym(){
+ Set<NameRelationship> set = getBasionymOrReplacedSynonymRelations(false, true);
+ Set<TaxonNameBase> result = new HashSet<TaxonNameBase>();
+ for (NameRelationship nameRelationship : set){
+ result.add(nameRelationship.getFromName());
+ }
+ return result;
+ }
+
+ /**
+ * Returns the name relationships that represent either a basionym (original combination) relationship or
+ * a replaced synonym relationship.
+ * @return
+ */
+ @Transient
+ public Set<NameRelationship> getBasionymAndReplacedSynonymRelations(){
+ return getBasionymOrReplacedSynonymRelations(true, true);
+ }
+
+ /**
+ * Computes all basionym and replaced synonym relationships between names in this group.
+ * If <code>doBasionym</code> is <code>false</code> basionym relationships are excluded.
+ * If <code>doReplacedSynonym</code> is <code>false</code> replaced synonym relationships are excluded.
+ * @param doBasionym
+ * @param doReplacedSynonym
+ * @return
+ */
+ @Transient
+ private Set<NameRelationship> getBasionymOrReplacedSynonymRelations(boolean doBasionym, boolean doReplacedSynonym){
+ Set<NameRelationship> result = new HashSet<NameRelationship>();
+ Set<TaxonNameBase> names = this.getTypifiedNames();
+ if (names.size() > 1){
+ for (TaxonNameBase name : names){
+ Set nameRels = name.getNameRelations();
+ //TODO make getNameRelations generic
+ for (Object obj : nameRels){
+ NameRelationship nameRel = (NameRelationship)obj;
+ NameRelationshipType type = nameRel.getType();
+ if ( type.isBasionymRelation() && doBasionym){
+ if (testRelatedNameInThisGroup(nameRel)){
+ result.add(nameRel);
+ }else{
+ logger.warn("Name has basionym relation to a name that is not in the same homotypical group");
+ }
+ }else if (type.isReplacedSynonymRelation() && doReplacedSynonym) {
+ if (testRelatedNameInThisGroup(nameRel)){
+ result.add(nameRel);
+ }else{
+ logger.warn("Name has replaced synonym relation to a name that is not in the same homotypical group");
+ }
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+ private boolean testRelatedNameInThisGroup(NameRelationship nameRel){
+ TaxonNameBase toName = nameRel.getToName();
+ return (this.getTypifiedNames().contains(toName));
+ }
+
+ private boolean isBasionymOrRepSynRel(NameRelationshipType relType){
+ if (relType == null){
+ throw new IllegalArgumentException("NameRelationshipType should never be null");
+ }else if (relType.equals(NameRelationshipType.BASIONYM())) {
+ return true;
+ }else if (relType.equals(NameRelationshipType.REPLACED_SYNONYM())){
+ return true;
+ }else{
+ return false;
+ }
+ }
}