2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
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.
10 package eu
.etaxonomy
.taxeditor
.model
;
12 import java
.util
.HashSet
;
13 import java
.util
.List
;
15 import java
.util
.SortedSet
;
17 import org
.apache
.log4j
.Logger
;
18 import org
.eclipse
.jface
.dialogs
.MessageDialog
;
19 import org
.springframework
.transaction
.TransactionStatus
;
21 import eu
.etaxonomy
.cdm
.api
.service
.IDescriptionService
;
22 import eu
.etaxonomy
.cdm
.api
.service
.INameService
;
23 import eu
.etaxonomy
.cdm
.api
.service
.IReferenceService
;
24 import eu
.etaxonomy
.cdm
.api
.service
.ITaxonService
;
25 import eu
.etaxonomy
.cdm
.model
.common
.OrderedTermVocabulary
;
26 import eu
.etaxonomy
.cdm
.model
.common
.TermVocabulary
;
27 import eu
.etaxonomy
.cdm
.model
.common
.TimePeriod
;
28 import eu
.etaxonomy
.cdm
.model
.description
.Feature
;
29 import eu
.etaxonomy
.cdm
.model
.name
.HomotypicalGroup
;
30 import eu
.etaxonomy
.cdm
.model
.name
.NameRelationship
;
31 import eu
.etaxonomy
.cdm
.model
.name
.NameRelationshipType
;
32 import eu
.etaxonomy
.cdm
.model
.name
.NomenclaturalCode
;
33 import eu
.etaxonomy
.cdm
.model
.name
.NomenclaturalStatusType
;
34 import eu
.etaxonomy
.cdm
.model
.name
.NonViralName
;
35 import eu
.etaxonomy
.cdm
.model
.name
.Rank
;
36 import eu
.etaxonomy
.cdm
.model
.name
.TaxonNameBase
;
37 import eu
.etaxonomy
.cdm
.model
.reference
.ReferenceBase
;
38 import eu
.etaxonomy
.cdm
.model
.taxon
.Synonym
;
39 import eu
.etaxonomy
.cdm
.model
.taxon
.SynonymRelationshipType
;
40 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
41 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonBase
;
42 import eu
.etaxonomy
.cdm
.strategy
.parser
.INonViralNameParser
;
43 import eu
.etaxonomy
.cdm
.strategy
.parser
.NonViralNameParserImpl
;
44 import eu
.etaxonomy
.taxeditor
.TaxEditorPlugin
;
45 import eu
.etaxonomy
.taxeditor
.UiUtil
;
46 import eu
.etaxonomy
.taxeditor
.preference
.PreferencesUtil
;
53 public class CdmUtil
{
54 private static final Logger logger
= Logger
.getLogger(CdmUtil
.class);
56 private static INonViralNameParser nonViralNameParser
;
57 private static TermVocabulary
<Feature
> features
;
58 private static SortedSet
<Rank
> ranks
;
59 private static TermVocabulary
<NomenclaturalStatusType
> statii
;
62 * Clears all objects retrieved from <code>cdmlib</code>
63 * to force them to re-initialize the next time they
66 public static void clearLibraryObjects() {
69 nonViralNameParser
= null;
71 TaxEditorPlugin
.getDefault().setNomStatusVocabulary(null);
75 * Checks whether synonym's name is the basionym for ALL names
82 public static boolean isSynonymGroupBasionym(Synonym synonym
) {
84 TaxonNameBase synonymName
= synonym
.getName();
85 return isNameGroupBasionym(synonymName
);
89 * Checks whether name is the basionym for ALL names
95 public static boolean isNameGroupBasionym(TaxonNameBase name
) {
100 HomotypicalGroup homotypicalGroup
= name
.getHomotypicalGroup();
101 if (homotypicalGroup
== null) {
105 Set
<TaxonNameBase
> typifiedNames
= homotypicalGroup
.getTypifiedNames();
107 // Check whether there are any other names in the group
108 if (typifiedNames
.size() == 1) {
112 boolean isBasionymToAll
= true;
114 for (TaxonNameBase taxonName
: typifiedNames
) {
115 if (!taxonName
.equals(name
)) {
116 if (!isNameBasionymOf(name
, taxonName
)) {
125 * Checks whether a basionym relationship exists between fromName and toName.
131 public static boolean isNameBasionymOf(TaxonNameBase fromName
, TaxonNameBase toName
) {
132 Set
<NameRelationship
> relations
= toName
.getRelationsToThisName();
133 for (NameRelationship relation
: relations
) {
134 if (relation
.getType().equals(NameRelationshipType
.BASIONYM()) &&
135 relation
.getFromName().equals(fromName
)) {
143 * Creates a basionym relationship between basionymName and
144 * each name in its homotypic group.
146 * @param basionymName
148 public static void setGroupBasionym(TaxonNameBase basionymName
) {
149 HomotypicalGroup homotypicalGroup
= basionymName
.getHomotypicalGroup();
150 if (homotypicalGroup
== null) {
153 for (TaxonNameBase name
: homotypicalGroup
.getTypifiedNames()) {
154 if (!name
.equals(basionymName
)) {
156 // First check whether the relationship already exists
157 if (!isNameBasionymOf(basionymName
, name
)) {
160 name
.addRelationshipFromName(basionymName
,
161 NameRelationshipType
.BASIONYM(), null);
168 * Removes all basionym relationships between basionymName and
169 * the names in its homotypic group.
171 * @param basionymName
173 public static void removeGroupBasionym(TaxonNameBase basionymName
) {
174 HomotypicalGroup homotypicalGroup
= basionymName
.getHomotypicalGroup();
175 Set
<NameRelationship
> relations
= basionymName
.getRelationsFromThisName();
176 Set
<NameRelationship
> removeRelations
= new HashSet
<NameRelationship
>();
178 for (NameRelationship relation
: relations
) {
180 // If this is a basionym relation, and toName is in the homotypical group,
181 // remove the relationship.
182 if (relation
.getType().equals(NameRelationshipType
.BASIONYM()) &&
183 relation
.getToName().getHomotypicalGroup().equals(homotypicalGroup
)) {
184 removeRelations
.add(relation
);
188 // Removing relations from a set through which we are iterating causes a
189 // ConcurrentModificationException. Therefore, we delete the targeted
190 // relations in a second step.
191 for (NameRelationship relation
: removeRelations
) {
192 basionymName
.removeNameRelationship(relation
);
197 * Checks whether name belongs to the same homotypic group as taxon's name.
203 public static boolean isNameHomotypic(TaxonNameBase name
, Taxon taxon
) {
204 TaxonNameBase taxonName
= taxon
.getName();
205 if (taxonName
== null || name
== null) {
208 HomotypicalGroup homotypicGroup
= taxonName
.getHomotypicalGroup();
209 if (homotypicGroup
== null) {
212 if (homotypicGroup
.equals(name
.getHomotypicalGroup())) {
219 * Returns whatever is currently considered the display name for Taxon
220 * objects. Currently titleCache.
225 public static String
getDisplayName(TaxonBase taxonBase
) {
226 TaxonNameBase name
= taxonBase
.getName();
227 return getDisplayName(name
);
234 public static String
getDisplayName(TaxonNameBase name
) {
236 return name
.getTitleCache();
241 public static String
getDisplayNameAndRef(TaxonBase taxonBase
) {
242 TaxonNameBase name
= taxonBase
.getName();
244 return name
.getFullTitleCache();
252 private static INonViralNameParser
getNonViralNameParser() {
253 if (nonViralNameParser
== null) {
254 nonViralNameParser
= NonViralNameParserImpl
.NewInstance();
256 return nonViralNameParser
;
260 * Takes a raw string, returns a brand spanking new name object.
262 * If no nomenclatural code is specified, the code specified in user preferences
263 * is used, i.e. if the preferred code is ICBN, a <code>BotanicalName</code> is returned;
264 * if it's ICZN, a <code>ZoologicalName</code> is returned.
267 * @param fullReference
272 public static TaxonNameBase
parseFullReference(String fullReference
,
273 NomenclaturalCode nomCode
, Rank rank
) {
275 if (nomCode
== null) {
276 nomCode
= PreferencesUtil
.getPreferredNomenclaturalCode();
279 TaxonNameBase name
= getNonViralNameParser().parseReferencedName(fullReference
,
282 if (name
.hasProblem()) {
283 name
.setFullTitleCache(fullReference
);
290 * Takes an existing name object and a string, returns the same name
291 * object with the fields parsed from the string.
293 * @param nameToBeFilled
294 * @param fullReference
298 public static void parseFullReference(NonViralName nameToBeFilled
, String fullReference
) {
301 boolean makeEmpty
= true;
303 // If the name already has a rank, make sure it is passed to the parser
304 if (nameToBeFilled
.getRank() != null) {
305 rank
= nameToBeFilled
.getRank();
308 // Call get status to get status list into the transaction
309 // for (NomenclaturalStatusType status : nameToBeFilled.getStatus()) {
312 // TaxEditorPlugin.getDefault().getCdmApp().getTermService().saveTerm(termBase)
313 // NomenclaturalStatusType term = NomenclaturalStatusType.INVALID();
314 //// .getRepresentation(Language.DEFAULT());
315 // TaxEditorPlugin.getDefaulty().getCdmApp().getTermService().saveTerm(term);
316 // logger.warn(term.getRepresentation(Language.DEFAULT()));
318 getNonViralNameParser().parseReferencedName(nameToBeFilled
, fullReference
, rank
, makeEmpty
);
320 if (nameToBeFilled
.hasProblem()) {
321 nameToBeFilled
.setFullTitleCache(fullReference
);
326 * @param nameToBeFilled
327 * @param fullNameString
331 public static void parseFullName(NonViralName nameToBeFilled
,
332 String fullNameString
, Rank rank
, boolean makeEmpty
) {
333 getNonViralNameParser().parseFullName(nameToBeFilled
, fullNameString
,
342 public static ReferenceBase
getSessionDefaultSec() {
344 return TaxEditorPlugin
.getDefault().getSessionDefaultSec();
349 * @param newAcceptedTaxon
352 * @param citationMicroReference
354 public static void makeTaxonSynonym(Taxon oldTaxon
, Taxon newAcceptedTaxon
,
355 SynonymRelationshipType synonymType
, ReferenceBase citation
,
356 String citationMicroReference
) {
357 ITaxonService taxonService
= getTaxonService();
358 taxonService
.makeTaxonSynonym(oldTaxon
, newAcceptedTaxon
, synonymType
,
359 citation
, citationMicroReference
);
366 public static Set
<TaxonNameBase
> getNameByName(String searchText
) {
367 Set
<TaxonNameBase
> resultsSet
= new HashSet
<TaxonNameBase
>();
368 resultsSet
.addAll(getNameService()
369 .getNamesByName(searchText
.replace("*", "%")));
373 public static INameService
getNameService() {
374 return TaxEditorPlugin
.getDefault().getNameService();
377 public static ITaxonService
getTaxonService() {
378 return TaxEditorPlugin
.getDefault().getTaxonService();
381 public static IDescriptionService
getDescriptionService() {
382 return TaxEditorPlugin
.getDefault().getDescriptionService();
385 public static IReferenceService
getReferenceService() {
386 return TaxEditorPlugin
.getDefault().getReferenceService();
389 public static TermVocabulary
<Feature
> getFeatures() {
390 if (features
== null) {
391 features
= CdmUtil
.getDescriptionService().
392 getDefaultFeatureVocabulary();
397 public static SortedSet
<Rank
> getRanks() {
399 // TransactionStatus tx = startReadOnlyTransaction();
400 OrderedTermVocabulary
<Rank
> rankVocabulary
= TaxEditorPlugin
.getDefault().getRankVocabulary();
401 ranks
= rankVocabulary
.getOrderedTerms(null);
402 // commitTransaction(tx);
412 public static Set
<TaxonNameBase
> getNameByNameForTaxonContext(String searchText
, Taxon taxon
) {
413 Set
<TaxonNameBase
> resultsSet
= new HashSet
<TaxonNameBase
>();
414 resultsSet
.addAll(getNameService().getNamesByName
415 (searchText
.replace("*", "%"), taxon
));
419 public static TransactionStatus
startTransaction() {
420 return TaxEditorPlugin
.getDefault().getCdmApp().startTransaction();
423 public static TransactionStatus
startReadOnlyTransaction() {
424 return TaxEditorPlugin
.getDefault().getCdmApp().startTransaction(true);
427 public static void commitTransaction(TransactionStatus tx
) {
428 TaxEditorPlugin
.getDefault().getCdmApp().commitTransaction(tx
);
431 public static void getNomenclaturalReference(TaxonNameBase name
) {
432 // INomenclaturalReference nomenclaturalReference = (INomenclaturalReference) name.getNomenclaturalReference();
433 // if (nomenclaturalReference == null) {
436 // String microReference = name.getNomenclaturalMicroReference();
437 // return CdmUtils.Nz(nomenclaturalReference.getNomenclaturalCitation(microReference));
441 * Converts a <code>String</code> whose format is either a valid year
442 * or two valid years with the format "XXXX-XXXX" into a TimePeriod.
444 * @see #getValidYear(String yearStr)
447 * @throws NumberFormatException
449 public static TimePeriod
convertTimePeriod(String refYear
) throws NumberFormatException
{
451 if (refYear
== null || ("").equals(refYear
)){
455 TimePeriod datePublished
= TimePeriod
.NewInstance();
457 // In case format is "xxxx-xxxx"
458 String
[] years
= refYear
.split("-");
460 // Unlikely case of "xxxx-xxxx-xxxx..."
461 if (years
.length
> 2) {
462 throw new NumberFormatException();
466 datePublished
.setStartYear(getValidYear(years
[0]));
468 // Format is "xxxx-xxxx"
469 if (years
.length
== 2) {
470 datePublished
.setEndYear(getValidYear(years
[1]));
473 return datePublished
;
478 * Checks whether a <code>String</code> is a valid year between
479 * 1750 and 2030. Throws a <code>NumberFormatException</code> if not.
483 * @throws NumberFormatException
485 public static Integer
getValidYear(String yearStr
) throws NumberFormatException
{
487 Integer yearInt
= null;
489 // Try casting string - don't catch number format exception
491 yearInt
= new Integer(yearStr
);
492 } catch (ClassCastException e
) {
493 throw new NumberFormatException();
496 // Is year in valid range?
497 if (yearInt
< 1750 || yearInt
> 2030) {
498 throw new NumberFormatException();
505 * Searches for references by string. "%" is used as a wildcard.
510 public static List
getReferencesByTitle(String reference
) {
512 reference
= reference
.replace("*", "%");
513 List resultsList
= null;
515 resultsList
= getReferenceService().getReferencesByTitle(reference
);
516 } catch (RuntimeException e
) {
517 MessageDialog
.openError(UiUtil
.getShell(), "Search reference error",
518 "Reference search returned an error. This could be a Hibernate concurrency problem. " +
519 "Please try saving your work, then searching again.");
526 * Returns true if <code>taxon</code> belongs to the children, grandchildren,
527 * etc. of <code>checkTaxon</code>.
533 public static boolean isTaxonChildOfTaxon(Taxon taxon
, Taxon checkTaxon
) {
535 // Iterate through all checkTaxon's children
536 for (Taxon childTaxon
: checkTaxon
.getTaxonomicChildren()) {
538 if (childTaxon
.equals(taxon
)) {
542 // Compare taxon with childTaxon's children
543 if (isTaxonChildOfTaxon(taxon
, childTaxon
)) {