| 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 | |
|---|
| 10 | package eu.etaxonomy.cdm.model.name; |
|---|
| 11 | |
|---|
| 12 | import java.util.ArrayList; |
|---|
| 13 | import java.util.Collections; |
|---|
| 14 | import java.util.HashSet; |
|---|
| 15 | import java.util.List; |
|---|
| 16 | import java.util.Set; |
|---|
| 17 | |
|---|
| 18 | import javax.persistence.Entity; |
|---|
| 19 | import javax.persistence.FetchType; |
|---|
| 20 | import javax.persistence.OneToMany; |
|---|
| 21 | import javax.persistence.Transient; |
|---|
| 22 | import javax.xml.bind.annotation.XmlAccessType; |
|---|
| 23 | import javax.xml.bind.annotation.XmlAccessorType; |
|---|
| 24 | import javax.xml.bind.annotation.XmlElement; |
|---|
| 25 | import javax.xml.bind.annotation.XmlElementWrapper; |
|---|
| 26 | import javax.xml.bind.annotation.XmlIDREF; |
|---|
| 27 | import javax.xml.bind.annotation.XmlSchemaType; |
|---|
| 28 | import javax.xml.bind.annotation.XmlType; |
|---|
| 29 | |
|---|
| 30 | import org.apache.log4j.Logger; |
|---|
| 31 | import org.hibernate.envers.Audited; |
|---|
| 32 | |
|---|
| 33 | import eu.etaxonomy.cdm.model.common.AnnotatableEntity; |
|---|
| 34 | import eu.etaxonomy.cdm.model.reference.Reference; |
|---|
| 35 | import eu.etaxonomy.cdm.model.taxon.Synonym; |
|---|
| 36 | import eu.etaxonomy.cdm.model.taxon.TaxonComparator; |
|---|
| 37 | |
|---|
| 38 | |
|---|
| 39 | /** |
|---|
| 40 | * The homotypical group class represents a set of {@link TaxonNameBase taxon names} associated |
|---|
| 41 | * on the base of their typifications. Since it can be asserted that two taxon |
|---|
| 42 | * names are typified by the same type without mentioning the type itself, even |
|---|
| 43 | * taxon names without explicit {@link TypeDesignationBase type designation} can belong |
|---|
| 44 | * to an homotypical group.<BR> |
|---|
| 45 | * Taxon names belonging to an homotypical group and the taxon names or |
|---|
| 46 | * {@link eu.etaxonomy.cdm.model.occurrence.DerivedUnitBase specimens} used as types for their |
|---|
| 47 | * {@link TypeDesignationBase type designations} have the following properties: <ul> |
|---|
| 48 | * <li> A taxon name belongs exactly to one homotypical group |
|---|
| 49 | * <li> A type specimen or a type name can be used as a type only for taxon |
|---|
| 50 | * names belonging to the same homotypical group<BR> |
|---|
| 51 | * - therefore an homotypical group circumscribes a set of types<BR> |
|---|
| 52 | * - each taxon name shares a subset of these types<BR> |
|---|
| 53 | * - each type is used by a subset of these taxon names |
|---|
| 54 | * within the homotypical group |
|---|
| 55 | * <li> Names that share at least one common type must belong to the same |
|---|
| 56 | * homotypical group |
|---|
| 57 | * <li> Names that share the same basionym or replaced synonym must belong to |
|---|
| 58 | * the same homotypical group |
|---|
| 59 | * </ul> |
|---|
| 60 | * |
|---|
| 61 | * @see TypeDesignationBase |
|---|
| 62 | * @see NameTypeDesignation |
|---|
| 63 | * @see SpecimenTypeDesignation |
|---|
| 64 | * @author m.doering |
|---|
| 65 | * @version 1.0 |
|---|
| 66 | * @created 08-Nov-2007 |
|---|
| 67 | */ |
|---|
| 68 | @XmlAccessorType(XmlAccessType.FIELD) |
|---|
| 69 | @XmlType(name = "HomotypicalGroup", propOrder = { |
|---|
| 70 | "typifiedNames" |
|---|
| 71 | }) |
|---|
| 72 | @Entity |
|---|
| 73 | @Audited |
|---|
| 74 | public class HomotypicalGroup extends AnnotatableEntity { |
|---|
| 75 | private static final Logger logger = Logger.getLogger(HomotypicalGroup.class); |
|---|
| 76 | |
|---|
| 77 | @XmlElementWrapper(name = "TypifiedNames") |
|---|
| 78 | @XmlElement(name = "TypifiedName") |
|---|
| 79 | @XmlIDREF |
|---|
| 80 | @XmlSchemaType(name = "IDREF") |
|---|
| 81 | @OneToMany(mappedBy="homotypicalGroup", fetch=FetchType.LAZY) |
|---|
| 82 | protected Set<TaxonNameBase> typifiedNames = new HashSet<TaxonNameBase>(); |
|---|
| 83 | |
|---|
| 84 | // ******************** static methods **************************************/ |
|---|
| 85 | /** |
|---|
| 86 | * Creates a new homotypical group instance with an empty set of typified |
|---|
| 87 | * {@link TaxonNameBase taxon names}. |
|---|
| 88 | * |
|---|
| 89 | * @see #HomotypicalGroup() |
|---|
| 90 | */ |
|---|
| 91 | public static HomotypicalGroup NewInstance(){ |
|---|
| 92 | return new HomotypicalGroup(); |
|---|
| 93 | } |
|---|
| 94 | |
|---|
| 95 | |
|---|
| 96 | //********************** CONSTRUCTOR ********************************************/ |
|---|
| 97 | |
|---|
| 98 | /** |
|---|
| 99 | * Class constructor: creates a new homotypical group instance with an |
|---|
| 100 | * empty set of typified {@link TaxonNameBase taxon names}. |
|---|
| 101 | */ |
|---|
| 102 | public HomotypicalGroup() { |
|---|
| 103 | super(); |
|---|
| 104 | } |
|---|
| 105 | |
|---|
| 106 | // ********************** GETTER/SETTER/ADDER/REMOVER ********************************/ |
|---|
| 107 | |
|---|
| 108 | /** |
|---|
| 109 | * Returns the set of {@link TaxonNameBase taxon names} that belong to <i>this</i> homotypical group. |
|---|
| 110 | * |
|---|
| 111 | * @see #getSpecimenTypeDesignations() |
|---|
| 112 | */ |
|---|
| 113 | public Set<TaxonNameBase> getTypifiedNames() { |
|---|
| 114 | return typifiedNames; |
|---|
| 115 | } |
|---|
| 116 | |
|---|
| 117 | /** |
|---|
| 118 | * Adds a new {@link TaxonNameBase taxon name} to the set of taxon names that belong |
|---|
| 119 | * to <i>this</i> homotypical group. |
|---|
| 120 | * |
|---|
| 121 | * @param typifiedName the taxon name to be added to <i>this</i> group |
|---|
| 122 | * @see #getTypifiedNames() |
|---|
| 123 | * @see #removeTypifiedName(TaxonNameBase) |
|---|
| 124 | */ |
|---|
| 125 | public void addTypifiedName(TaxonNameBase typifiedName) { |
|---|
| 126 | if (typifiedName != null){ |
|---|
| 127 | typifiedNames.add(typifiedName); |
|---|
| 128 | typifiedName.setHomotypicalGroup(this); |
|---|
| 129 | } |
|---|
| 130 | } |
|---|
| 131 | /** |
|---|
| 132 | * Removes one element from the set of {@link TaxonNameBase taxon names} |
|---|
| 133 | * that belong to <i>this</i> homotypical group. |
|---|
| 134 | * |
|---|
| 135 | * @param taxonBase the taxon name which should be removed from the corresponding set |
|---|
| 136 | * @see #addTypifiedName(TaxonNameBase) |
|---|
| 137 | */ |
|---|
| 138 | public void removeTypifiedName(TaxonNameBase typifiedName) { |
|---|
| 139 | HomotypicalGroup newHomotypicalGroup = HomotypicalGroup.NewInstance(); |
|---|
| 140 | typifiedName.setHomotypicalGroup(newHomotypicalGroup); |
|---|
| 141 | typifiedNames.remove(typifiedName); |
|---|
| 142 | } |
|---|
| 143 | |
|---|
| 144 | /** |
|---|
| 145 | * Merges the typified {@link TaxonNameBase taxon names} from one homotypical group into |
|---|
| 146 | * the set of typified taxon names of <i>this</i> homotypical group. |
|---|
| 147 | * |
|---|
| 148 | * @param homotypicalGroupToMerge the homotypical group the typified names of which |
|---|
| 149 | * are to be transferred to <i>this</i> homotypical group |
|---|
| 150 | */ |
|---|
| 151 | public void merge(HomotypicalGroup homotypicalGroupToMerge){ |
|---|
| 152 | if (homotypicalGroupToMerge != null){ |
|---|
| 153 | Set<TaxonNameBase> typifiedNames = new HashSet<TaxonNameBase>(); |
|---|
| 154 | typifiedNames.addAll(homotypicalGroupToMerge.getTypifiedNames()); |
|---|
| 155 | for (TaxonNameBase typifiedName: typifiedNames){ |
|---|
| 156 | this.addTypifiedName(typifiedName); |
|---|
| 157 | } |
|---|
| 158 | } |
|---|
| 159 | } |
|---|
| 160 | |
|---|
| 161 | |
|---|
| 162 | /** |
|---|
| 163 | * Returns the set of {@link SpecimenTypeDesignation specimen type designations} that |
|---|
| 164 | * typify the {@link TaxonNameBase taxon names} belonging to <i>this</i> homotypical group |
|---|
| 165 | * including the status of these designations. |
|---|
| 166 | * |
|---|
| 167 | * @see #getTypifiedNames() |
|---|
| 168 | * @see #getNameTypeDesignations() |
|---|
| 169 | * @see #getTypeDesignations() |
|---|
| 170 | * @see TaxonNameBase#getSpecimenTypeDesignations() |
|---|
| 171 | */ |
|---|
| 172 | @Transient |
|---|
| 173 | public Set<SpecimenTypeDesignation> getSpecimenTypeDesignations(){ |
|---|
| 174 | Set<SpecimenTypeDesignation> result = new HashSet<SpecimenTypeDesignation>(); |
|---|
| 175 | for (TaxonNameBase taxonName : typifiedNames){ |
|---|
| 176 | result.addAll(taxonName.getSpecimenTypeDesignations()); |
|---|
| 177 | } |
|---|
| 178 | return result; |
|---|
| 179 | } |
|---|
| 180 | |
|---|
| 181 | /** |
|---|
| 182 | * Returns the set of {@link NameTypeDesignation name type designations} that |
|---|
| 183 | * typify the {@link TaxonNameBase taxon names} belonging to <i>this</i> homotypical group |
|---|
| 184 | * including the status of these designations. |
|---|
| 185 | * |
|---|
| 186 | * @see #getTypifiedNames() |
|---|
| 187 | * @see #getSpecimenTypeDesignations() |
|---|
| 188 | * @see #getTypeDesignations() |
|---|
| 189 | * @see TaxonNameBase#getNameTypeDesignations() |
|---|
| 190 | */ |
|---|
| 191 | @Transient |
|---|
| 192 | public Set<NameTypeDesignation> getNameTypeDesignations(){ |
|---|
| 193 | Set<NameTypeDesignation> result = new HashSet<NameTypeDesignation>(); |
|---|
| 194 | for (TaxonNameBase taxonName : typifiedNames){ |
|---|
| 195 | result.addAll(taxonName.getNameTypeDesignations()); |
|---|
| 196 | } |
|---|
| 197 | return result; |
|---|
| 198 | } |
|---|
| 199 | |
|---|
| 200 | |
|---|
| 201 | /** |
|---|
| 202 | * Returns the set of all {@link TypeDesignationBase type designations} that |
|---|
| 203 | * typify the {@link TaxonNameBase taxon names} belonging to <i>this</i> homotypical group |
|---|
| 204 | * (this includes either {@link NameTypeDesignation name type designations} or |
|---|
| 205 | * {@link SpecimenTypeDesignation specimen type designations}). |
|---|
| 206 | * |
|---|
| 207 | * @see #getTypifiedNames() |
|---|
| 208 | * @see #getNameTypeDesignations() |
|---|
| 209 | * @see #getSpecimenTypeDesignations() |
|---|
| 210 | * @see TaxonNameBase#getTypeDesignations() |
|---|
| 211 | */ |
|---|
| 212 | @Transient |
|---|
| 213 | public Set<TypeDesignationBase> getTypeDesignations(){ |
|---|
| 214 | Set<TypeDesignationBase> result = new HashSet<TypeDesignationBase>(); |
|---|
| 215 | for (TaxonNameBase taxonName : typifiedNames){ |
|---|
| 216 | result.addAll(taxonName.getTypeDesignations()); |
|---|
| 217 | } |
|---|
| 218 | return result; |
|---|
| 219 | } |
|---|
| 220 | |
|---|
| 221 | // /** |
|---|
| 222 | // * Returns the set of {@link SpecimenTypeDesignation specimen type designations} that |
|---|
| 223 | // * typify <i>this</i> homotypical group including the status of these designations. |
|---|
| 224 | // * |
|---|
| 225 | // * @see #getTypifiedNames() |
|---|
| 226 | // */ |
|---|
| 227 | // @OneToMany |
|---|
| 228 | // @Cascade({CascadeType.SAVE_UPDATE}) |
|---|
| 229 | // public Set<SpecimenTypeDesignation> getSpecimenTypeDesignations() { |
|---|
| 230 | // return specimenTypeDesignations; |
|---|
| 231 | // } |
|---|
| 232 | // /** |
|---|
| 233 | // * @see #getSpecimenTypeDesignations() |
|---|
| 234 | // */ |
|---|
| 235 | // protected void setSpecimenTypeDesignations(Set<SpecimenTypeDesignation> specimenTypeDesignations) { |
|---|
| 236 | // this.specimenTypeDesignations = specimenTypeDesignations; |
|---|
| 237 | // } |
|---|
| 238 | // /** |
|---|
| 239 | // * Adds a new {@link SpecimenTypeDesignation specimen type designation} to the set |
|---|
| 240 | // * of specimen type designations assigned to <i>this</i> homotypical group and eventually |
|---|
| 241 | // * (with a boolean parameter) also to the corresponding set of each of the |
|---|
| 242 | // * {@link TaxonNameBase taxon names} belonging to <i>this</i> homotypical group. |
|---|
| 243 | // * |
|---|
| 244 | // * @param specimenTypeDesignation the specimen type designation to be added |
|---|
| 245 | // * @param addToAllNames the boolean flag indicating whether the addition will also |
|---|
| 246 | // * carried out for each taxon name |
|---|
| 247 | // * |
|---|
| 248 | // * @see TaxonNameBase#getSpecimenTypeDesignations() |
|---|
| 249 | // * @see SpecimenTypeDesignation |
|---|
| 250 | // */ |
|---|
| 251 | // public void addSpecimenTypeDesignation(SpecimenTypeDesignation specimenTypeDesignation, boolean addToAllNames) { |
|---|
| 252 | // if (specimenTypeDesignation != null){ |
|---|
| 253 | // specimenTypeDesignation.setHomotypicalGroup(this); |
|---|
| 254 | // specimenTypeDesignations.add(specimenTypeDesignation); |
|---|
| 255 | // } |
|---|
| 256 | // if (addToAllNames){ |
|---|
| 257 | // for (TaxonNameBase taxonNameBase : this.typifiedNames){ |
|---|
| 258 | // taxonNameBase.addSpecimenTypeDesignation(specimenTypeDesignation); |
|---|
| 259 | // } |
|---|
| 260 | // } |
|---|
| 261 | // } |
|---|
| 262 | // /** |
|---|
| 263 | // * Removes one element from the set of {@link SpecimenTypeDesignation specimen type designations} assigned to the |
|---|
| 264 | // * {@link HomotypicalGroup homotypical group} to which this {@link TaxonNameBase taxon name} belongs. |
|---|
| 265 | // * The same element will be removed from the corresponding set of each of |
|---|
| 266 | // * the taxon names belonging to <i>this</i> homotypical group. Furthermore the |
|---|
| 267 | // * homotypical group attribute of the specimen type designation will be |
|---|
| 268 | // * nullified. |
|---|
| 269 | // * |
|---|
| 270 | // * @param specimenTypeDesignation the specimen type designation which should be deleted |
|---|
| 271 | // * @see #getSpecimenTypeDesignations() |
|---|
| 272 | // * @see #addSpecimenTypeDesignation(SpecimenTypeDesignation, boolean) |
|---|
| 273 | // * @see TaxonNameBase#removeSpecimenTypeDesignation(SpecimenTypeDesignation) |
|---|
| 274 | // * @see SpecimenTypeDesignation#getHomotypicalGroup() |
|---|
| 275 | // */ |
|---|
| 276 | // public void removeSpecimenTypeDesignation(SpecimenTypeDesignation specimenTypeDesignation) { |
|---|
| 277 | // if (specimenTypeDesignation != null){ |
|---|
| 278 | // specimenTypeDesignation.setHomotypicalGroup(null); |
|---|
| 279 | // specimenTypeDesignations.remove(specimenTypeDesignation); |
|---|
| 280 | // } |
|---|
| 281 | // for (TaxonNameBase taxonNameBase : this.typifiedNames){ |
|---|
| 282 | // taxonNameBase.removeSpecimenTypeDesignation(specimenTypeDesignation); |
|---|
| 283 | // } |
|---|
| 284 | // } |
|---|
| 285 | |
|---|
| 286 | |
|---|
| 287 | // /** |
|---|
| 288 | // * Returns the set of {@link NameTypeDesignation name type designations} that |
|---|
| 289 | // * typify <i>this</i> homotypical group including the status of these designations. |
|---|
| 290 | // * |
|---|
| 291 | // * @see #getTypifiedNames() |
|---|
| 292 | // */ |
|---|
| 293 | // @OneToMany |
|---|
| 294 | // @Cascade({CascadeType.SAVE_UPDATE}) |
|---|
| 295 | // public Set<NameTypeDesignation> getNameTypeDesignations() { |
|---|
| 296 | // return nameTypeDesignations; |
|---|
| 297 | // } |
|---|
| 298 | // /** |
|---|
| 299 | // * @see #getNameTypeDesignations() |
|---|
| 300 | // */ |
|---|
| 301 | // protected void setNameTypeDesignations(Set<NameTypeDesignation> nameTypeDesignations) { |
|---|
| 302 | // this.nameTypeDesignations = nameTypeDesignations; |
|---|
| 303 | // } |
|---|
| 304 | // /** |
|---|
| 305 | // * Adds a new {@link NameTypeDesignation name type designation} to the set |
|---|
| 306 | // * of name type designations assigned to <i>this</i> homotypical group and eventually |
|---|
| 307 | // * (with a boolean parameter) also to the corresponding set of each of the |
|---|
| 308 | // * {@link TaxonNameBase taxon names} belonging to <i>this</i> homotypical group. |
|---|
| 309 | // * |
|---|
| 310 | // * @param nameTypeDesignation the name type designation to be added |
|---|
| 311 | // * @param addToAllNames the boolean flag indicating whether the addition will also |
|---|
| 312 | // * carried out for each taxon name |
|---|
| 313 | // * |
|---|
| 314 | // * @see TaxonNameBase#getNameTypeDesignations() |
|---|
| 315 | // * @see NameTypeDesignation |
|---|
| 316 | // */ |
|---|
| 317 | // public void addNameTypeDesignation(NameTypeDesignation nameTypeDesignation, boolean addToAllNames) { |
|---|
| 318 | // if (nameTypeDesignation != null){ |
|---|
| 319 | // nameTypeDesignation.setHomotypicalGroup(this); |
|---|
| 320 | // nameTypeDesignations.add(nameTypeDesignation); |
|---|
| 321 | // } |
|---|
| 322 | // if (addToAllNames){ |
|---|
| 323 | // for (TaxonNameBase taxonNameBase : this.typifiedNames){ |
|---|
| 324 | // taxonNameBase.addNameTypeDesignation(nameTypeDesignation); |
|---|
| 325 | // } |
|---|
| 326 | // } |
|---|
| 327 | // } |
|---|
| 328 | // /** |
|---|
| 329 | // * Removes one element from the set of {@link NameTypeDesignation name type designations} assigned to the |
|---|
| 330 | // * {@link HomotypicalGroup homotypical group} to which this {@link TaxonNameBase taxon name} belongs. |
|---|
| 331 | // * The same element will be removed from the corresponding set of each of |
|---|
| 332 | // * the taxon names belonging to <i>this</i> homotypical group. Furthermore the |
|---|
| 333 | // * homotypical group attribute of the name type designation will be |
|---|
| 334 | // * nullified. |
|---|
| 335 | // * |
|---|
| 336 | // * @param nameTypeDesignation the name type designation which should be deleted |
|---|
| 337 | // * @see #getNameTypeDesignations() |
|---|
| 338 | // * @see #addNameTypeDesignation(NameTypeDesignation, boolean) |
|---|
| 339 | // * @see TaxonNameBase#removeNameTypeDesignation(NameTypeDesignation) |
|---|
| 340 | // * @see NameTypeDesignation#getHomotypicalGroup() |
|---|
| 341 | // */ |
|---|
| 342 | // public void removeNameTypeDesignation(NameTypeDesignation nameTypeDesignation) { |
|---|
| 343 | // if (nameTypeDesignation != null){ |
|---|
| 344 | // nameTypeDesignation.setHomotypicalGroup(null); |
|---|
| 345 | // nameTypeDesignations.remove(nameTypeDesignation); |
|---|
| 346 | // } |
|---|
| 347 | // for (TaxonNameBase taxonNameBase : this.typifiedNames){ |
|---|
| 348 | // taxonNameBase.removeNameTypeDesignation(nameTypeDesignation); |
|---|
| 349 | // } |
|---|
| 350 | // } |
|---|
| 351 | |
|---|
| 352 | |
|---|
| 353 | /** |
|---|
| 354 | * Retrieves the ordered list (depending on the date of publication) of |
|---|
| 355 | * {@link taxon.Synonym synonyms} (according to a given reference) |
|---|
| 356 | * the {@link TaxonNameBase taxon names} of which belong to <i>this</i> homotypical group. |
|---|
| 357 | * If other names are part of <i>this</i> group that are not considered synonyms |
|---|
| 358 | * according to the respective reference, then they will not be included in |
|---|
| 359 | * the result set. |
|---|
| 360 | * |
|---|
| 361 | * @deprecated synonyms should not depend on the sec. Therefore this method will be removed in |
|---|
| 362 | * version 3.1 or higher. Use {@link Taxon#getSynonymsInGroup(HomotypicalGroup)} instead. But be |
|---|
| 363 | * aware that the semantics is slightly different. |
|---|
| 364 | * @param sec the reference whose treatment is to be considered |
|---|
| 365 | * @return the ordered list of synonyms |
|---|
| 366 | * @see TaxonNameBase#getSynonyms() |
|---|
| 367 | * @see TaxonNameBase#getTaxa() |
|---|
| 368 | * @see taxon.Synonym |
|---|
| 369 | */ |
|---|
| 370 | @Deprecated |
|---|
| 371 | public List<Synonym> getSynonymsInGroup(Reference sec){ |
|---|
| 372 | List<Synonym> result = new ArrayList<Synonym>(); |
|---|
| 373 | for (TaxonNameBase<?, ?>name : this.getTypifiedNames()){ |
|---|
| 374 | for (Synonym synonym : name.getSynonyms()){ |
|---|
| 375 | if ( (synonym.getSec() == null && sec == null) || |
|---|
| 376 | synonym.getSec() != null && synonym.getSec().equals(sec)){ |
|---|
| 377 | result.add(synonym); |
|---|
| 378 | } |
|---|
| 379 | } |
|---|
| 380 | } |
|---|
| 381 | Collections.sort(result, new TaxonComparator()); |
|---|
| 382 | return result; |
|---|
| 383 | } |
|---|
| 384 | |
|---|
| 385 | /** |
|---|
| 386 | * Creates a basionym relationship to all other names in this names homotypical |
|---|
| 387 | * group. |
|---|
| 388 | * |
|---|
| 389 | * @see HomotypicalGroup.setGroupBasionym(TaxonNameBase basionymName) |
|---|
| 390 | * |
|---|
| 391 | * @param basionymName |
|---|
| 392 | * @throws IllegalArgumentException if basionymName is not member in this homotypical group |
|---|
| 393 | */ |
|---|
| 394 | public void setGroupBasionym(TaxonNameBase basionymName) throws IllegalArgumentException{ |
|---|
| 395 | setGroupBasionym(basionymName, null, null, null); |
|---|
| 396 | } |
|---|
| 397 | |
|---|
| 398 | public void setGroupBasionym(TaxonNameBase basionymName, Reference citation, String microCitation, String ruleConsidered) |
|---|
| 399 | throws IllegalArgumentException { |
|---|
| 400 | if (! typifiedNames.contains(basionymName)){ |
|---|
| 401 | throw new IllegalArgumentException("Name to be set as basionym/original combination must be part of the homotypical group but is not"); |
|---|
| 402 | } |
|---|
| 403 | if (typifiedNames.size() < 2){return;} |
|---|
| 404 | // |
|---|
| 405 | //Add new relations |
|---|
| 406 | for (TaxonNameBase name : typifiedNames) { |
|---|
| 407 | if (!name.equals(basionymName)) { |
|---|
| 408 | name.addRelationshipFromName(basionymName, NameRelationshipType.BASIONYM(), citation, microCitation, ruleConsidered); |
|---|
| 409 | } |
|---|
| 410 | } |
|---|
| 411 | } |
|---|
| 412 | |
|---|
| 413 | /** |
|---|
| 414 | * Removes all basionym relationships between basionymName and any other name |
|---|
| 415 | * in its homotypic group |
|---|
| 416 | * |
|---|
| 417 | * @param basionymName |
|---|
| 418 | */ |
|---|
| 419 | public static void removeGroupBasionym(TaxonNameBase basionymName) { |
|---|
| 420 | HomotypicalGroup homotypicalGroup = basionymName.getHomotypicalGroup(); |
|---|
| 421 | Set<NameRelationship> relations = basionymName.getRelationsFromThisName(); |
|---|
| 422 | Set<NameRelationship> removeRelations = new HashSet<NameRelationship>(); |
|---|
| 423 | |
|---|
| 424 | for (NameRelationship relation : relations) { |
|---|
| 425 | |
|---|
| 426 | // If this is a basionym relation, and toName is in the homotypical group, |
|---|
| 427 | // remove the relationship. |
|---|
| 428 | if (relation.getType().isBasionymRelation() && |
|---|
| 429 | relation.getToName().getHomotypicalGroup().equals(homotypicalGroup)) { |
|---|
| 430 | removeRelations.add(relation); |
|---|
| 431 | } |
|---|
| 432 | } |
|---|
| 433 | |
|---|
| 434 | // Removing relations from a set through which we are iterating causes a |
|---|
| 435 | // ConcurrentModificationException. Therefore, we delete the targeted |
|---|
| 436 | // relations in a second step. |
|---|
| 437 | for (NameRelationship relation : removeRelations) { |
|---|
| 438 | basionymName.removeNameRelationship(relation); |
|---|
| 439 | } |
|---|
| 440 | } |
|---|
| 441 | |
|---|
| 442 | |
|---|
| 443 | /** |
|---|
| 444 | * Returns all taxon names in the homotypical group that do not have an 'is_basionym_for' (zool.: 'is_original_combination_for') |
|---|
| 445 | * or a replaced synonym relationship. |
|---|
| 446 | * @return |
|---|
| 447 | */ |
|---|
| 448 | @Transient |
|---|
| 449 | public Set<TaxonNameBase> getUnrelatedNames(){ |
|---|
| 450 | Set<NameRelationship> set = getBasionymOrReplacedSynonymRelations(true, true); |
|---|
| 451 | Set<TaxonNameBase> result = new HashSet<TaxonNameBase>(); |
|---|
| 452 | result.addAll(this.getTypifiedNames()); |
|---|
| 453 | for (NameRelationship nameRelationship : set){ |
|---|
| 454 | result.remove(nameRelationship.getFromName()); |
|---|
| 455 | result.remove(nameRelationship.getToName()); |
|---|
| 456 | } |
|---|
| 457 | return result; |
|---|
| 458 | } |
|---|
| 459 | |
|---|
| 460 | /** |
|---|
| 461 | * Returns all taxon names in the homotypical group that are new combinations (have a basionym/original combination |
|---|
| 462 | * or a replaced synonym). |
|---|
| 463 | * @return |
|---|
| 464 | */ |
|---|
| 465 | @Transient |
|---|
| 466 | public Set<TaxonNameBase> getNewCombinations(){ |
|---|
| 467 | Set<NameRelationship> set = getBasionymOrReplacedSynonymRelations(true, true); |
|---|
| 468 | Set<TaxonNameBase> result = new HashSet<TaxonNameBase>(); |
|---|
| 469 | for (NameRelationship nameRelationship : set){ |
|---|
| 470 | result.add(nameRelationship.getToName()); |
|---|
| 471 | } |
|---|
| 472 | return result; |
|---|
| 473 | } |
|---|
| 474 | |
|---|
| 475 | |
|---|
| 476 | |
|---|
| 477 | /** |
|---|
| 478 | * Returns all taxon names in the homotypical group that have an 'is_basionym_for' (zool.: 'is_original_combination_for') |
|---|
| 479 | * or a replaced synonym relationship. |
|---|
| 480 | * @return |
|---|
| 481 | */ |
|---|
| 482 | @Transient |
|---|
| 483 | public Set<TaxonNameBase> getBasionymsOrReplacedSynonyms(){ |
|---|
| 484 | Set<NameRelationship> set = getBasionymOrReplacedSynonymRelations(true, true); |
|---|
| 485 | Set<TaxonNameBase> result = new HashSet<TaxonNameBase>(); |
|---|
| 486 | for (NameRelationship nameRelationship : set){ |
|---|
| 487 | result.add(nameRelationship.getFromName()); |
|---|
| 488 | } |
|---|
| 489 | return result; |
|---|
| 490 | } |
|---|
| 491 | |
|---|
| 492 | /** |
|---|
| 493 | * Returns all taxon names in the homotypical group that have a 'is_basionym_for' (zool.: 'is_original_combination_for') relationship. |
|---|
| 494 | * @return |
|---|
| 495 | */ |
|---|
| 496 | @Transient |
|---|
| 497 | public Set<TaxonNameBase> getBasionyms(){ |
|---|
| 498 | Set<NameRelationship> set = getBasionymOrReplacedSynonymRelations(true, false); |
|---|
| 499 | Set<TaxonNameBase> result = new HashSet<TaxonNameBase>(); |
|---|
| 500 | for (NameRelationship nameRelationship : set){ |
|---|
| 501 | result.add(nameRelationship.getFromName()); |
|---|
| 502 | } |
|---|
| 503 | return result; |
|---|
| 504 | } |
|---|
| 505 | |
|---|
| 506 | /** |
|---|
| 507 | * Returns all taxon names in the homotypical group that have a 'is_replaced_synonym_for' relationship. |
|---|
| 508 | * @return |
|---|
| 509 | */ |
|---|
| 510 | @Transient |
|---|
| 511 | public Set<TaxonNameBase> getReplacedSynonym(){ |
|---|
| 512 | Set<NameRelationship> set = getBasionymOrReplacedSynonymRelations(false, true); |
|---|
| 513 | Set<TaxonNameBase> result = new HashSet<TaxonNameBase>(); |
|---|
| 514 | for (NameRelationship nameRelationship : set){ |
|---|
| 515 | result.add(nameRelationship.getFromName()); |
|---|
| 516 | } |
|---|
| 517 | return result; |
|---|
| 518 | } |
|---|
| 519 | |
|---|
| 520 | /** |
|---|
| 521 | * Returns the name relationships that represent either a basionym (original combination) relationship or |
|---|
| 522 | * a replaced synonym relationship. |
|---|
| 523 | * @return |
|---|
| 524 | */ |
|---|
| 525 | @Transient |
|---|
| 526 | public Set<NameRelationship> getBasionymAndReplacedSynonymRelations(){ |
|---|
| 527 | return getBasionymOrReplacedSynonymRelations(true, true); |
|---|
| 528 | } |
|---|
| 529 | |
|---|
| 530 | /** |
|---|
| 531 | * Computes all basionym and replaced synonym relationships between names in this group. |
|---|
| 532 | * If <code>doBasionym</code> is <code>false</code> basionym relationships are excluded. |
|---|
| 533 | * If <code>doReplacedSynonym</code> is <code>false</code> replaced synonym relationships are excluded. |
|---|
| 534 | * @param doBasionym |
|---|
| 535 | * @param doReplacedSynonym |
|---|
| 536 | * @return |
|---|
| 537 | */ |
|---|
| 538 | @Transient |
|---|
| 539 | private Set<NameRelationship> getBasionymOrReplacedSynonymRelations(boolean doBasionym, boolean doReplacedSynonym){ |
|---|
| 540 | Set<NameRelationship> result = new HashSet<NameRelationship>(); |
|---|
| 541 | Set<TaxonNameBase> names = this.getTypifiedNames(); |
|---|
| 542 | if (names.size() > 1){ |
|---|
| 543 | for (TaxonNameBase name : names){ |
|---|
| 544 | Set nameRels = name.getNameRelations(); |
|---|
| 545 | //TODO make getNameRelations generic |
|---|
| 546 | for (Object obj : nameRels){ |
|---|
| 547 | NameRelationship nameRel = (NameRelationship)obj; |
|---|
| 548 | NameRelationshipType type = nameRel.getType(); |
|---|
| 549 | if ( type.isBasionymRelation() && doBasionym){ |
|---|
| 550 | if (testRelatedNameInThisGroup(nameRel)){ |
|---|
| 551 | result.add(nameRel); |
|---|
| 552 | }else{ |
|---|
| 553 | logger.warn("Name has basionym relation to a name that is not in the same homotypical group"); |
|---|
| 554 | } |
|---|
| 555 | }else if (type.isReplacedSynonymRelation() && doReplacedSynonym) { |
|---|
| 556 | if (testRelatedNameInThisGroup(nameRel)){ |
|---|
| 557 | result.add(nameRel); |
|---|
| 558 | }else{ |
|---|
| 559 | logger.warn("Name has replaced synonym relation to a name that is not in the same homotypical group"); |
|---|
| 560 | } |
|---|
| 561 | } |
|---|
| 562 | } |
|---|
| 563 | } |
|---|
| 564 | } |
|---|
| 565 | return result; |
|---|
| 566 | } |
|---|
| 567 | |
|---|
| 568 | private boolean testRelatedNameInThisGroup(NameRelationship nameRel){ |
|---|
| 569 | TaxonNameBase toName = nameRel.getToName(); |
|---|
| 570 | return (this.getTypifiedNames().contains(toName)); |
|---|
| 571 | } |
|---|
| 572 | |
|---|
| 573 | private boolean isBasionymOrRepSynRel(NameRelationshipType relType){ |
|---|
| 574 | if (relType == null){ |
|---|
| 575 | throw new IllegalArgumentException("NameRelationshipType should never be null"); |
|---|
| 576 | }else if (relType.equals(NameRelationshipType.BASIONYM())) { |
|---|
| 577 | return true; |
|---|
| 578 | }else if (relType.equals(NameRelationshipType.REPLACED_SYNONYM())){ |
|---|
| 579 | return true; |
|---|
| 580 | }else{ |
|---|
| 581 | return false; |
|---|
| 582 | } |
|---|
| 583 | } |
|---|
| 584 | |
|---|
| 585 | |
|---|
| 586 | } |
|---|