merging revisions 14601:14603, 14653:14683 from branches/cdmlib/vibrant-index into...
[cdmlib.git] / cdmlib-services / src / main / java / eu / etaxonomy / cdm / api / service / TaxonServiceImpl.java
1 // $Id$
2 /**
3 * Copyright (C) 2007 EDIT
4 * European Distributed Institute of Taxonomy
5 * http://www.e-taxonomy.eu
6 *
7 * The contents of this file are subject to the Mozilla Public License Version 1.1
8 * See LICENSE.TXT at the top of this package for the full license terms.
9 */
10
11 package eu.etaxonomy.cdm.api.service;
12
13 import java.io.IOException;
14 import java.util.ArrayList;
15 import java.util.HashMap;
16 import java.util.HashSet;
17 import java.util.List;
18 import java.util.Set;
19 import java.util.UUID;
20
21 import org.apache.log4j.Logger;
22 import org.apache.lucene.index.CorruptIndexException;
23 import org.apache.lucene.queryParser.ParseException;
24 import org.apache.lucene.search.TopDocs;
25 import org.springframework.beans.factory.annotation.Autowired;
26 import org.springframework.stereotype.Service;
27 import org.springframework.transaction.annotation.Propagation;
28 import org.springframework.transaction.annotation.Transactional;
29
30 import eu.etaxonomy.cdm.api.service.config.ITaxonServiceConfigurator;
31 import eu.etaxonomy.cdm.api.service.config.MatchingTaxonConfigurator;
32 import eu.etaxonomy.cdm.api.service.config.NameDeletionConfigurator;
33 import eu.etaxonomy.cdm.api.service.config.TaxonDeletionConfigurator;
34 import eu.etaxonomy.cdm.api.service.exception.DataChangeNoRollbackException;
35 import eu.etaxonomy.cdm.api.service.exception.HomotypicalGroupChangeException;
36 import eu.etaxonomy.cdm.api.service.exception.ReferencedObjectUndeletableException;
37 import eu.etaxonomy.cdm.api.service.pager.Pager;
38 import eu.etaxonomy.cdm.api.service.pager.impl.DefaultPagerImpl;
39 import eu.etaxonomy.cdm.api.service.search.ISearchResultBuilder;
40 import eu.etaxonomy.cdm.api.service.search.SearchResult;
41 import eu.etaxonomy.cdm.common.monitor.IProgressMonitor;
42 import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
43 import eu.etaxonomy.cdm.model.common.CdmBase;
44 import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
45 import eu.etaxonomy.cdm.model.common.IdentifiableSource;
46 import eu.etaxonomy.cdm.model.common.OrderedTermVocabulary;
47 import eu.etaxonomy.cdm.model.common.RelationshipBase;
48 import eu.etaxonomy.cdm.model.common.RelationshipBase.Direction;
49 import eu.etaxonomy.cdm.model.common.UuidAndTitleCache;
50 import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
51 import eu.etaxonomy.cdm.model.description.IIdentificationKey;
52 import eu.etaxonomy.cdm.model.description.PolytomousKeyNode;
53 import eu.etaxonomy.cdm.model.description.TaxonDescription;
54 import eu.etaxonomy.cdm.model.description.TaxonInteraction;
55 import eu.etaxonomy.cdm.model.media.Media;
56 import eu.etaxonomy.cdm.model.media.MediaRepresentation;
57 import eu.etaxonomy.cdm.model.media.MediaUtils;
58 import eu.etaxonomy.cdm.model.name.HomotypicalGroup;
59 import eu.etaxonomy.cdm.model.name.Rank;
60 import eu.etaxonomy.cdm.model.name.TaxonNameBase;
61 import eu.etaxonomy.cdm.model.name.ZoologicalName;
62 import eu.etaxonomy.cdm.model.occurrence.DerivedUnitBase;
63 import eu.etaxonomy.cdm.model.reference.Reference;
64 import eu.etaxonomy.cdm.model.taxon.Classification;
65 import eu.etaxonomy.cdm.model.taxon.Synonym;
66 import eu.etaxonomy.cdm.model.taxon.SynonymRelationship;
67 import eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType;
68 import eu.etaxonomy.cdm.model.taxon.Taxon;
69 import eu.etaxonomy.cdm.model.taxon.TaxonBase;
70 import eu.etaxonomy.cdm.model.taxon.TaxonNode;
71 import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;
72 import eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType;
73 import eu.etaxonomy.cdm.persistence.dao.common.ICdmGenericDao;
74 import eu.etaxonomy.cdm.persistence.dao.common.IOrderedTermVocabularyDao;
75 import eu.etaxonomy.cdm.persistence.dao.name.ITaxonNameDao;
76 import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao;
77 import eu.etaxonomy.cdm.persistence.fetch.CdmFetch;
78 import eu.etaxonomy.cdm.persistence.query.MatchMode;
79 import eu.etaxonomy.cdm.persistence.query.OrderHint;
80 import eu.etaxonomy.cdm.persistence.query.OrderHint.SortOrder;
81 import eu.etaxonomy.cdm.search.LuceneSearch;
82 import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
83
84
85 /**
86 * @author a.kohlbecker
87 * @date 10.09.2010
88 *
89 */
90 @Service
91 @Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
92 public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDao> implements ITaxonService{
93 private static final Logger logger = Logger.getLogger(TaxonServiceImpl.class);
94
95 public static final String POTENTIAL_COMBINATION_NAMESPACE = "Potential combination";
96
97 public static final String INFERRED_EPITHET_NAMESPACE = "Inferred epithet";
98
99 public static final String INFERRED_GENUS_NAMESPACE = "Inferred genus";
100
101
102 @Autowired
103 private ITaxonNameDao nameDao;
104
105 @Autowired
106 private ISearchResultBuilder searchResultBuilder;
107
108 @Autowired
109 private INameService nameService;
110
111 @Autowired
112 private ICdmGenericDao genericDao;
113
114 @Autowired
115 private IDescriptionService descriptionService;
116
117 @Autowired
118 private IOrderedTermVocabularyDao orderedVocabularyDao;
119
120 /**
121 * Constructor
122 */
123 public TaxonServiceImpl(){
124 if (logger.isDebugEnabled()) { logger.debug("Load TaxonService Bean"); }
125 }
126
127 /**
128 * FIXME Candidate for harmonization
129 * rename searchByName ?
130 */
131 public List<TaxonBase> searchTaxaByName(String name, Reference sec) {
132 return dao.getTaxaByName(name, sec);
133 }
134
135 /**
136 * FIXME Candidate for harmonization
137 * list(Synonym.class, ...)
138 * (non-Javadoc)
139 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllSynonyms(int, int)
140 */
141 public List<Synonym> getAllSynonyms(int limit, int start) {
142 return dao.getAllSynonyms(limit, start);
143 }
144
145 /**
146 * FIXME Candidate for harmonization
147 * list(Taxon.class, ...)
148 * (non-Javadoc)
149 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllTaxa(int, int)
150 */
151 public List<Taxon> getAllTaxa(int limit, int start) {
152 return dao.getAllTaxa(limit, start);
153 }
154
155 /**
156 * FIXME Candidate for harmonization
157 * merge with getRootTaxa(Reference sec, ..., ...)
158 * (non-Javadoc)
159 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getRootTaxa(eu.etaxonomy.cdm.model.reference.Reference, boolean)
160 */
161 public List<Taxon> getRootTaxa(Reference sec, CdmFetch cdmFetch, boolean onlyWithChildren) {
162 if (cdmFetch == null){
163 cdmFetch = CdmFetch.NO_FETCH();
164 }
165 return dao.getRootTaxa(sec, cdmFetch, onlyWithChildren, false);
166 }
167
168
169 /* (non-Javadoc)
170 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getRootTaxa(eu.etaxonomy.cdm.model.name.Rank, eu.etaxonomy.cdm.model.reference.Reference, boolean, boolean)
171 */
172 public List<Taxon> getRootTaxa(Rank rank, Reference sec, boolean onlyWithChildren,boolean withMisapplications, List<String> propertyPaths) {
173 return dao.getRootTaxa(rank, sec, null, onlyWithChildren, withMisapplications, propertyPaths);
174 }
175
176 /* (non-Javadoc)
177 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllRelationships(int, int)
178 */
179 public List<RelationshipBase> getAllRelationships(int limit, int start){
180 return dao.getAllRelationships(limit, start);
181 }
182
183 /**
184 * FIXME Candidate for harmonization
185 * is this the same as termService.getVocabulary(VocabularyEnum.TaxonRelationshipType) ?
186 */
187 @Deprecated
188 public OrderedTermVocabulary<TaxonRelationshipType> getTaxonRelationshipTypeVocabulary() {
189
190 String taxonRelTypeVocabularyId = "15db0cf7-7afc-4a86-a7d4-221c73b0c9ac";
191 UUID uuid = UUID.fromString(taxonRelTypeVocabularyId);
192 OrderedTermVocabulary<TaxonRelationshipType> taxonRelTypeVocabulary =
193 (OrderedTermVocabulary)orderedVocabularyDao.findByUuid(uuid);
194 return taxonRelTypeVocabulary;
195 }
196
197
198
199 /*
200 * (non-Javadoc)
201 * @see eu.etaxonomy.cdm.api.service.ITaxonService#swapSynonymWithAcceptedTaxon(eu.etaxonomy.cdm.model.taxon.Synonym)
202 */
203 @Transactional(readOnly = false)
204 public void swapSynonymAndAcceptedTaxon(Synonym synonym, Taxon acceptedTaxon){
205
206 TaxonNameBase<?,?> synonymName = synonym.getName();
207 synonymName.removeTaxonBase(synonym);
208 TaxonNameBase<?,?> taxonName = acceptedTaxon.getName();
209 taxonName.removeTaxonBase(acceptedTaxon);
210
211 synonym.setName(taxonName);
212 acceptedTaxon.setName(synonymName);
213
214 // the accepted taxon needs a new uuid because the concept has changed
215 // FIXME this leads to an error "HibernateException: immutable natural identifier of an instance of eu.etaxonomy.cdm.model.taxon.Taxon was altered"
216 //acceptedTaxon.setUuid(UUID.randomUUID());
217 }
218
219
220 /* (non-Javadoc)
221 * @see eu.etaxonomy.cdm.api.service.ITaxonService#changeSynonymToAcceptedTaxon(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon)
222 */
223 //TODO correct delete handling still needs to be implemented / checked
224 @Override
225 @Transactional(readOnly = false)
226 public Taxon changeSynonymToAcceptedTaxon(Synonym synonym, Taxon acceptedTaxon, boolean deleteSynonym, boolean copyCitationInfo, Reference citation, String microCitation) throws HomotypicalGroupChangeException{
227
228 TaxonNameBase<?,?> acceptedName = acceptedTaxon.getName();
229 TaxonNameBase<?,?> synonymName = synonym.getName();
230 HomotypicalGroup synonymHomotypicGroup = synonymName.getHomotypicalGroup();
231
232 //check synonym is not homotypic
233 if (acceptedName.getHomotypicalGroup().equals(synonymHomotypicGroup)){
234 String message = "The accepted taxon and the synonym are part of the same homotypical group and therefore can not be both accepted.";
235 throw new HomotypicalGroupChangeException(message);
236 }
237
238 Taxon newAcceptedTaxon = Taxon.NewInstance(synonymName, acceptedTaxon.getSec());
239
240 SynonymRelationshipType relTypeForGroup = SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF();
241 List<Synonym> heteroSynonyms = acceptedTaxon.getSynonymsInGroup(synonymHomotypicGroup);
242
243 for (Synonym heteroSynonym : heteroSynonyms){
244 if (synonym.equals(heteroSynonym)){
245 acceptedTaxon.removeSynonym(heteroSynonym, false);
246 }else{
247 //move synonyms in same homotypic group to new accepted taxon
248 heteroSynonym.replaceAcceptedTaxon(newAcceptedTaxon, relTypeForGroup, copyCitationInfo, citation, microCitation);
249 }
250 }
251
252 //synonym.getName().removeTaxonBase(synonym);
253 //TODO correct delete handling still needs to be implemented / checked
254 if (deleteSynonym){
255 // deleteSynonym(synonym, taxon, false);
256 try {
257 this.dao.flush();
258 this.delete(synonym);
259
260 } catch (Exception e) {
261 logger.info("Can't delete old synonym from database");
262 }
263 }
264
265 return newAcceptedTaxon;
266 }
267
268
269 public Taxon changeSynonymToRelatedTaxon(Synonym synonym, Taxon toTaxon, TaxonRelationshipType taxonRelationshipType, Reference citation, String microcitation){
270
271 // Get name from synonym
272 TaxonNameBase<?, ?> synonymName = synonym.getName();
273
274 // remove synonym from taxon
275 toTaxon.removeSynonym(synonym);
276
277 // Create a taxon with synonym name
278 Taxon fromTaxon = Taxon.NewInstance(synonymName, null);
279
280 // Add taxon relation
281 fromTaxon.addTaxonRelation(toTaxon, taxonRelationshipType, citation, microcitation);
282
283 // since we are swapping names, we have to detach the name from the synonym completely.
284 // Otherwise the synonym will still be in the list of typified names.
285 synonym.getName().removeTaxonBase(synonym);
286
287 return fromTaxon;
288 }
289
290
291 /* (non-Javadoc)
292 * @see eu.etaxonomy.cdm.api.service.ITaxonService#changeHomotypicalGroupOfSynonym(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.name.HomotypicalGroup, eu.etaxonomy.cdm.model.taxon.Taxon, boolean, boolean)
293 */
294 @Transactional(readOnly = false)
295 @Override
296 public void changeHomotypicalGroupOfSynonym(Synonym synonym, HomotypicalGroup newHomotypicalGroup, Taxon targetTaxon,
297 boolean removeFromOtherTaxa, boolean setBasionymRelationIfApplicable){
298 // Get synonym name
299 TaxonNameBase synonymName = synonym.getName();
300 HomotypicalGroup oldHomotypicalGroup = synonymName.getHomotypicalGroup();
301
302
303 // Switch groups
304 oldHomotypicalGroup.removeTypifiedName(synonymName);
305 newHomotypicalGroup.addTypifiedName(synonymName);
306
307 //remove existing basionym relationships
308 synonymName.removeBasionyms();
309
310 //add basionym relationship
311 if (setBasionymRelationIfApplicable){
312 Set<TaxonNameBase> basionyms = newHomotypicalGroup.getBasionyms();
313 for (TaxonNameBase basionym : basionyms){
314 synonymName.addBasionym(basionym);
315 }
316 }
317
318 //set synonym relationship correctly
319 // SynonymRelationship relToTaxon = null;
320 boolean relToTargetTaxonExists = false;
321 Set<SynonymRelationship> existingRelations = synonym.getSynonymRelations();
322 for (SynonymRelationship rel : existingRelations){
323 Taxon acceptedTaxon = rel.getAcceptedTaxon();
324 boolean isTargetTaxon = acceptedTaxon != null && acceptedTaxon.equals(targetTaxon);
325 HomotypicalGroup acceptedGroup = acceptedTaxon.getHomotypicGroup();
326 boolean isHomotypicToTaxon = acceptedGroup.equals(newHomotypicalGroup);
327 SynonymRelationshipType newRelationType = isHomotypicToTaxon? SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF() : SynonymRelationshipType.HETEROTYPIC_SYNONYM_OF();
328 rel.setType(newRelationType);
329 //TODO handle citation and microCitation
330
331 if (isTargetTaxon){
332 relToTargetTaxonExists = true;
333 }else{
334 if (removeFromOtherTaxa){
335 acceptedTaxon.removeSynonym(synonym, false);
336 }else{
337 //do nothing
338 }
339 }
340 }
341 if (targetTaxon != null && ! relToTargetTaxonExists ){
342 Taxon acceptedTaxon = targetTaxon;
343 HomotypicalGroup acceptedGroup = acceptedTaxon.getHomotypicGroup();
344 boolean isHomotypicToTaxon = acceptedGroup.equals(newHomotypicalGroup);
345 SynonymRelationshipType relType = isHomotypicToTaxon? SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF() : SynonymRelationshipType.HETEROTYPIC_SYNONYM_OF();
346 //TODO handle citation and microCitation
347 Reference citation = null;
348 String microCitation = null;
349 acceptedTaxon.addSynonym(synonym, relType, citation, microCitation);
350 }
351
352 }
353
354
355 /* (non-Javadoc)
356 * @see eu.etaxonomy.cdm.api.service.IIdentifiableEntityService#updateTitleCache(java.lang.Integer, eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy)
357 */
358 @Override
359 public void updateTitleCache(Class<? extends TaxonBase> clazz, Integer stepSize, IIdentifiableEntityCacheStrategy<TaxonBase> cacheStrategy, IProgressMonitor monitor) {
360 if (clazz == null){
361 clazz = TaxonBase.class;
362 }
363 super.updateTitleCacheImpl(clazz, stepSize, cacheStrategy, monitor);
364 }
365
366 @Autowired
367 protected void setDao(ITaxonDao dao) {
368 this.dao = dao;
369 }
370
371 /* (non-Javadoc)
372 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxaByName(java.lang.Class, java.lang.String, java.lang.String, java.lang.String, java.lang.String, eu.etaxonomy.cdm.model.name.Rank, java.lang.Integer, java.lang.Integer)
373 */
374 public Pager<TaxonBase> findTaxaByName(Class<? extends TaxonBase> clazz, String uninomial, String infragenericEpithet, String specificEpithet, String infraspecificEpithet, Rank rank, Integer pageSize,Integer pageNumber) {
375 Integer numberOfResults = dao.countTaxaByName(clazz, uninomial, infragenericEpithet, specificEpithet, infraspecificEpithet, rank);
376
377 List<TaxonBase> results = new ArrayList<TaxonBase>();
378 if(numberOfResults > 0) { // no point checking again
379 results = dao.findTaxaByName(clazz, uninomial, infragenericEpithet, specificEpithet, infraspecificEpithet, rank, pageSize, pageNumber);
380 }
381
382 return new DefaultPagerImpl<TaxonBase>(pageNumber, numberOfResults, pageSize, results);
383 }
384
385 /* (non-Javadoc)
386 * @see eu.etaxonomy.cdm.api.service.ITaxonService#listTaxaByName(java.lang.Class, java.lang.String, java.lang.String, java.lang.String, java.lang.String, eu.etaxonomy.cdm.model.name.Rank, java.lang.Integer, java.lang.Integer)
387 */
388 public List<TaxonBase> listTaxaByName(Class<? extends TaxonBase> clazz, String uninomial, String infragenericEpithet, String specificEpithet, String infraspecificEpithet, Rank rank, Integer pageSize,Integer pageNumber) {
389 Integer numberOfResults = dao.countTaxaByName(clazz, uninomial, infragenericEpithet, specificEpithet, infraspecificEpithet, rank);
390
391 List<TaxonBase> results = new ArrayList<TaxonBase>();
392 if(numberOfResults > 0) { // no point checking again
393 results = dao.findTaxaByName(clazz, uninomial, infragenericEpithet, specificEpithet, infraspecificEpithet, rank, pageSize, pageNumber);
394 }
395
396 return results;
397 }
398
399 /* (non-Javadoc)
400 * @see eu.etaxonomy.cdm.api.service.ITaxonService#listToTaxonRelationships(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)
401 */
402 public List<TaxonRelationship> listToTaxonRelationships(Taxon taxon, TaxonRelationshipType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths){
403 Integer numberOfResults = dao.countTaxonRelationships(taxon, type, TaxonRelationship.Direction.relatedTo);
404
405 List<TaxonRelationship> results = new ArrayList<TaxonRelationship>();
406 if(numberOfResults > 0) { // no point checking again
407 results = dao.getTaxonRelationships(taxon, type, pageSize, pageNumber, orderHints, propertyPaths, TaxonRelationship.Direction.relatedTo);
408 }
409 return results;
410 }
411
412 /* (non-Javadoc)
413 * @see eu.etaxonomy.cdm.api.service.ITaxonService#pageToTaxonRelationships(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)
414 */
415 public Pager<TaxonRelationship> pageToTaxonRelationships(Taxon taxon, TaxonRelationshipType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
416 Integer numberOfResults = dao.countTaxonRelationships(taxon, type, TaxonRelationship.Direction.relatedTo);
417
418 List<TaxonRelationship> results = new ArrayList<TaxonRelationship>();
419 if(numberOfResults > 0) { // no point checking again
420 results = dao.getTaxonRelationships(taxon, type, pageSize, pageNumber, orderHints, propertyPaths, TaxonRelationship.Direction.relatedTo);
421 }
422 return new DefaultPagerImpl<TaxonRelationship>(pageNumber, numberOfResults, pageSize, results);
423 }
424
425 /* (non-Javadoc)
426 * @see eu.etaxonomy.cdm.api.service.ITaxonService#listFromTaxonRelationships(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)
427 */
428 public List<TaxonRelationship> listFromTaxonRelationships(Taxon taxon, TaxonRelationshipType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths){
429 Integer numberOfResults = dao.countTaxonRelationships(taxon, type, TaxonRelationship.Direction.relatedFrom);
430
431 List<TaxonRelationship> results = new ArrayList<TaxonRelationship>();
432 if(numberOfResults > 0) { // no point checking again
433 results = dao.getTaxonRelationships(taxon, type, pageSize, pageNumber, orderHints, propertyPaths, TaxonRelationship.Direction.relatedFrom);
434 }
435 return results;
436 }
437
438 /* (non-Javadoc)
439 * @see eu.etaxonomy.cdm.api.service.ITaxonService#pageFromTaxonRelationships(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)
440 */
441 public Pager<TaxonRelationship> pageFromTaxonRelationships(Taxon taxon, TaxonRelationshipType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
442 Integer numberOfResults = dao.countTaxonRelationships(taxon, type, TaxonRelationship.Direction.relatedFrom);
443
444 List<TaxonRelationship> results = new ArrayList<TaxonRelationship>();
445 if(numberOfResults > 0) { // no point checking again
446 results = dao.getTaxonRelationships(taxon, type, pageSize, pageNumber, orderHints, propertyPaths, TaxonRelationship.Direction.relatedFrom);
447 }
448 return new DefaultPagerImpl<TaxonRelationship>(pageNumber, numberOfResults, pageSize, results);
449 }
450
451 /* (non-Javadoc)
452 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getSynonyms(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)
453 */
454 public Pager<SynonymRelationship> getSynonyms(Taxon taxon, SynonymRelationshipType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
455 Integer numberOfResults = dao.countSynonyms(taxon, type);
456
457 List<SynonymRelationship> results = new ArrayList<SynonymRelationship>();
458 if(numberOfResults > 0) { // no point checking again
459 results = dao.getSynonyms(taxon, type, pageSize, pageNumber, orderHints, propertyPaths);
460 }
461
462 return new DefaultPagerImpl<SynonymRelationship>(pageNumber, numberOfResults, pageSize, results);
463 }
464
465 /* (non-Javadoc)
466 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getSynonyms(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)
467 */
468 public Pager<SynonymRelationship> getSynonyms(Synonym synonym, SynonymRelationshipType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
469 Integer numberOfResults = dao.countSynonyms(synonym, type);
470
471 List<SynonymRelationship> results = new ArrayList<SynonymRelationship>();
472 if(numberOfResults > 0) { // no point checking again
473 results = dao.getSynonyms(synonym, type, pageSize, pageNumber, orderHints, propertyPaths);
474 }
475
476 return new DefaultPagerImpl<SynonymRelationship>(pageNumber, numberOfResults, pageSize, results);
477 }
478
479 /* (non-Javadoc)
480 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getHomotypicSynonymsByHomotypicGroup(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.List)
481 */
482 public List<Synonym> getHomotypicSynonymsByHomotypicGroup(Taxon taxon, List<String> propertyPaths){
483 Taxon t = (Taxon)dao.load(taxon.getUuid(), propertyPaths);
484 return t.getHomotypicSynonymsByHomotypicGroup();
485 }
486
487 /* (non-Javadoc)
488 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getHeterotypicSynonymyGroups(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.List)
489 */
490 public List<List<Synonym>> getHeterotypicSynonymyGroups(Taxon taxon, List<String> propertyPaths){
491 Taxon t = (Taxon)dao.load(taxon.getUuid(), propertyPaths);
492 List<HomotypicalGroup> homotypicalGroups = t.getHeterotypicSynonymyGroups();
493 List<List<Synonym>> heterotypicSynonymyGroups = new ArrayList<List<Synonym>>(homotypicalGroups.size());
494 for(HomotypicalGroup homotypicalGroup : homotypicalGroups){
495 heterotypicSynonymyGroups.add(t.getSynonymsInGroup(homotypicalGroup));
496 }
497 return heterotypicSynonymyGroups;
498 }
499
500 public List<UuidAndTitleCache<TaxonBase>> findTaxaAndNamesForEditor(ITaxonServiceConfigurator configurator){
501
502 List<UuidAndTitleCache<TaxonBase>> result = new ArrayList<UuidAndTitleCache<TaxonBase>>();
503 // Class<? extends TaxonBase> clazz = null;
504 // if ((configurator.isDoTaxa() && configurator.isDoSynonyms())) {
505 // clazz = TaxonBase.class;
506 // //propertyPath.addAll(configurator.getTaxonPropertyPath());
507 // //propertyPath.addAll(configurator.getSynonymPropertyPath());
508 // } else if(configurator.isDoTaxa()) {
509 // clazz = Taxon.class;
510 // //propertyPath = configurator.getTaxonPropertyPath();
511 // } else if (configurator.isDoSynonyms()) {
512 // clazz = Synonym.class;
513 // //propertyPath = configurator.getSynonymPropertyPath();
514 // }
515
516
517 result = dao.getTaxaByNameForEditor(configurator.isDoTaxa(), configurator.isDoSynonyms(), configurator.getTitleSearchStringSqlized(), configurator.getClassification(), configurator.getMatchMode(), configurator.getNamedAreas());
518 return result;
519 }
520
521 /* (non-Javadoc)
522 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxaAndNames(eu.etaxonomy.cdm.api.service.config.ITaxonServiceConfigurator)
523 */
524 public Pager<IdentifiableEntity> findTaxaAndNames(ITaxonServiceConfigurator configurator) {
525
526 List<IdentifiableEntity> results = new ArrayList<IdentifiableEntity>();
527 int numberOfResults = 0; // overall number of results (as opposed to number of results per page)
528 List<TaxonBase> taxa = null;
529
530 // Taxa and synonyms
531 long numberTaxaResults = 0L;
532
533
534 List<String> propertyPath = new ArrayList<String>();
535 if(configurator.getTaxonPropertyPath() != null){
536 propertyPath.addAll(configurator.getTaxonPropertyPath());
537 }
538
539
540 if (configurator.isDoMisappliedNames() || configurator.isDoSynonyms() || configurator.isDoTaxa()){
541 if(configurator.getPageSize() != null){ // no point counting if we need all anyway
542 numberTaxaResults =
543 dao.countTaxaByName(configurator.isDoTaxa(),configurator.isDoSynonyms(), configurator.isDoMisappliedNames(),
544 configurator.getTitleSearchStringSqlized(), configurator.getClassification(), configurator.getMatchMode(),
545 configurator.getNamedAreas());
546 }
547
548 if(configurator.getPageSize() == null || numberTaxaResults > configurator.getPageSize() * configurator.getPageNumber()){ // no point checking again if less results
549 taxa = dao.getTaxaByName(configurator.isDoTaxa(), configurator.isDoSynonyms(),
550 configurator.isDoMisappliedNames(), configurator.getTitleSearchStringSqlized(), configurator.getClassification(),
551 configurator.getMatchMode(), configurator.getNamedAreas(),
552 configurator.getPageSize(), configurator.getPageNumber(), propertyPath);
553 }
554 }
555
556 if (logger.isDebugEnabled()) { logger.debug(numberTaxaResults + " matching taxa counted"); }
557
558 if(taxa != null){
559 results.addAll(taxa);
560 }
561
562 numberOfResults += numberTaxaResults;
563
564 // Names without taxa
565 if (configurator.isDoNamesWithoutTaxa()) {
566 int numberNameResults = 0;
567
568 List<? extends TaxonNameBase<?,?>> names =
569 nameDao.findByName(configurator.getTitleSearchStringSqlized(), configurator.getMatchMode(),
570 configurator.getPageSize(), configurator.getPageNumber(), null, configurator.getTaxonNamePropertyPath());
571 if (logger.isDebugEnabled()) { logger.debug(names.size() + " matching name(s) found"); }
572 if (names.size() > 0) {
573 for (TaxonNameBase<?,?> taxonName : names) {
574 if (taxonName.getTaxonBases().size() == 0) {
575 results.add(taxonName);
576 numberNameResults++;
577 }
578 }
579 if (logger.isDebugEnabled()) { logger.debug(numberNameResults + " matching name(s) without taxa found"); }
580 numberOfResults += numberNameResults;
581 }
582 }
583
584 // Taxa from common names
585
586 if (configurator.isDoTaxaByCommonNames()) {
587 taxa = new ArrayList<TaxonBase>();
588 numberTaxaResults = 0;
589 if(configurator.getPageSize() != null){// no point counting if we need all anyway
590 numberTaxaResults = dao.countTaxaByCommonName(configurator.getTitleSearchStringSqlized(), configurator.getClassification(), configurator.getMatchMode(), configurator.getNamedAreas());
591 }
592 if(configurator.getPageSize() == null || numberTaxaResults > configurator.getPageSize() * configurator.getPageNumber()){
593 List<Object[]> commonNameResults = dao.getTaxaByCommonName(configurator.getTitleSearchStringSqlized(), configurator.getClassification(), configurator.getMatchMode(), configurator.getNamedAreas(), configurator.getPageSize(), configurator.getPageNumber(), configurator.getTaxonPropertyPath());
594 for( Object[] entry : commonNameResults ) {
595 taxa.add((TaxonBase) entry[0]);
596 }
597 }
598 if(taxa != null){
599 results.addAll(taxa);
600 }
601 numberOfResults += numberTaxaResults;
602
603 }
604
605 return new DefaultPagerImpl<IdentifiableEntity>
606 (configurator.getPageNumber(), numberOfResults, configurator.getPageSize(), results);
607 }
608
609 public List<UuidAndTitleCache<TaxonBase>> getTaxonUuidAndTitleCache(){
610 return dao.getUuidAndTitleCache();
611 }
612
613 /* (non-Javadoc)
614 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllMedia(eu.etaxonomy.cdm.model.taxon.Taxon, int, int, int, java.lang.String[])
615 */
616 public List<MediaRepresentation> getAllMedia(Taxon taxon, int size, int height, int widthOrDuration, String[] mimeTypes){
617 List<MediaRepresentation> medRep = new ArrayList<MediaRepresentation>();
618 taxon = (Taxon)dao.load(taxon.getUuid());
619 Set<TaxonDescription> descriptions = taxon.getDescriptions();
620 for (TaxonDescription taxDesc: descriptions){
621 Set<DescriptionElementBase> elements = taxDesc.getElements();
622 for (DescriptionElementBase descElem: elements){
623 for(Media media : descElem.getMedia()){
624
625 //find the best matching representation
626 medRep.add(MediaUtils.findBestMatchingRepresentation(media, null, size, height, widthOrDuration, mimeTypes));
627
628 }
629 }
630 }
631 return medRep;
632 }
633
634 /* (non-Javadoc)
635 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxaByID(java.util.Set)
636 */
637 public List<TaxonBase> findTaxaByID(Set<Integer> listOfIDs) {
638 return this.dao.findById(listOfIDs);
639 }
640
641 /* (non-Javadoc)
642 * @see eu.etaxonomy.cdm.api.service.ITaxonService#countAllRelationships()
643 */
644 public int countAllRelationships() {
645 return this.dao.countAllRelationships();
646 }
647
648
649
650
651 /* (non-Javadoc)
652 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findIdenticalTaxonNames(java.util.List)
653 */
654 public List<TaxonNameBase> findIdenticalTaxonNames(List<String> propertyPath) {
655 return this.dao.findIdenticalTaxonNames(propertyPath);
656 }
657
658
659 /* (non-Javadoc)
660 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteTaxon(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.api.service.config.TaxonDeletionConfigurator)
661 */
662 @Override
663 public void deleteTaxon(Taxon taxon, TaxonDeletionConfigurator config) throws ReferencedObjectUndeletableException {
664 if (config == null){
665 config = new TaxonDeletionConfigurator();
666 }
667
668 // TaxonNode
669 if (! config.isDeleteTaxonNodes()){
670 if (taxon.getTaxonNodes().size() > 0){
671 String message = "Taxon can't be deleted as it is used in a classification node. Remove taxon from all classifications prior to deletion.";
672 throw new ReferencedObjectUndeletableException(message);
673 }
674 }
675
676
677 // SynonymRelationShip
678 if (config.isDeleteSynonymRelations()){
679 boolean removeSynonymNameFromHomotypicalGroup = false;
680 for (SynonymRelationship synRel : taxon.getSynonymRelations()){
681 Synonym synonym = synRel.getSynonym();
682 taxon.removeSynonymRelation(synRel, removeSynonymNameFromHomotypicalGroup);
683 if (config.isDeleteSynonymsIfPossible()){
684 //TODO which value
685 boolean newHomotypicGroupIfNeeded = true;
686 deleteSynonym(synonym, taxon, config.isDeleteNameIfPossible(), newHomotypicGroupIfNeeded);
687 }else{
688 deleteSynonymRelationships(synonym, taxon);
689 }
690 }
691 }
692
693 // TaxonRelationship
694 if (! config.isDeleteTaxonRelationships()){
695 if (taxon.getTaxonRelations().size() > 0){
696 String message = "Taxon can't be deleted as it is related to another taxon. Remove taxon from all relations to other taxa prior to deletion.";
697 throw new ReferencedObjectUndeletableException(message);
698 }
699 }
700
701
702 // TaxonDescription
703 Set<TaxonDescription> descriptions = taxon.getDescriptions();
704
705 for (TaxonDescription desc: descriptions){
706 if (config.isDeleteDescriptions()){
707 //TODO use description delete configurator ?
708 //FIXME check if description is ALWAYS deletable
709 descriptionService.delete(desc);
710 }else{
711 if (desc.getDescribedSpecimenOrObservations().size()>0){
712 String message = "Taxon can't be deleted as it is used in a TaxonDescription" +
713 " which also describes specimens or abservations";
714 throw new ReferencedObjectUndeletableException(message);
715 }
716 }
717 }
718
719
720 //check references with only reverse mapping
721 Set<CdmBase> referencingObjects = genericDao.getReferencingObjects(taxon);
722 for (CdmBase referencingObject : referencingObjects){
723 //IIdentificationKeys (Media, Polytomous, MultiAccess)
724 if (HibernateProxyHelper.isInstanceOf(referencingObject, IIdentificationKey.class)){
725 String message = "Taxon can't be deleted as it is used in an identification key. Remove from identification key prior to deleting this name";
726 message = String.format(message, CdmBase.deproxy(referencingObject, DerivedUnitBase.class).getTitleCache());
727 throw new ReferencedObjectUndeletableException(message);
728 }
729
730
731 //PolytomousKeyNode
732 if (referencingObject.isInstanceOf(PolytomousKeyNode.class)){
733 String message = "Taxon can't be deleted as it is used in polytomous key node";
734 throw new ReferencedObjectUndeletableException(message);
735 }
736
737 //TaxonInteraction
738 if (referencingObject.isInstanceOf(TaxonInteraction.class)){
739 String message = "Taxon can't be deleted as it is used in taxonInteraction#taxon2";
740 throw new ReferencedObjectUndeletableException(message);
741 }
742 }
743
744
745 //TaxonNameBase
746 if (config.isDeleteNameIfPossible()){
747 try {
748 nameService.delete(taxon.getName(), config.getNameDeletionConfig());
749 } catch (ReferencedObjectUndeletableException e) {
750 //do nothing
751 if (logger.isDebugEnabled()){logger.debug("Name could not be deleted");}
752 }
753 }
754
755 }
756
757 /* (non-Javadoc)
758 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonym(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon, boolean, boolean)
759 */
760 @Transactional(readOnly = false)
761 @Override
762 public void deleteSynonym(Synonym synonym, Taxon taxon, boolean removeNameIfPossible,boolean newHomotypicGroupIfNeeded) {
763 if (synonym == null){
764 return;
765 }
766 synonym = CdmBase.deproxy(dao.merge(synonym), Synonym.class);
767
768 //remove synonymRelationship
769 Set<Taxon> taxonSet = new HashSet<Taxon>();
770 if (taxon != null){
771 taxonSet.add(taxon);
772 }else{
773 taxonSet.addAll(synonym.getAcceptedTaxa());
774 }
775 for (Taxon relatedTaxon : taxonSet){
776 // dao.deleteSynonymRelationships(synonym, relatedTaxon);
777 relatedTaxon.removeSynonym(synonym, newHomotypicGroupIfNeeded);
778 }
779 this.saveOrUpdate(synonym);
780
781 //TODO remove name from homotypical group?
782
783 //remove synonym (if necessary)
784 if (synonym.getSynonymRelations().isEmpty()){
785 TaxonNameBase<?,?> name = synonym.getName();
786 synonym.setName(null);
787 dao.delete(synonym);
788
789 //remove name if possible (and required)
790 if (name != null && removeNameIfPossible){
791 try{
792 nameService.delete(name, new NameDeletionConfigurator());
793 }catch (DataChangeNoRollbackException ex){
794 if (logger.isDebugEnabled())logger.debug("Name wasn't deleted as it is referenced");
795 }
796 }
797 }
798 }
799
800
801 /* (non-Javadoc)
802 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findIdenticalTaxonNameIds(java.util.List)
803 */
804 public List<TaxonNameBase> findIdenticalTaxonNameIds(List<String> propertyPath) {
805
806 return this.dao.findIdenticalNamesNew(propertyPath);
807 }
808
809 /* (non-Javadoc)
810 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getPhylumName(eu.etaxonomy.cdm.model.name.TaxonNameBase)
811 */
812 public String getPhylumName(TaxonNameBase name){
813 return this.dao.getPhylumName(name);
814 }
815
816 /* (non-Javadoc)
817 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonymRelationships(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon)
818 */
819 public long deleteSynonymRelationships(Synonym syn, Taxon taxon) {
820 return dao.deleteSynonymRelationships(syn, taxon);
821 }
822
823 /* (non-Javadoc)
824 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonymRelationships(eu.etaxonomy.cdm.model.taxon.Synonym)
825 */
826 public long deleteSynonymRelationships(Synonym syn) {
827 return dao.deleteSynonymRelationships(syn, null);
828 }
829
830
831 /* (non-Javadoc)
832 * @see eu.etaxonomy.cdm.api.service.ITaxonService#listSynonymRelationships(eu.etaxonomy.cdm.model.taxon.TaxonBase, eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List, eu.etaxonomy.cdm.model.common.RelationshipBase.Direction)
833 */
834 public List<SynonymRelationship> listSynonymRelationships(
835 TaxonBase taxonBase, SynonymRelationshipType type, Integer pageSize, Integer pageNumber,
836 List<OrderHint> orderHints, List<String> propertyPaths, Direction direction) {
837 Integer numberOfResults = dao.countSynonymRelationships(taxonBase, type, direction);
838
839 List<SynonymRelationship> results = new ArrayList<SynonymRelationship>();
840 if(numberOfResults > 0) { // no point checking again
841 results = dao.getSynonymRelationships(taxonBase, type, pageSize, pageNumber, orderHints, propertyPaths, direction);
842 }
843 return results;
844 }
845
846 /* (non-Javadoc)
847 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findBestMatchingTaxon(java.lang.String)
848 */
849 @Override
850 public Taxon findBestMatchingTaxon(String taxonName) {
851 MatchingTaxonConfigurator config = MatchingTaxonConfigurator.NewInstance();
852 config.setTaxonNameTitle(taxonName);
853 return findBestMatchingTaxon(config);
854 }
855
856
857
858 @Override
859 public Taxon findBestMatchingTaxon(MatchingTaxonConfigurator config) {
860
861 Taxon bestCandidate = null;
862 try{
863 // 1. search for acceptet taxa
864 List<TaxonBase> taxonList = dao.findByNameTitleCache(true, false, config.getTaxonNameTitle(), null, MatchMode.EXACT, null, 0, null, null);
865 boolean bestCandidateMatchesSecUuid = false;
866 boolean bestCandidateIsInClassification = false;
867 int countEqualCandidates = 0;
868 for(TaxonBase taxonBaseCandidate : taxonList){
869 if(taxonBaseCandidate instanceof Taxon){
870 Taxon newCanditate = CdmBase.deproxy(taxonBaseCandidate, Taxon.class);
871 boolean newCandidateMatchesSecUuid = isMatchesSecUuid(newCanditate, config);
872 if (! newCandidateMatchesSecUuid && config.isOnlyMatchingSecUuid() ){
873 continue;
874 }else if(newCandidateMatchesSecUuid && ! bestCandidateMatchesSecUuid){
875 bestCandidate = newCanditate;
876 countEqualCandidates = 1;
877 bestCandidateMatchesSecUuid = true;
878 continue;
879 }
880
881 boolean newCandidateInClassification = isInClassification(newCanditate, config);
882 if (! newCandidateInClassification && config.isOnlyMatchingClassificationUuid()){
883 continue;
884 }else if (newCandidateInClassification && ! bestCandidateIsInClassification){
885 bestCandidate = newCanditate;
886 countEqualCandidates = 1;
887 bestCandidateIsInClassification = true;
888 continue;
889 }
890 if (bestCandidate == null){
891 bestCandidate = newCanditate;
892 countEqualCandidates = 1;
893 continue;
894 }
895
896 }else{ //not Taxon.class
897 continue;
898 }
899 countEqualCandidates++;
900
901 }
902 if (bestCandidate != null){
903 if(countEqualCandidates > 1){
904 logger.info(countEqualCandidates + " equally matching TaxonBases found, using first accepted Taxon: " + bestCandidate.getTitleCache());
905 return bestCandidate;
906 } else {
907 logger.info("using accepted Taxon: " + bestCandidate.getTitleCache());
908 return bestCandidate;
909 }
910 }
911
912
913 // 2. search for synonyms
914 if (config.isIncludeSynonyms()){
915 List<TaxonBase> synonymList = dao.findByNameTitleCache(false, true, config.getTaxonNameTitle(), null, MatchMode.EXACT, null, 0, null, null);
916 for(TaxonBase taxonBase : synonymList){
917 if(taxonBase instanceof Synonym){
918 Synonym synonym = CdmBase.deproxy(taxonBase, Synonym.class);
919 Set<Taxon> acceptetdCandidates = synonym.getAcceptedTaxa();
920 if(!acceptetdCandidates.isEmpty()){
921 bestCandidate = acceptetdCandidates.iterator().next();
922 if(acceptetdCandidates.size() == 1){
923 logger.info(acceptetdCandidates.size() + " Accepted taxa found for synonym " + taxonBase.getTitleCache() + ", using first one: " + bestCandidate.getTitleCache());
924 return bestCandidate;
925 } else {
926 logger.info("using accepted Taxon " + bestCandidate.getTitleCache() + "for synonym " + taxonBase.getTitleCache());
927 return bestCandidate;
928 }
929 //TODO extend method: search using treeUUID, using SecUUID, first find accepted then include synonyms until a matching taxon is found
930 }
931 }
932 }
933 }
934
935 } catch (Exception e){
936 logger.error(e);
937 }
938
939 return bestCandidate;
940 }
941
942 private boolean isInClassification(Taxon taxon, MatchingTaxonConfigurator config) {
943 UUID configClassificationUuid = config.getClassificationUuid();
944 if (configClassificationUuid == null){
945 return false;
946 }
947 for (TaxonNode node : taxon.getTaxonNodes()){
948 UUID classUuid = node.getClassification().getUuid();
949 if (configClassificationUuid.equals(classUuid)){
950 return true;
951 }
952 }
953 return false;
954 }
955
956 private boolean isMatchesSecUuid(Taxon taxon, MatchingTaxonConfigurator config) {
957 UUID configSecUuid = config.getSecUuid();
958 if (configSecUuid == null){
959 return false;
960 }
961 UUID taxonSecUuid = (taxon.getSec() == null)? null : taxon.getSec().getUuid();
962 return configSecUuid.equals(taxonSecUuid);
963 }
964
965 /* (non-Javadoc)
966 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findBestMatchingSynonym(java.lang.String)
967 */
968 @Override
969 public Synonym findBestMatchingSynonym(String taxonName) {
970 List<TaxonBase> synonymList = dao.findByNameTitleCache(false, true, taxonName, null, MatchMode.EXACT, null, 0, null, null);
971 if(! synonymList.isEmpty()){
972 Synonym result = CdmBase.deproxy(synonymList.iterator().next(), Synonym.class);
973 if(synonymList.size() == 1){
974 logger.info(synonymList.size() + " Synonym found " + result.getTitleCache() );
975 return result;
976 } else {
977 logger.info("Several matching synonyms found. Using first: " + result.getTitleCache());
978 return result;
979 }
980 }
981 return null;
982 }
983
984
985 /* (non-Javadoc)
986 * @see eu.etaxonomy.cdm.api.service.ITaxonService#moveSynonymToAnotherTaxon(eu.etaxonomy.cdm.model.taxon.SynonymRelationship, eu.etaxonomy.cdm.model.taxon.Taxon, boolean, eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType, eu.etaxonomy.cdm.model.reference.Reference, java.lang.String, boolean)
987 */
988 @Override
989 public SynonymRelationship moveSynonymToAnotherTaxon(SynonymRelationship oldSynonymRelation, Taxon newTaxon, boolean moveHomotypicGroup,
990 SynonymRelationshipType newSynonymRelationshipType, Reference reference, String referenceDetail, boolean keepReference) throws HomotypicalGroupChangeException {
991
992 Synonym synonym = oldSynonymRelation.getSynonym();
993 Taxon fromTaxon = oldSynonymRelation.getAcceptedTaxon();
994 //TODO what if there is no name ?? Concepts may be cached (e.g. via TCS import)
995 TaxonNameBase<?,?> synonymName = synonym.getName();
996 TaxonNameBase<?,?> fromTaxonName = fromTaxon.getName();
997 //set default relationship type
998 if (newSynonymRelationshipType == null){
999 newSynonymRelationshipType = SynonymRelationshipType.HETEROTYPIC_SYNONYM_OF();
1000 }
1001 boolean newRelTypeIsHomotypic = newSynonymRelationshipType.equals(SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF());
1002
1003 HomotypicalGroup homotypicGroup = synonymName.getHomotypicalGroup();
1004 int hgSize = homotypicGroup.getTypifiedNames().size();
1005 boolean isSingleInGroup = !(hgSize > 1);
1006
1007 if (! isSingleInGroup){
1008 boolean isHomotypicToAccepted = synonymName.isHomotypic(fromTaxonName);
1009 boolean hasHomotypicSynonymRelatives = isHomotypicToAccepted ? hgSize > 2 : hgSize > 1;
1010 if (isHomotypicToAccepted){
1011 String message = "Synonym is in homotypic group with accepted taxon%s. First remove synonym from homotypic group of accepted taxon before moving to other taxon.";
1012 String homotypicRelatives = hasHomotypicSynonymRelatives ? " and other synonym(s)":"";
1013 message = String.format(message, homotypicRelatives);
1014 throw new HomotypicalGroupChangeException(message);
1015 }
1016 if (! moveHomotypicGroup){
1017 String message = "Synonym is in homotypic group with other synonym(s). Either move complete homotypic group or remove synonym from homotypic group prior to moving to other taxon.";
1018 throw new HomotypicalGroupChangeException(message);
1019 }
1020 }else{
1021 moveHomotypicGroup = true; //single synonym always allows to moveCompleteGroup
1022 }
1023 // Assert.assertTrue("Synonym can only be moved with complete homotypic group", moveHomotypicGroup);
1024
1025 SynonymRelationship result = null;
1026 //move all synonyms to new taxon
1027 List<Synonym> homotypicSynonyms = fromTaxon.getSynonymsInGroup(homotypicGroup);
1028 for (Synonym syn: homotypicSynonyms){
1029 Set<SynonymRelationship> synRelations = syn.getSynonymRelations();
1030 for (SynonymRelationship synRelation : synRelations){
1031 if (fromTaxon.equals(synRelation.getAcceptedTaxon())){
1032 Reference<?> newReference = reference;
1033 if (newReference == null && keepReference){
1034 newReference = synRelation.getCitation();
1035 }
1036 String newRefDetail = referenceDetail;
1037 if (newRefDetail == null && keepReference){
1038 newRefDetail = synRelation.getCitationMicroReference();
1039 }
1040 SynonymRelationship newSynRelation = newTaxon.addSynonym(syn, newSynonymRelationshipType, newReference, newRefDetail);
1041 fromTaxon.removeSynonymRelation(synRelation, false);
1042 //
1043 //change homotypic group of synonym if relType is 'homotypic'
1044 // if (newRelTypeIsHomotypic){
1045 // newTaxon.getName().getHomotypicalGroup().addTypifiedName(syn.getName());
1046 // }
1047 //set result
1048 if (synRelation.equals(oldSynonymRelation)){
1049 result = newSynRelation;
1050 }
1051 }
1052 }
1053
1054 }
1055 saveOrUpdate(newTaxon);
1056 //Assert that there is a result
1057 if (result == null){
1058 String message = "Old synonym relation could not be transformed into new relation. This should not happen.";
1059 throw new IllegalStateException(message);
1060 }
1061 return result;
1062 }
1063
1064 /* (non-Javadoc)
1065 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getUuidAndTitleCacheTaxon()
1066 */
1067 @Override
1068 public List<UuidAndTitleCache<TaxonBase>> getUuidAndTitleCacheTaxon() {
1069 return dao.getUuidAndTitleCacheTaxon();
1070 }
1071
1072 /* (non-Javadoc)
1073 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getUuidAndTitleCacheSynonym()
1074 */
1075 @Override
1076 public List<UuidAndTitleCache<TaxonBase>> getUuidAndTitleCacheSynonym() {
1077 return dao.getUuidAndTitleCacheSynonym();
1078 }
1079
1080 @Override
1081 public Pager<SearchResult<TaxonBase>> findByDescriptionElementFullText(Class<? extends DescriptionElementBase> clazz, String queryString, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints,
1082 List<String> propertyPaths) throws CorruptIndexException, IOException, ParseException {
1083
1084 String luceneQueryTemplate = "titleCache:%1$s OR multilanguageText.text:%1$s OR name:%1$s";
1085 String luceneQuery = String.format(luceneQueryTemplate, queryString);
1086
1087 LuceneSearch luceneSearch = new LuceneSearch(getSession(), clazz);
1088 TopDocs topDocsResultSet = luceneSearch.executeSearch(luceneQuery);
1089 List<SearchResult<TaxonBase>> searchResults = searchResultBuilder.createResultSetFromIds(luceneSearch, topDocsResultSet, dao, "inDescription.taxon.id");
1090
1091 return new DefaultPagerImpl<SearchResult<TaxonBase>>(pageNumber, searchResults.size(), pageSize, searchResults);
1092
1093 }
1094
1095 public List<Synonym> createInferredSynonyms(Taxon taxon, Classification classification, SynonymRelationshipType type){
1096 List <Synonym> inferredSynonyms = new ArrayList<Synonym>();
1097 List<Synonym> inferredSynonymsToBeRemoved = new ArrayList<Synonym>();
1098
1099 HashMap <UUID, ZoologicalName> zooHashMap = new HashMap<UUID, ZoologicalName>();
1100
1101 UUID uuid= taxon.getName().getUuid();
1102 ZoologicalName taxonName = getZoologicalName(uuid, zooHashMap);
1103 String epithetOfTaxon = null;
1104 String infragenericEpithetOfTaxon = null;
1105 String infraspecificEpithetOfTaxon = null;
1106 if (taxonName.isSpecies()){
1107 epithetOfTaxon= taxonName.getSpecificEpithet();
1108 } else if (taxonName.isInfraGeneric()){
1109 infragenericEpithetOfTaxon = taxonName.getInfraGenericEpithet();
1110 } else if (taxonName.isInfraSpecific()){
1111 infraspecificEpithetOfTaxon = taxonName.getInfraSpecificEpithet();
1112 }
1113 String genusOfTaxon = taxonName.getGenusOrUninomial();
1114 Set<TaxonNode> nodes = taxon.getTaxonNodes();
1115 List<String> taxonNames = new ArrayList<String>();
1116
1117 for (TaxonNode node: nodes){
1118 // HashMap<String, String> synonymsGenus = new HashMap<String, String>(); // Changed this to be able to store the idInSource to a genusName
1119 // List<String> synonymsEpithet = new ArrayList<String>();
1120
1121 if (node.getClassification().equals(classification)){
1122 if (!node.isTopmostNode()){
1123 TaxonNode parent = (TaxonNode)node.getParent();
1124 parent = (TaxonNode)HibernateProxyHelper.deproxy(parent);
1125 TaxonNameBase parentName = parent.getTaxon().getName();
1126 ZoologicalName zooParentName = HibernateProxyHelper.deproxy(parentName, ZoologicalName.class);
1127 Taxon parentTaxon = (Taxon)HibernateProxyHelper.deproxy(parent.getTaxon());
1128 Rank rankOfTaxon = taxonName.getRank();
1129
1130
1131 //create inferred synonyms for species, subspecies or subgenus
1132 if (parentName.isGenus() || parentName.isSpecies() || parentName.getRank().equals(Rank.SUBGENUS())){
1133
1134 Synonym inferredEpithet;
1135 Synonym inferredGenus = null;
1136 Synonym potentialCombination;
1137
1138 List<String> propertyPaths = new ArrayList<String>();
1139 propertyPaths.add("synonym");
1140 propertyPaths.add("synonym.name");
1141 List<OrderHint> orderHints = new ArrayList<OrderHint>();
1142 orderHints.add(new OrderHint("relatedFrom.titleCache", SortOrder.ASCENDING));
1143
1144 List<SynonymRelationship> synonymRelationshipsOfGenus = dao.getSynonyms(parentTaxon, SynonymRelationshipType.HETEROTYPIC_SYNONYM_OF(), null, null,orderHints,propertyPaths);
1145 List<SynonymRelationship> synonymRelationshipsOfTaxon= dao.getSynonyms(taxon, SynonymRelationshipType.HETEROTYPIC_SYNONYM_OF(), null, null,orderHints,propertyPaths);
1146
1147 if (type.equals(SynonymRelationshipType.INFERRED_EPITHET_OF())){
1148
1149 for (SynonymRelationship synonymRelationOfGenus:synonymRelationshipsOfGenus){
1150 TaxonNameBase synName;
1151 ZoologicalName inferredSynName;
1152 Synonym syn = synonymRelationOfGenus.getSynonym();
1153 HibernateProxyHelper.deproxy(syn);
1154
1155 // Determine the idInSource
1156 String idInSourceSyn = getIdInSource(syn);
1157 String idInSourceTaxon = getIdInSource(taxon);
1158 // Determine the sourceReference
1159 Reference sourceReference = syn.getSec();
1160
1161 synName = syn.getName();
1162 ZoologicalName zooName = getZoologicalName(synName.getUuid(), zooHashMap);
1163 String synGenusName = zooName.getGenusOrUninomial();
1164 String synInfraGenericEpithet = null;
1165 String synSpecificEpithet = null;
1166 if (zooName.isInfraGeneric()){
1167 synInfraGenericEpithet = zooName.getInfraGenericEpithet();
1168 } else if (zooName.isSpecies()){
1169 synSpecificEpithet = zooName.getSpecificEpithet();
1170 }
1171
1172 /* if (synGenusName != null && !synonymsGenus.containsKey(synGenusName)){
1173 synonymsGenus.put(synGenusName, idInSource);
1174 }*/
1175
1176 inferredSynName = ZoologicalName.NewInstance(rankOfTaxon);
1177
1178 // DEBUG TODO: for subgenus or subspecies the infrageneric or infraspecific epithet should be used!!!
1179 if (epithetOfTaxon == null && infragenericEpithetOfTaxon == null && infraspecificEpithetOfTaxon == null) {
1180 logger.error("This specificEpithet is NULL" + taxon.getTitleCache());
1181 }
1182 inferredSynName.setGenusOrUninomial(synGenusName);
1183 if (inferredSynName.isSpecies()){
1184 if (parentName.isInfraGeneric()){
1185 inferredSynName.setInfraGenericEpithet(synInfraGenericEpithet);
1186 }
1187 inferredSynName.setSpecificEpithet(epithetOfTaxon);
1188 } else if (inferredSynName.isInfraGeneric()) {
1189 inferredSynName.setInfraGenericEpithet(infragenericEpithetOfTaxon);
1190 } else if (inferredSynName.isInfraSpecific()){
1191 inferredSynName.setSpecificEpithet(synSpecificEpithet);
1192 inferredSynName.setInfraSpecificEpithet(infraspecificEpithetOfTaxon);
1193 }
1194
1195 inferredEpithet = Synonym.NewInstance(inferredSynName, null);
1196
1197 // Set the sourceReference
1198 inferredEpithet.setSec(sourceReference);
1199
1200 /* Add the original source
1201 if (idInSource != null) {
1202 IdentifiableSource originalSource = IdentifiableSource.NewInstance(idInSource, "InferredEpithetOf", syn.getSec(), null);
1203
1204 // Add the citation
1205 Reference citation = getCitation(syn);
1206 if (citation != null) {
1207 originalSource.setCitation(citation);
1208 inferredEpithet.addSource(originalSource);
1209 }
1210 }*/
1211 String taxonId = idInSourceTaxon+ "; " + idInSourceSyn;
1212
1213 IdentifiableSource originalSource;
1214 originalSource = IdentifiableSource.NewInstance(taxonId, INFERRED_EPITHET_NAMESPACE, sourceReference, null);
1215
1216 inferredEpithet.addSource(originalSource);
1217
1218 originalSource = IdentifiableSource.NewInstance(taxonId, INFERRED_EPITHET_NAMESPACE, sourceReference, null);
1219
1220 inferredSynName.addSource(originalSource);
1221
1222
1223
1224 taxon.addSynonym(inferredEpithet, SynonymRelationshipType.INFERRED_EPITHET_OF());
1225 inferredSynonyms.add(inferredEpithet);
1226 inferredSynName.generateTitle();
1227 zooHashMap.put(inferredSynName.getUuid(), inferredSynName);
1228 taxonNames.add(inferredSynName.getNameCache());
1229 }
1230
1231 if (!taxonNames.isEmpty()){
1232 List<String> synNotInCDM = dao.taxaByNameNotInDB(taxonNames);
1233 ZoologicalName name;
1234 if (!synNotInCDM.isEmpty()){
1235 inferredSynonymsToBeRemoved.clear();
1236
1237 for (Synonym syn :inferredSynonyms){
1238 name = getZoologicalName(syn.getName().getUuid(), zooHashMap);
1239 if (!synNotInCDM.contains(name.getNameCache())){
1240 inferredSynonymsToBeRemoved.add(syn);
1241 }
1242 }
1243
1244 // Remove identified Synonyms from inferredSynonyms
1245 for (Synonym synonym : inferredSynonymsToBeRemoved) {
1246 inferredSynonyms.remove(synonym);
1247 }
1248 }
1249 }
1250
1251 }else if (type.equals(SynonymRelationshipType.INFERRED_GENUS_OF())){
1252
1253
1254 for (SynonymRelationship synonymRelationOfTaxon:synonymRelationshipsOfTaxon){
1255 TaxonNameBase synName;
1256 ZoologicalName inferredSynName;
1257
1258 Synonym syn = synonymRelationOfTaxon.getSynonym();
1259 synName =syn.getName();
1260 HibernateProxyHelper.deproxy(syn);
1261
1262 // Determine the idInSource
1263 String idInSourceSyn = getIdInSource(syn);
1264 String idInSourceTaxon = getIdInSource(taxon);
1265 // Determine the sourceReference
1266 Reference sourceReference = syn.getSec();
1267
1268 synName = syn.getName();
1269 ZoologicalName synZooName = getZoologicalName(synName.getUuid(), zooHashMap);
1270 String synSpeciesEpithetName = synZooName.getSpecificEpithet();
1271 /* if (synonymsEpithet != null && !synonymsEpithet.contains(synSpeciesEpithetName)){
1272 synonymsEpithet.add(synSpeciesEpithetName);
1273 }*/
1274
1275 inferredSynName = ZoologicalName.NewInstance(rankOfTaxon);
1276 //TODO:differ between parent is genus and taxon is species, parent is subgenus and taxon is species, parent is species and taxon is subspecies and parent is genus and taxon is subgenus...
1277
1278
1279 inferredSynName.setGenusOrUninomial(genusOfTaxon);
1280
1281 if (taxonName.isSpecies()){
1282 inferredSynName.setSpecificEpithet(synSpeciesEpithetName);
1283 if (zooParentName.isInfraGeneric()){
1284 inferredSynName.setInfraGenericEpithet(zooParentName.getInfraGenericEpithet());
1285 }
1286 }
1287 if (taxonName.isInfraSpecific()){
1288 inferredSynName.setSpecificEpithet(epithetOfTaxon);
1289 inferredSynName.setInfraSpecificEpithet(synZooName.getInfraGenericEpithet());
1290 }
1291 if (taxonName.isInfraGeneric()){
1292 inferredSynName.setInfraGenericEpithet(synZooName.getInfraGenericEpithet());
1293 }
1294
1295 inferredGenus = Synonym.NewInstance(inferredSynName, null);
1296
1297 // Set the sourceReference
1298 inferredGenus.setSec(sourceReference);
1299
1300 // Add the original source
1301 if (idInSourceSyn != null && idInSourceTaxon != null) {
1302 IdentifiableSource originalSource = IdentifiableSource.NewInstance(idInSourceSyn + "; " + idInSourceTaxon, INFERRED_GENUS_NAMESPACE, sourceReference, null);
1303 inferredGenus.addSource(originalSource);
1304
1305 originalSource = IdentifiableSource.NewInstance(idInSourceSyn + "; " + idInSourceTaxon, INFERRED_GENUS_NAMESPACE, sourceReference, null);
1306 inferredSynName.addSource(originalSource);
1307
1308 }
1309
1310 taxon.addSynonym(inferredGenus, SynonymRelationshipType.INFERRED_GENUS_OF());
1311 inferredSynonyms.add(inferredGenus);
1312 inferredSynName.generateTitle();
1313 zooHashMap.put(inferredSynName.getUuid(), inferredSynName);
1314 taxonNames.add(inferredSynName.getNameCache());
1315 }
1316
1317 if (!taxonNames.isEmpty()){
1318 List<String> synNotInCDM = dao.taxaByNameNotInDB(taxonNames);
1319 ZoologicalName name;
1320 if (!synNotInCDM.isEmpty()){
1321 inferredSynonymsToBeRemoved.clear();
1322
1323 for (Synonym syn :inferredSynonyms){
1324 name = getZoologicalName(syn.getName().getUuid(), zooHashMap);
1325 if (!synNotInCDM.contains(name.getNameCache())){
1326 inferredSynonymsToBeRemoved.add(syn);
1327 }
1328 }
1329
1330 // Remove identified Synonyms from inferredSynonyms
1331 for (Synonym synonym : inferredSynonymsToBeRemoved) {
1332 inferredSynonyms.remove(synonym);
1333 }
1334 }
1335 }
1336
1337 }else if (type.equals(SynonymRelationshipType.POTENTIAL_COMBINATION_OF())){
1338
1339 Reference sourceReference = null; // TODO: Determination of sourceReference is redundant
1340 ZoologicalName inferredSynName;
1341 //for all synonyms of the parent...
1342 for (SynonymRelationship synonymRelationOfGenus:synonymRelationshipsOfGenus){
1343 TaxonNameBase synName;
1344 Synonym synParent = synonymRelationOfGenus.getSynonym();
1345 synName = synParent.getName();
1346
1347 HibernateProxyHelper.deproxy(synParent);
1348
1349 // Set the sourceReference
1350 sourceReference = synParent.getSec();
1351
1352 // Determine the idInSource
1353 String idInSourceParent = getIdInSource(synParent);
1354
1355 ZoologicalName parentZooName = getZoologicalName(synName.getUuid(), zooHashMap);
1356 String synParentGenus = parentZooName.getGenusOrUninomial();
1357 String synParentInfragenericName = null;
1358 String synParentSpecificEpithet = null;
1359
1360 if (parentZooName.isInfraGeneric()){
1361 synParentInfragenericName = parentZooName.getInfraGenericEpithet();
1362 }
1363 if (parentZooName.isSpecies()){
1364 synParentSpecificEpithet = parentZooName.getSpecificEpithet();
1365 }
1366
1367 /* if (synGenusName != null && !synonymsGenus.containsKey(synGenusName)){
1368 synonymsGenus.put(synGenusName, idInSource);
1369 }*/
1370
1371 //for all synonyms of the taxon
1372
1373 for (SynonymRelationship synonymRelationOfTaxon:synonymRelationshipsOfTaxon){
1374
1375 Synonym syn = synonymRelationOfTaxon.getSynonym();
1376 HibernateProxyHelper.deproxy(syn);
1377
1378 // Set sourceReference
1379 sourceReference = syn.getSec();
1380
1381 ZoologicalName zooName = getZoologicalName(syn.getName().getUuid(), zooHashMap);
1382 String synTaxonSpecificEpithet = zooName.getSpecificEpithet();
1383 String synTaxonInfragenericName = null;
1384 String synTaxonInfraSpecificName= null;
1385
1386 if (parentZooName.isSpecies()){
1387 synTaxonInfraSpecificName = zooName.getInfraSpecificEpithet();
1388 }
1389 if (zooName.isInfraGeneric()){
1390 synTaxonInfragenericName = zooName.getInfraGenericEpithet();
1391 }
1392
1393 /*if (epithetName != null && !synonymsEpithet.contains(epithetName)){
1394 synonymsEpithet.add(epithetName);
1395 }*/
1396
1397 //create potential combinations...
1398 inferredSynName = ZoologicalName.NewInstance(rankOfTaxon);
1399
1400 inferredSynName.setGenusOrUninomial(synParentGenus);
1401 if (taxonName.isSpecies()){
1402 inferredSynName.setSpecificEpithet(synTaxonSpecificEpithet);
1403 if (parentName.isInfraGeneric()){
1404 inferredSynName.setInfraGenericEpithet(synTaxonInfragenericName);
1405 }
1406 }
1407 if (taxonName.isInfraSpecific()){
1408 inferredSynName.setSpecificEpithet(synParentSpecificEpithet);
1409 inferredSynName.setInfraSpecificEpithet(synTaxonInfraSpecificName);
1410 }
1411 if (taxonName.isInfraGeneric()){
1412 inferredSynName.setInfraGenericEpithet(synTaxonInfragenericName);
1413 }
1414
1415
1416 potentialCombination = Synonym.NewInstance(inferredSynName, null);
1417
1418 // Set the sourceReference
1419 potentialCombination.setSec(sourceReference);
1420
1421
1422 // Determine the idInSource
1423 String idInSourceSyn= getIdInSource(syn);
1424
1425 if (idInSourceParent != null && idInSourceSyn != null) {
1426 // IdentifiableSource originalSourceGenus = IdentifiableSource.NewInstance(idInSourceSyn + "; " + idInSourceParent, POTENTIAL_COMBINATION_NAMESPACE, sourceReference, null);
1427 // inferredGenus.addSource(originalSourceGenus);
1428
1429 IdentifiableSource originalSource = IdentifiableSource.NewInstance(idInSourceSyn + "; " + idInSourceParent, POTENTIAL_COMBINATION_NAMESPACE, sourceReference, null);
1430 inferredSynName.addSource(originalSource);
1431
1432 }
1433
1434 // if (idInSourceTaxon != null) {
1435 // IdentifiableSource originalSourceTaxon = IdentifiableSource.NewInstance(idInSourceTaxon, "PotentialCombinationOf", sourceReference, null);
1436 // if (sourceReference != null) {
1437 // originalSourceTaxon.setCitation(sourceReference);
1438 // potentialCombination.addSource(originalSourceTaxon);
1439 // }
1440 // }
1441 // if (idInSourceParent != null){
1442 // IdentifiableSource originalSourceParent = IdentifiableSource.NewInstance(idInSourceParent, "PotentialCombinationOf", sourceReference, null);
1443 // if (sourceReference != null) {
1444 // originalSourceParent.setCitation(sourceReference);
1445 // potentialCombination.addSource(originalSourceParent);
1446 // }
1447 // }
1448
1449 // Add the citation
1450
1451
1452
1453 inferredSynonyms.add(potentialCombination);
1454 inferredSynName.generateTitle();
1455 zooHashMap.put(inferredSynName.getUuid(), inferredSynName);
1456 taxonNames.add(inferredSynName.getNameCache());
1457
1458 }
1459
1460 }
1461 if (!taxonNames.isEmpty()){
1462 List<String> synNotInCDM = dao.taxaByNameNotInDB(taxonNames);
1463 ZoologicalName name;
1464 if (!synNotInCDM.isEmpty()){
1465 inferredSynonymsToBeRemoved.clear();
1466 for (Synonym syn :inferredSynonyms){
1467 try{
1468 name = (ZoologicalName) syn.getName();
1469 }catch (ClassCastException e){
1470 name = getZoologicalName(syn.getName().getUuid(), zooHashMap);
1471 }
1472 if (!synNotInCDM.contains(name.getNameCache())){
1473 inferredSynonymsToBeRemoved.add(syn);
1474 }
1475 }
1476 // Remove identified Synonyms from inferredSynonyms
1477 for (Synonym synonym : inferredSynonymsToBeRemoved) {
1478 inferredSynonyms.remove(synonym);
1479 }
1480 }
1481 }
1482 }
1483 }else {
1484 logger.info("The synonymrelationship type is not defined.");
1485 return inferredSynonyms;
1486 }
1487 }
1488 }
1489
1490 }
1491
1492 return inferredSynonyms;
1493 }
1494
1495 /**
1496 * Returns an existing ZoologicalName or extends an internal hashmap if it does not exist.
1497 * Very likely only useful for createInferredSynonyms().
1498 * @param uuid
1499 * @param zooHashMap
1500 * @return
1501 */
1502 private ZoologicalName getZoologicalName(UUID uuid, HashMap <UUID, ZoologicalName> zooHashMap) {
1503 ZoologicalName taxonName =nameDao.findZoologicalNameByUUID(uuid);
1504 if (taxonName == null) {
1505 taxonName = zooHashMap.get(uuid);
1506 }
1507 return taxonName;
1508 }
1509
1510 /**
1511 * Returns the idInSource for a given Synonym.
1512 * @param syn
1513 */
1514 private String getIdInSource(TaxonBase taxonBase) {
1515 String idInSource = null;
1516 Set<IdentifiableSource> sources = taxonBase.getSources();
1517 if (sources.size() == 1) {
1518 IdentifiableSource source = sources.iterator().next();
1519 if (source != null) {
1520 idInSource = source.getIdInSource();
1521 }
1522 } else if (sources.size() > 1) {
1523 int count = 1;
1524 idInSource = "";
1525 for (IdentifiableSource source : sources) {
1526 idInSource += source.getIdInSource();
1527 if (count < sources.size()) {
1528 idInSource += "; ";
1529 }
1530 count++;
1531 }
1532 }
1533
1534 return idInSource;
1535 }
1536
1537
1538 /**
1539 * Returns the citation for a given Synonym.
1540 * @param syn
1541 */
1542 private Reference getCitation(Synonym syn) {
1543 Reference citation = null;
1544 Set<IdentifiableSource> sources = syn.getSources();
1545 if (sources.size() == 1) {
1546 IdentifiableSource source = sources.iterator().next();
1547 if (source != null) {
1548 citation = source.getCitation();
1549 }
1550 } else if (sources.size() > 1) {
1551 logger.warn("This Synonym has more than one source: " + syn.getUuid() + " (" + syn.getTitleCache() +")");
1552 }
1553
1554 return citation;
1555 }
1556
1557 public List<Synonym> createAllInferredSynonyms(Taxon taxon, Classification tree){
1558 List <Synonym> inferredSynonyms = new ArrayList<Synonym>();
1559
1560 inferredSynonyms.addAll(createInferredSynonyms(taxon, tree, SynonymRelationshipType.INFERRED_EPITHET_OF()));
1561 inferredSynonyms.addAll(createInferredSynonyms(taxon, tree, SynonymRelationshipType.INFERRED_GENUS_OF()));
1562 inferredSynonyms.addAll(createInferredSynonyms(taxon, tree, SynonymRelationshipType.POTENTIAL_COMBINATION_OF()));
1563
1564 return inferredSynonyms;
1565 }
1566
1567
1568
1569
1570 }