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