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