Completed type module.
[taxeditor.git] / eclipseprojects / eu.etaxonomy.taxeditor / src / eu / etaxonomy / taxeditor / model / CdmUtil.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.taxeditor.model;
11
12 import java.util.ArrayList;
13 import java.util.HashSet;
14 import java.util.List;
15 import java.util.Set;
16
17 import org.apache.log4j.Logger;
18 import org.eclipse.jface.dialogs.MessageDialog;
19
20 import eu.etaxonomy.cdm.api.application.CdmApplicationController;
21 import eu.etaxonomy.cdm.api.service.INameService;
22 import eu.etaxonomy.cdm.api.service.IReferenceService;
23 import eu.etaxonomy.cdm.api.service.ITaxonService;
24 import eu.etaxonomy.cdm.api.service.config.ITaxonServiceConfigurator;
25 import eu.etaxonomy.cdm.api.service.config.impl.TaxonServiceConfiguratorImpl;
26 import eu.etaxonomy.cdm.common.CdmUtils;
27 import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
28 import eu.etaxonomy.cdm.model.common.TimePeriod;
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.Rank;
33 import eu.etaxonomy.cdm.model.name.TaxonNameBase;
34 import eu.etaxonomy.cdm.model.reference.ReferenceBase;
35 import eu.etaxonomy.cdm.model.taxon.Synonym;
36 import eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType;
37 import eu.etaxonomy.cdm.model.taxon.Taxon;
38 import eu.etaxonomy.cdm.model.taxon.TaxonBase;
39 import eu.etaxonomy.taxeditor.TaxEditorPlugin;
40 import eu.etaxonomy.taxeditor.controller.GlobalController;
41 import eu.etaxonomy.taxeditor.navigation.SearchResult;
42
43 /**
44 * @author p.ciardelli
45 * @created 17.09.2008
46 * @version 1.0
47 */
48 public class CdmUtil {
49 private static final Logger logger = Logger.getLogger(CdmUtil.class);
50
51 /**
52 * Checks whether synonym's name is the basionym for ALL names
53 * in its group.
54 *
55 * @param synonym
56 *
57 * @return
58 */
59 public static boolean isSynonymGroupBasionym(Synonym synonym) {
60
61 TaxonNameBase synonymName = synonym.getName();
62 return isNameGroupBasionym(synonymName);
63 }
64
65 /**
66 * Checks whether name is the basionym for ALL names
67 * in its group.
68 * @param name
69 *
70 * @return
71 */
72 public static boolean isNameGroupBasionym(TaxonNameBase name) {
73 if (name == null) {
74 return false;
75 }
76
77 HomotypicalGroup homotypicalGroup = name.getHomotypicalGroup();
78 if (homotypicalGroup == null) {
79 return false;
80 }
81
82 Set<TaxonNameBase> typifiedNames = homotypicalGroup.getTypifiedNames();
83
84 // Check whether there are any other names in the group
85 if (typifiedNames.size() == 1) {
86 return false;
87 }
88
89 boolean isBasionymToAll = true;
90
91 for (TaxonNameBase taxonName : typifiedNames) {
92 if (!taxonName.equals(name)) {
93 if (!isNameBasionymOf(name, taxonName)) {
94 return false;
95 }
96 }
97 }
98 return true;
99 }
100
101 /**
102 * Checks whether a basionym relationship exists between fromName and toName.
103 *
104 * @param fromName
105 * @param toName
106 * @return
107 */
108 public static boolean isNameBasionymOf(TaxonNameBase fromName, TaxonNameBase toName) {
109 Set<NameRelationship> relations = toName.getRelationsToThisName();
110 for (NameRelationship relation : relations) {
111 if (relation.getType().equals(NameRelationshipType.BASIONYM()) &&
112 relation.getFromName().equals(fromName)) {
113 return true;
114 }
115 }
116 return false;
117 }
118
119 /**
120 * Creates a basionym relationship between basionymName and
121 * each name in its homotypic group.
122 *
123 * @param basionymName
124 */
125 public static void setGroupBasionym(TaxonNameBase basionymName) {
126 HomotypicalGroup homotypicalGroup = basionymName.getHomotypicalGroup();
127 if (homotypicalGroup == null) {
128 return;
129 }
130 for (TaxonNameBase name : homotypicalGroup.getTypifiedNames()) {
131 if (!name.equals(basionymName)) {
132
133 // First check whether the relationship already exists
134 if (!isNameBasionymOf(basionymName, name)) {
135
136 // Then create it
137 name.addRelationshipFromName(basionymName,
138 NameRelationshipType.BASIONYM(), null);
139 }
140 }
141 }
142 }
143
144 /**
145 * Removes all basionym relationships between basionymName and
146 * the names in its homotypic group.
147 *
148 * @param basionymName
149 */
150 public static void removeGroupBasionym(TaxonNameBase basionymName) {
151 HomotypicalGroup homotypicalGroup = basionymName.getHomotypicalGroup();
152 Set<NameRelationship> relations = basionymName.getRelationsFromThisName();
153 Set<NameRelationship> removeRelations = new HashSet<NameRelationship>();
154
155 for (NameRelationship relation : relations) {
156
157 // If this is a basionym relation, and toName is in the homotypical group,
158 // remove the relationship.
159 if (relation.getType().equals(NameRelationshipType.BASIONYM()) &&
160 relation.getToName().getHomotypicalGroup().equals(homotypicalGroup)) {
161 removeRelations.add(relation);
162 }
163 }
164
165 // Removing relations from a set through which we are iterating causes a
166 // ConcurrentModificationException. Therefore, we delete the targeted
167 // relations in a second step.
168 for (NameRelationship relation : removeRelations) {
169 basionymName.removeNameRelationship(relation);
170 }
171 }
172
173 /**
174 * Checks whether name belongs to the same homotypic group as taxon's name.
175 *
176 * @param name
177 * @param taxon
178 * @return
179 */
180 public static boolean isNameHomotypic(TaxonNameBase name, Taxon taxon) {
181 TaxonNameBase taxonName = taxon.getName();
182 if (taxonName == null || name == null) {
183 return false;
184 }
185 HomotypicalGroup homotypicGroup = taxonName.getHomotypicalGroup();
186 if (homotypicGroup == null) {
187 return false;
188 }
189 if (homotypicGroup.equals(name.getHomotypicalGroup())) {
190 return true;
191 }
192 return false;
193 }
194
195 /**
196 * Returns whatever is currently considered the display name for Taxon
197 * objects. Currently titleCache.
198 *
199 * @param taxon
200 * @return
201 */
202 public static String getDisplayName(TaxonBase taxonBase) {
203 TaxonNameBase name = taxonBase.getName();
204 return getDisplayName(name);
205 }
206
207 /**
208 * @param name
209 * @return
210 */
211 public static String getDisplayName(TaxonNameBase name) {
212 if (name != null) {
213 return name.getTitleCache();
214 }
215 return "";
216 }
217
218 public static String getDisplayNameWithRef(TaxonBase taxonBase) {
219 TaxonNameBase name = taxonBase.getName();
220 if (name != null) {
221 if (name.getFullTitleCache() == null || name.getFullTitleCache().length() == 0) {
222 return CdmUtils.Nz(name.getTitleCache());
223 } else {
224 return name.getFullTitleCache();
225 }
226 }
227 return "";
228 }
229
230 /**
231 * @param oldTaxon
232 * @param newAcceptedTaxon
233 * @param synonymType
234 * @param citation
235 * @param citationMicroReference
236 */
237 public static void makeTaxonSynonym(Taxon oldTaxon, Taxon newAcceptedTaxon,
238 SynonymRelationshipType synonymType, ReferenceBase citation,
239 String citationMicroReference) {
240 ITaxonService taxonService = getTaxonService();
241 taxonService.makeTaxonSynonym(oldTaxon, newAcceptedTaxon, synonymType,
242 citation, citationMicroReference);
243 }
244
245 /**
246 * @param searchText
247 * @return
248 */
249 public static List<TaxonNameBase> searchNameString(String searchText) {
250 List<TaxonNameBase> resultsSet = new ArrayList<TaxonNameBase>();
251 resultsSet.addAll(getNameService()
252 .getNamesByName(searchText.replace("*", "%")));
253 return resultsSet;
254 }
255
256 public static SearchResult searchTaxaByName(String name) {
257 SearchResult searchResult = new SearchResult();
258
259 ITaxonServiceConfigurator configurator = new TaxonServiceConfiguratorImpl();
260
261 configurator.setSearchString(name.replace("*", "%"));
262 configurator.setDoTaxa(true);
263 configurator.setDoNamesWithoutTaxa(true);
264 configurator.setDoSynonyms(true);
265 configurator.setPageNumber(1);
266 // TODO currently limit results to 1000 for now
267 configurator.setPageSize(1000);
268
269 List<IdentifiableEntity> result = getTaxonService().findTaxaAndNames(configurator).getRecords();
270
271 searchResult.addAll(result);
272 return searchResult;
273 }
274
275 private static CdmApplicationController getApplicationController() {
276 return TaxEditorPlugin.getDefault().getApplicationController();
277 }
278
279 public static INameService getNameService() {
280 return getApplicationController().getNameService();
281 }
282
283 public static ITaxonService getTaxonService() {
284 return getApplicationController().getTaxonService();
285 }
286
287 public static IReferenceService getReferenceService() {
288 return getApplicationController().getReferenceService();
289 }
290
291 /**
292 * @param searchText
293 * @param taxon
294 * @return
295 */
296 public static Set<TaxonNameBase> getNameByNameForTaxonContext(String searchText, Taxon taxon) {
297 Set<TaxonNameBase> resultsSet = new HashSet<TaxonNameBase>();
298 resultsSet.addAll(getNameService().getNamesByName
299 (searchText.replace("*", "%"), taxon));
300 return resultsSet;
301 }
302
303 /**
304 * Converts a <code>String</code> whose format is either a valid year
305 * or two valid years with the format "XXXX-XXXX" into a TimePeriod.
306 *
307 * @see #getValidYear(String yearStr)
308 * @param refYear
309 * @return
310 * @throws NumberFormatException
311 */
312 public static TimePeriod convertTimePeriod(String refYear) throws NumberFormatException {
313
314 if (refYear == null || ("").equals(refYear)){
315 return null;
316 }
317
318 TimePeriod datePublished = TimePeriod.NewInstance();
319
320 // In case format is "xxxx-xxxx"
321 String[] years = refYear.split("-");
322
323 // Unlikely case of "xxxx-xxxx-xxxx..."
324 if (years.length > 2) {
325 throw new NumberFormatException();
326 }
327
328 // Set startYear
329 datePublished.setStartYear(getValidYear(years[0]));
330
331 // Format is "xxxx-xxxx"
332 if (years.length == 2) {
333 datePublished.setEndYear(getValidYear(years[1]));
334 }
335
336 return datePublished;
337 }
338
339
340 /**
341 * Checks whether a <code>String</code> is a valid year between
342 * 1750 and 2030. Throws a <code>NumberFormatException</code> if not.
343 *
344 * @param yearStr
345 * @return
346 * @throws NumberFormatException
347 */
348 public static Integer getValidYear(String yearStr) throws NumberFormatException {
349
350 Integer yearInt = null;
351
352 // Try casting string - don't catch number format exception
353 try {
354 yearInt = new Integer(yearStr);
355 } catch (ClassCastException e) {
356 throw new NumberFormatException();
357 }
358
359 // Is year in valid range?
360 if (yearInt < 1750 || yearInt > 2030) {
361 throw new NumberFormatException();
362 }
363
364 return yearInt;
365 }
366
367 /**
368 * Searches for references by string. "%" is used as a wildcard.
369 *
370 * @param text
371 * @return
372 */
373 public static List getReferencesByTitle(String reference) {
374
375 reference = reference.replace("*", "%");
376 List resultsList = null;
377 try {
378 resultsList = getReferenceService().getReferencesByTitle(reference);
379 } catch (RuntimeException e) {
380 MessageDialog.openError(GlobalController.getShell(), "Search reference error",
381 "Reference search returned an error. This could be a Hibernate concurrency problem. " +
382 "Please try saving your work, then searching again.");
383 e.printStackTrace();
384 }
385 return resultsList;
386 }
387
388 /**
389 * Returns true if <code>taxon</code> belongs to the children, grandchildren,
390 * etc. of <code>checkTaxon</code>.
391 *
392 * @param taxon
393 * @param checkTaxon
394 * @return
395 */
396 public static boolean isTaxonChildOfTaxon(Taxon taxon, Taxon checkTaxon) {
397
398 // Traverse all checkTaxon's children
399 for (Taxon childTaxon : checkTaxon.getTaxonomicChildren()) {
400
401 if (childTaxon.equals(taxon)) {
402 return true;
403 } else {
404
405 // Compare taxon with childTaxon's children
406 if (isTaxonChildOfTaxon(taxon, childTaxon)) {
407 return true;
408 }
409 }
410 }
411 return false;
412 }
413
414 /**
415 * @param name
416 * @return
417 */
418 public static boolean isNameSupraSpecific(TaxonNameBase name) {
419
420 if (name == null || name.getRank() == null) {
421 return false;
422 }
423
424 if (name.getRank().isHigher(Rank.SPECIES())) {
425 // if (name.isInfraGeneric() || name.isSupraGeneric() || name.isGenus()) {
426 return true;
427 } else {
428 return false;
429 }
430 }
431 }