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