minor model change for NameTypeDesignations
[cdmlib.git] / cdmlib-model / src / main / java / eu / etaxonomy / cdm / model / name / NameRelationshipType.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
10 package eu.etaxonomy.cdm.model.name;
11
12
13 import java.util.HashMap;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.UUID;
17
18 import javax.persistence.Entity;
19 import javax.persistence.Transient;
20 import javax.xml.bind.annotation.XmlAccessType;
21 import javax.xml.bind.annotation.XmlAccessorType;
22 import javax.xml.bind.annotation.XmlType;
23
24 import org.apache.log4j.Logger;
25 import org.hibernate.envers.Audited;
26
27 import eu.etaxonomy.cdm.common.CdmUtils;
28 import eu.etaxonomy.cdm.model.common.DefinedTermBase;
29 import eu.etaxonomy.cdm.model.common.RelationshipTermBase;
30 import eu.etaxonomy.cdm.model.common.TermVocabulary;
31
32 /**
33 * The class representing the categories of {@link NameRelationship taxon name relationships} between
34 * two {@link TaxonNameBase taxon names}. These name relationship types are
35 * based on the concrete {@link NomenclaturalCode nomenclatural code} governing
36 * the taxon names involved in the name relationship or on decisions taken by
37 * the competent authorities; they do not depend on the use made of these
38 * taxon names in a particular reference or in a particular taxonomic treatment.
39 * Most relationships are to be understood as 'is .... of': for instance
40 * <i>Linum radiola</i> L. is a replaced synonym of <i>Radiola linoides</i> Roth or
41 * <i>Astragalus rhizanthus</i> Boiss. is a later homonym of
42 * <i>Astragalus rhizanthus</i> Royle.
43 * <P>
44 * A standard (ordered) list of name relationship type instances will be
45 * automatically created as the project starts. But this class allows to extend
46 * this standard list by creating new instances of additional name relationship
47 * types if needed.
48 * <P>
49 * This class corresponds partially to: <ul>
50 * <li> TaxonRelationshipTerm and NomenclaturalNoteTypeTerm according to the TDWG ontology
51 * <li> RelationshipType and NomenclaturalNoteType according to the TCS
52 * </ul>
53 *
54 * @author m.doering
55 * @version 1.0
56 * @created 08-Nov-2007 13:06:38
57 */
58 @XmlAccessorType(XmlAccessType.FIELD)
59 @XmlType(name = "NameRelationshipType")
60 @Entity
61 @Audited
62 public class NameRelationshipType extends RelationshipTermBase<NameRelationshipType> {
63 static Logger logger = Logger.getLogger(NameRelationshipType.class);
64
65 private static final UUID uuidOrthographicVariant = UUID.fromString("eeaea868-c4c1-497f-b9fe-52c9fc4aca53");
66 private static final UUID uuidMisspelling = UUID.fromString("c6f9afcb-8287-4a2b-a6f6-4da3a073d5de");
67 private static final UUID uuidEmendation = UUID.fromString("6e23ad45-3f2a-462b-ad87-d2389cd6e26c");
68 private static final UUID uuidLaterHomonym = UUID.fromString("80f06f65-58e0-4209-b811-cb40ad7220a6");
69 private static final UUID uuidTreatedAsLaterHomonym = UUID.fromString("2990a884-3302-4c8b-90b2-dfd31aaa2778");
70 private static final UUID uuidAlternativeName = UUID.fromString("049c6358-1094-4765-9fae-c9972a0e7780");
71 private static final UUID uuidBasionym = UUID.fromString("25792738-98de-4762-bac1-8c156faded4a");
72 private static final UUID uuidReplacedSynonym = UUID.fromString("71c67c38-d162-445b-b0c2-7aba56106696");
73 private static final UUID uuidConservedAgainst = UUID.fromString("e6439f95-bcac-4ebb-a8b5-69fa5ce79e6a");
74 private static final UUID uuidValidatedByName = UUID.fromString("a176c9ad-b4c2-4c57-addd-90373f8270eb");
75 private static final UUID uuidLaterValidatedByName = UUID.fromString("a25ee4c1-863a-4dab-9499-290bf9b89639");
76 private static final UUID uuidBlockingNameFor = UUID.fromString("1dab357f-2e12-4511-97a4-e5153589e6a6");
77
78 protected static Map<UUID, NameRelationshipType> termMap = null;
79
80 protected static NameRelationshipType findTermByUuid(UUID uuid){
81 if (termMap == null){
82 return null;
83 }
84 return (NameRelationshipType)termMap.get(uuid);
85 }
86
87
88 // ************* CONSTRUCTORS *************/
89 /**
90 * Class constructor: creates a new empty name relationship type instance.
91 *
92 * @see #NameRelationshipType(String, String, String, boolean, boolean)
93 */
94 public NameRelationshipType() {
95 }
96
97 /**
98 * Class constructor: creates an additional name relationship type
99 * instance with a description, a label, a label abbreviation and the flags
100 * indicating whether <i>this</i> new name relationship type is symmetric and/or
101 * transitive.
102 *
103 * @param term the string (in the default language) describing the
104 * new name relationship type to be created
105 * @param label the string identifying the new name relationship
106 * type to be created
107 * @param labelAbbrev the string identifying (in abbreviated form) the
108 * new name relationship type to be created
109 * @param symmetric the boolean indicating whether the new name
110 * relationship type to be created is symmetric
111 * @param transitive the boolean indicating whether the new name
112 * relationship type to be created is transitive
113 * @see #NameRelationshipType()
114 */
115 public NameRelationshipType(String term, String label, String labelAbbrev, boolean symmetric, boolean transitive) {
116 super(term, label, labelAbbrev, symmetric, transitive);
117 }
118
119
120 //********* METHODS **************************************/
121
122 // TODO this method should be moved to consistency proof classes
123 /**
124 * Returns the boolean value indicating whether the nomenclatural status
125 * type of the {@link eu.etaxonomy.cdm.model.common.RelationshipBase#getRelatedFrom() first taxon name}
126 * involved in a name relationship with <i>this</i> name relationship type should
127 * be "invalid" (true) or not (false). Returns false if <i>this</i> name
128 * relationship status type is null.
129 *
130 * @see #isLegitimateType()
131 * @see #isIllegitimateType()
132 * @see NomenclaturalStatusType#isInvalidType()
133 * @see eu.etaxonomy.cdm.model.common.RelationshipBase#getRelatedFrom()
134 */
135 @Transient
136 public boolean isInvalidType(){
137 if (this.equals(VALIDATED_BY_NAME()) ||
138 this.equals(LATER_VALIDATED_BY_NAME())
139 ){
140 return true;
141 }else{
142 return false;
143 }
144 }
145
146 // TODO this method should be moved to consistency proof classes
147 /**
148 * Returns the boolean value indicating whether the nomenclatural status
149 * type of the {@link eu.etaxonomy.cdm.model.common.RelationshipBase#getRelatedFrom() first taxon name}
150 * involved in a name relationship with <i>this</i> name relationship type should
151 * be "legitimate" (true) or not (false). Returns false if <i>this</i> name
152 * relationship status type is null.
153 *
154 * @see #isInvalidType()
155 * @see #isIllegitimateType()
156 * @see NomenclaturalStatusType#isLegitimateType()
157 * @see eu.etaxonomy.cdm.model.common.RelationshipBase#getRelatedFrom()
158 */
159 @Transient
160 public boolean isLegitimateType(){
161 if (this.equals(BASIONYM()) ||
162 this.equals(REPLACED_SYNONYM()) ||
163 this.equals(ALTERNATIVE_NAME()) ||
164 this.equals(CONSERVED_AGAINST())
165 ){
166 return true;
167 }else{
168 return false;
169 }
170 }
171
172 // TODO this method should be moved to consistency proof classes
173 /**
174 * Returns the boolean value indicating whether the nomenclatural status
175 * type of the {@link eu.etaxonomy.cdm.model.common.RelationshipBase#getRelatedFrom() first taxon name}
176 * involved in a name relationship with <i>this</i> name relationship type should
177 * be "illegitimate" (true) or not (false). Returns false if <i>this</i> name
178 * relationship status type is null.
179 *
180 * @see #isInvalidType()
181 * @see #isLegitimateType()
182 * @see NomenclaturalStatusType#isIllegitimateType()
183 * @see eu.etaxonomy.cdm.model.common.RelationshipBase#getRelatedFrom()
184 */
185 @Transient
186 public boolean isIllegitimateType(){
187 //TODO: implement isX method. Maybe as persistent class attribute?
188 //TODO: RejectedInFavour,
189 if (this.equals(LATER_HOMONYM()) ||
190 this.equals(TREATED_AS_LATER_HOMONYM())
191 ){
192 return true;
193 }else{
194 return false;
195 }
196 }
197
198 @Transient
199 public boolean isBasionymRelation(){
200 if (BASIONYM() == null){
201 throw new IllegalStateException("NameRelationships have not been initialized yet. Please initialize DefinedTerms first");
202 }
203 return this.equals(BASIONYM());
204 }
205
206 @Transient
207 public boolean isReplacedSynonymRelation(){
208 if (REPLACED_SYNONYM() == null){
209 throw new IllegalStateException("NameRelationships have not been initialized yet. Please initialize DefinedTerms first");
210 }
211 return this.equals(REPLACED_SYNONYM());
212 }
213
214
215 /**
216 * Returns the "orthographic variant" name relationship type. The first
217 * {@link TaxonNameBase taxon name} involved in such a relationship is an
218 * orthographic variant of the second taxon name. The two {@link TaxonNameBase taxon names}
219 * involved in such a relationship must have the same {@link NonViralName#getAuthorshipCache() authorship}
220 * and {@link Rank rank}, belong to the same {@link HomotypicalGroup homotypical group} and their name parts
221 * must be almost identical (so one usually does not differentiate them).<BR>
222 * For instance <i>Angelica silvestris</i> L. is an orthographic variant of
223 * <i>Angelica sylvestris</i> L.<BR>
224 * This type is symmetric and transitive but usually orthographic variant relationships should be organized
225 * in a star schema with the correct variant in the middle and other variants pointing to it.
226 */
227 public static final NameRelationshipType ORTHOGRAPHIC_VARIANT(){
228 return findTermByUuid(uuidOrthographicVariant);
229 }
230 /**
231 * Returns the "misspelling" name relationship type. The first
232 * {@link TaxonNameBase taxon name} involved in such a relationship is a
233 * misspelling of the second taxon name. The two {@link TaxonNameBase taxon names}
234 * involved in such a relationship must have the same {@link NonViralName#getAuthorshipCache() authorship}
235 * and {@link Rank rank}, belong to the same {@link HomotypicalGroup homotypical group} and their name parts
236 * must be almost identical (so one usually does not differentiate them).<BR>
237 * For instance <i>Anhelica silvestris</i> L. is a misspelling of
238 * <i>Angelica silvestris</i> L.<BR>
239 * A misspelling is always accicentally (not on purpose). Therefore misspellings are a
240 * subset of {@link #ORTHOGRAPHIC_VARIANT orthographic variants} and are complementary to
241 * emendations. A misspelling is always an {@link #ORTHOGRAPHIC_VARIANT orthographic variant}, too.
242 * This type is symmetric and transitive but usually the misspelling relationships should be organized
243 * in a star schema with the correct variant in the middle and the misspellings pointing to it.
244 */
245 public static final NameRelationshipType MISSPELLING(){
246 return findTermByUuid(uuidMisspelling);
247 }
248 /**
249 * Returns the "emendation" name relationship type. The first
250 * {@link TaxonNameBase taxon name} involved in such a relationship is a
251 * misspelling of the second taxon name. The two {@link TaxonNameBase taxon names}
252 * involved in such a relationship must have the same {@link NonViralName#getAuthorshipCache() authorship}
253 * and {@link Rank rank}, belong to the same {@link HomotypicalGroup homotypical group} and their name parts
254 * must be almost identical (so one usually does not differentiate them).<BR>
255 * For instance <i>Angelica silvestris</i> L. is a emendation of
256 * <i>Angelica sylvestris</i> L.<BR>
257 * The name corrected by an emendation has originally been used on purpose (not accidentially)
258 * Therefore emendations are a subset of {@link #ORTHOGRAPHIC_VARIANT orthographic variants} and are
259 * complementary to {@link #MISSPELLING missepllings}. An emendation is always an
260 * {@link #ORTHOGRAPHIC_VARIANT orthographic variant}, too.<BR>
261 * This type is symmetric and transitive but usually the misspelling relationships should be organized
262 * in a star schema with the correct variant in the middle and the misspellings pointing to it.
263 */
264 public static final NameRelationshipType EMENDATION(){
265 return findTermByUuid(uuidEmendation);
266 }
267 /**
268 * Returns the "later homonym" name relationship type. The first
269 * {@link TaxonNameBase taxon name} involved in such a relationship should
270 * have been published after the second taxon name. The two {@link TaxonNameBase taxon names}
271 * involved in such a relationship must belong to different
272 * {@link HomotypicalGroup homotypical groups}, have in general different
273 * {@link NonViralName#getAuthorshipCache() authorship} and their name parts (excluding infraspecific
274 * {@link Rank ranks}) must be (almost) identical, so one could be mistaken for
275 * the other one. The first taxon name is "illegitimate" and the second one
276 * is "legitimate" (this corresponds to "invalid" and "valid" in case of
277 * {@link ZoologicalName zoological names}).<BR>
278 * For instance <i>Astragalus rhizanthus</i> Boiss. is a later homonym of
279 * <i>Astragalus rhizanthus</i> Royle.<BR>
280 * This type is not symmetric but transitive.
281 *
282 * @see NomenclaturalStatusType#isIllegitimateType()
283 * @see NomenclaturalStatusType#isLegitimateType()
284 */
285 public static final NameRelationshipType LATER_HOMONYM(){
286 return findTermByUuid(uuidLaterHomonym);
287 }
288 /**
289 * Returns the "treated as later homonym" name relationship type. The first
290 * {@link TaxonNameBase taxon name} involved in such a relationship is
291 * treated as an homonym although it has been published before the second
292 * taxon name. The two taxon names involved must belong to different
293 * {@link HomotypicalGroup homotypical groups} and their name parts (excluding
294 * {@link Rank#isInfraSpecific() infraspecific ranks} and {@link NonViralName#getAuthorshipCache() authorship}) must be
295 * almost identical (so one could be mistaken for the other). The first
296 * taxon name is "illegitimate" and the second one is "legitimate" (this
297 * corresponds to "invalid" and "valid" in case of {@link ZoologicalName zoological names}).<BR>
298 * This type is not symmetric but transitive.
299 *
300 * @see #LATER_HOMONYM()
301 * @see NomenclaturalStatusType#isIllegitimateType()
302 * @see NomenclaturalStatusType#isLegitimateType()
303 */
304 public static final NameRelationshipType TREATED_AS_LATER_HOMONYM(){
305 return findTermByUuid(uuidTreatedAsLaterHomonym);
306 }
307 /**
308 * Returns the "alternative name" name relationship type. Both {@link TaxonNameBase taxon names}
309 * involved in such a relationship are family names. The first one is a
310 * classical name long in use, in some cases, even before 1753 and is considered as
311 * {@link NomenclaturalStatusType#VALID() valid} and also {@link NomenclaturalStatusType#isLegitimateType() legitimate}
312 * although it does not follow the rules for family names (see Article 18 of
313 * the ICBN). An alternative name is typified by the type of the name
314 * it is alternative to (so both must belong to the same
315 * {@link HomotypicalGroup homotypical group}).<BR>
316 * For instance <i>Cruciferae</i> Adans is an alternative name to
317 * <i>Brassicaceae</i> Lindl.<BR>
318 * This type is neither symmetric nor transitive.
319 */
320 public static final NameRelationshipType ALTERNATIVE_NAME(){
321 return findTermByUuid(uuidAlternativeName);
322 }
323 /**
324 * Returns the "basionym" name relationship type. The first {@link TaxonNameBase taxon name}
325 * involved in such a relationship is the "basionym" of the second taxon
326 * name. Both taxon names belong to the same {@link HomotypicalGroup homotypical group}).
327 * The basionym is the epithet-bringing taxon name (first taxon name
328 * ever validly published given to the same {@link Rank#isInfraGeneric() infrageneric}
329 * taxon, the epithet of which is the same as in the second taxon name
330 * originated through a reclassification).<BR>
331 * According to the ICBN the author of the basionym must be mentioned in the
332 * later taxon name (by placing it in parentheses before the authority of
333 * the new combination). For instance <i>Pinus abies</i> L. is the basionym of
334 * <i>Picea abies</i> (L.) H. Karst.<BR>
335 * This type is neither symmetric nor transitive.
336 */
337 public static final NameRelationshipType BASIONYM(){
338 return findTermByUuid(uuidBasionym);
339 }
340 /**
341 * Returns the "replaced synonym" name relationship type. The first
342 * {@link TaxonNameBase taxon name} involved in such a relationship is the
343 * "replaced synonym" of the second taxon name. Both taxon names belong to
344 * the same {@link HomotypicalGroup homotypical group}. The replaced synonym is the
345 * first taxon name ever validly published given to the same
346 * {@link Rank#isInfraGeneric() infrageneric} taxon that is either itself a
347 * "later homonym" or the epithet of which could not be used in the new
348 * taxon name originated through a reclassification. A new epithet must be
349 * proposed if the use of the original epithet leads to an already existing
350 * taxon name (for another taxon) or in botany to autonyms (since the ICBN
351 * does not allow such names where epithet and genus name are the same).<BR>
352 * For instance <i>Spartium biflorum</i> Desf. is the replaced synonym of
353 * of <i>Cytisus fontanesii</i> Spach ("novum" taxon name) because at the time
354 * of reclassification a taxon name <i>Cytisus biflorum</i> had been already
355 * published by L'H�r.<BR>
356 * This type is neither symmetric nor transitive.
357 *
358 * @see #BASIONYM()
359 * @see #LATER_HOMONYM()
360 * @see NomenclaturalStatusType#NOVUM()
361 */
362 public static final NameRelationshipType REPLACED_SYNONYM(){
363 return findTermByUuid(uuidReplacedSynonym);
364 }
365 /**
366 * Returns the "conserved against" name relationship type. Both {@link TaxonNameBase taxon names}
367 * involved in such a relationship belong to the same {@link HomotypicalGroup homotypical group}.
368 * Competent authorities decided, regardless of the general
369 * nomenclatural rules, to handle the first one as the "legitimate"
370 * one and the second taxon name as "illegitimate" (this corresponds to
371 * "valid" and "invalid" in case of {@link ZoologicalName zoological names}).<BR>
372 * For instance <i>Cephaloziella</i> (Spruce) Schiffn. is conserved against
373 * <i>Dichiton</i> Mont.<BR>
374 * This type is neither symmetric nor transitive.
375 *
376 * @see NomenclaturalStatusType#CONSERVED()
377 * @see NomenclaturalStatusType#REJECTED()
378 * @see NomenclaturalStatusType#isLegitimateType()
379 * @see NomenclaturalStatusType#isIllegitimateType()
380 */
381 public static final NameRelationshipType CONSERVED_AGAINST(){
382 return findTermByUuid(uuidConservedAgainst);
383 }
384 /**
385 * Returns the "validated by name" name relationship type. The two
386 * {@link TaxonNameBase taxon names} involved in such a relationship were published
387 * in order to define the same taxonomical group but the first
388 * (earlier) taxon name was invalidly published whereas the second (later)
389 * taxon name is the one which was validly published for the first time.<BR>
390 * This type is neither symmetric nor transitive.
391 *
392 * @see NomenclaturalStatusType#isInvalidType()
393 * @see NomenclaturalStatusType#VALID()
394 */
395 public static final NameRelationshipType VALIDATED_BY_NAME(){
396 return findTermByUuid(uuidValidatedByName);
397 }
398 /**
399 * Returns the "later validated by name" name relationship type. The two
400 * {@link TaxonNameBase taxon names} involved in such a relationship were published
401 * in order to define the same taxonomical group but the first
402 * (earlier) taxon name was invalidly published whereas the second (later)
403 * taxon name is the one which was validly published for the first time.<BR>
404 * This type is neither symmetric nor transitive.
405 *
406 * @see NomenclaturalStatusType#isInvalidType()
407 * @see NomenclaturalStatusType#VALID()
408 */
409 public static final NameRelationshipType LATER_VALIDATED_BY_NAME(){
410 return findTermByUuid(uuidLaterValidatedByName);
411 }
412 /**
413 * Returns the "blocking name" name relationship type. The first
414 * {@link TaxonNameBase taxon name} involved in such a relationship is the
415 * "blocking name" for the second taxon name. Both taxon names belong to
416 * different {@link HomotypicalGroup homotypical groups}). The blocking taxon name is the
417 * {@link Rank#isInfraGeneric() infrageneric} taxon name, already published at the time of
418 * reclassification, which makes illegitim (because of homonymy) the use of
419 * the epithet in the second taxon name originated through a reclassification.
420 * Therefore a "replaced synonym" name relationship arises.<BR>
421 * For instance <i>Cytisus biflorum</i> L'H�r. is the blocking name for
422 * <i>Cytisus fontanesii</i> Spach ("novum" taxon name) when reclassifying
423 * <i>Spartium biflorum</i> Desf. from <i>Spartium</i> to <i>Cytisus</i>.<BR>
424 * This type is neither symmetric nor transitive.
425 *
426 * @see #REPLACED_SYNONYM()
427 * @see #LATER_HOMONYM()
428 * @see NomenclaturalStatusType#NOVUM()
429 */
430 public static final NameRelationshipType BLOCKING_NAME_FOR(){
431 return findTermByUuid(uuidBlockingNameFor);
432 }
433
434 @Override
435 protected void setDefaultTerms(TermVocabulary<NameRelationshipType> termVocabulary) {
436 termMap = new HashMap<UUID, NameRelationshipType>();
437 for (NameRelationshipType term : termVocabulary.getTerms()){
438 termMap.put(term.getUuid(), term);
439 }
440 }
441
442 @Override
443 public NameRelationshipType readCsvLine(Class<NameRelationshipType> termClass, List<String> csvLine, Map<UUID,DefinedTermBase> terms) {
444 NameRelationshipType result = super.readCsvLine(termClass, csvLine, terms);
445 String kindOfString = csvLine.get(8).trim();
446 if (CdmUtils.isNotEmpty(kindOfString)){
447 UUID uuidKindOf = UUID.fromString(kindOfString);
448 DefinedTermBase kindOf = terms.get(uuidKindOf);
449 result.setKindOf((NameRelationshipType)kindOf);
450 }
451 return result;
452 }
453 }