make update title cache writable
[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 @Transactional(readOnly = false)
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#findTaxonByUuid(UUID uuid, List<String> propertyPaths)
646 */
647 public TaxonBase findTaxonByUuid(UUID uuid, List<String> propertyPaths){
648 return this.dao.findByUuid(uuid, null ,propertyPaths);
649 }
650
651 /* (non-Javadoc)
652 * @see eu.etaxonomy.cdm.api.service.ITaxonService#countAllRelationships()
653 */
654 public int countAllRelationships() {
655 return this.dao.countAllRelationships();
656 }
657
658
659
660
661 /* (non-Javadoc)
662 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findIdenticalTaxonNames(java.util.List)
663 */
664 public List<TaxonNameBase> findIdenticalTaxonNames(List<String> propertyPath) {
665 return this.dao.findIdenticalTaxonNames(propertyPath);
666 }
667
668
669 /* (non-Javadoc)
670 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteTaxon(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.api.service.config.TaxonDeletionConfigurator)
671 */
672 @Override
673 public void deleteTaxon(Taxon taxon, TaxonDeletionConfigurator config) throws ReferencedObjectUndeletableException {
674 if (config == null){
675 config = new TaxonDeletionConfigurator();
676 }
677
678 // TaxonNode
679 if (! config.isDeleteTaxonNodes()){
680 if (taxon.getTaxonNodes().size() > 0){
681 String message = "Taxon can't be deleted as it is used in a classification node. Remove taxon from all classifications prior to deletion.";
682 throw new ReferencedObjectUndeletableException(message);
683 }
684 }
685
686
687 // SynonymRelationShip
688 if (config.isDeleteSynonymRelations()){
689 boolean removeSynonymNameFromHomotypicalGroup = false;
690 for (SynonymRelationship synRel : taxon.getSynonymRelations()){
691 Synonym synonym = synRel.getSynonym();
692 taxon.removeSynonymRelation(synRel, removeSynonymNameFromHomotypicalGroup);
693 if (config.isDeleteSynonymsIfPossible()){
694 //TODO which value
695 boolean newHomotypicGroupIfNeeded = true;
696 deleteSynonym(synonym, taxon, config.isDeleteNameIfPossible(), newHomotypicGroupIfNeeded);
697 }else{
698 deleteSynonymRelationships(synonym, taxon);
699 }
700 }
701 }
702
703 // TaxonRelationship
704 if (! config.isDeleteTaxonRelationships()){
705 if (taxon.getTaxonRelations().size() > 0){
706 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.";
707 throw new ReferencedObjectUndeletableException(message);
708 }
709 }
710
711
712 // TaxonDescription
713 Set<TaxonDescription> descriptions = taxon.getDescriptions();
714
715 for (TaxonDescription desc: descriptions){
716 if (config.isDeleteDescriptions()){
717 //TODO use description delete configurator ?
718 //FIXME check if description is ALWAYS deletable
719 descriptionService.delete(desc);
720 }else{
721 if (desc.getDescribedSpecimenOrObservations().size()>0){
722 String message = "Taxon can't be deleted as it is used in a TaxonDescription" +
723 " which also describes specimens or abservations";
724 throw new ReferencedObjectUndeletableException(message);
725 }
726 }
727 }
728
729
730 //check references with only reverse mapping
731 Set<CdmBase> referencingObjects = genericDao.getReferencingObjects(taxon);
732 for (CdmBase referencingObject : referencingObjects){
733 //IIdentificationKeys (Media, Polytomous, MultiAccess)
734 if (HibernateProxyHelper.isInstanceOf(referencingObject, IIdentificationKey.class)){
735 String message = "Taxon can't be deleted as it is used in an identification key. Remove from identification key prior to deleting this name";
736 message = String.format(message, CdmBase.deproxy(referencingObject, DerivedUnitBase.class).getTitleCache());
737 throw new ReferencedObjectUndeletableException(message);
738 }
739
740
741 //PolytomousKeyNode
742 if (referencingObject.isInstanceOf(PolytomousKeyNode.class)){
743 String message = "Taxon can't be deleted as it is used in polytomous key node";
744 throw new ReferencedObjectUndeletableException(message);
745 }
746
747 //TaxonInteraction
748 if (referencingObject.isInstanceOf(TaxonInteraction.class)){
749 String message = "Taxon can't be deleted as it is used in taxonInteraction#taxon2";
750 throw new ReferencedObjectUndeletableException(message);
751 }
752 }
753
754
755 //TaxonNameBase
756 if (config.isDeleteNameIfPossible()){
757 try {
758 nameService.delete(taxon.getName(), config.getNameDeletionConfig());
759 } catch (ReferencedObjectUndeletableException e) {
760 //do nothing
761 if (logger.isDebugEnabled()){logger.debug("Name could not be deleted");}
762 }
763 }
764
765 }
766
767 /* (non-Javadoc)
768 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonym(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon, boolean, boolean)
769 */
770 @Transactional(readOnly = false)
771 @Override
772 public void deleteSynonym(Synonym synonym, Taxon taxon, boolean removeNameIfPossible,boolean newHomotypicGroupIfNeeded) {
773 if (synonym == null){
774 return;
775 }
776 synonym = CdmBase.deproxy(dao.merge(synonym), Synonym.class);
777
778 //remove synonymRelationship
779 Set<Taxon> taxonSet = new HashSet<Taxon>();
780 if (taxon != null){
781 taxonSet.add(taxon);
782 }else{
783 taxonSet.addAll(synonym.getAcceptedTaxa());
784 }
785 for (Taxon relatedTaxon : taxonSet){
786 // dao.deleteSynonymRelationships(synonym, relatedTaxon);
787 relatedTaxon.removeSynonym(synonym, newHomotypicGroupIfNeeded);
788 }
789 this.saveOrUpdate(synonym);
790
791 //TODO remove name from homotypical group?
792
793 //remove synonym (if necessary)
794 if (synonym.getSynonymRelations().isEmpty()){
795 TaxonNameBase<?,?> name = synonym.getName();
796 synonym.setName(null);
797 dao.delete(synonym);
798
799 //remove name if possible (and required)
800 if (name != null && removeNameIfPossible){
801 try{
802 nameService.delete(name, new NameDeletionConfigurator());
803 }catch (DataChangeNoRollbackException ex){
804 if (logger.isDebugEnabled())logger.debug("Name wasn't deleted as it is referenced");
805 }
806 }
807 }
808 }
809
810
811 /* (non-Javadoc)
812 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findIdenticalTaxonNameIds(java.util.List)
813 */
814 public List<TaxonNameBase> findIdenticalTaxonNameIds(List<String> propertyPath) {
815
816 return this.dao.findIdenticalNamesNew(propertyPath);
817 }
818
819 /* (non-Javadoc)
820 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getPhylumName(eu.etaxonomy.cdm.model.name.TaxonNameBase)
821 */
822 public String getPhylumName(TaxonNameBase name){
823 return this.dao.getPhylumName(name);
824 }
825
826 /* (non-Javadoc)
827 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonymRelationships(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon)
828 */
829 public long deleteSynonymRelationships(Synonym syn, Taxon taxon) {
830 return dao.deleteSynonymRelationships(syn, taxon);
831 }
832
833 /* (non-Javadoc)
834 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonymRelationships(eu.etaxonomy.cdm.model.taxon.Synonym)
835 */
836 public long deleteSynonymRelationships(Synonym syn) {
837 return dao.deleteSynonymRelationships(syn, null);
838 }
839
840
841 /* (non-Javadoc)
842 * @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)
843 */
844 public List<SynonymRelationship> listSynonymRelationships(
845 TaxonBase taxonBase, SynonymRelationshipType type, Integer pageSize, Integer pageNumber,
846 List<OrderHint> orderHints, List<String> propertyPaths, Direction direction) {
847 Integer numberOfResults = dao.countSynonymRelationships(taxonBase, type, direction);
848
849 List<SynonymRelationship> results = new ArrayList<SynonymRelationship>();
850 if(numberOfResults > 0) { // no point checking again
851 results = dao.getSynonymRelationships(taxonBase, type, pageSize, pageNumber, orderHints, propertyPaths, direction);
852 }
853 return results;
854 }
855
856 /* (non-Javadoc)
857 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findBestMatchingTaxon(java.lang.String)
858 */
859 @Override
860 public Taxon findBestMatchingTaxon(String taxonName) {
861 MatchingTaxonConfigurator config = MatchingTaxonConfigurator.NewInstance();
862 config.setTaxonNameTitle(taxonName);
863 return findBestMatchingTaxon(config);
864 }
865
866
867
868 @Override
869 public Taxon findBestMatchingTaxon(MatchingTaxonConfigurator config) {
870
871 Taxon bestCandidate = null;
872 try{
873 // 1. search for acceptet taxa
874 List<TaxonBase> taxonList = dao.findByNameTitleCache(true, false, config.getTaxonNameTitle(), null, MatchMode.EXACT, null, 0, null, null);
875 boolean bestCandidateMatchesSecUuid = false;
876 boolean bestCandidateIsInClassification = false;
877 int countEqualCandidates = 0;
878 for(TaxonBase taxonBaseCandidate : taxonList){
879 if(taxonBaseCandidate instanceof Taxon){
880 Taxon newCanditate = CdmBase.deproxy(taxonBaseCandidate, Taxon.class);
881 boolean newCandidateMatchesSecUuid = isMatchesSecUuid(newCanditate, config);
882 if (! newCandidateMatchesSecUuid && config.isOnlyMatchingSecUuid() ){
883 continue;
884 }else if(newCandidateMatchesSecUuid && ! bestCandidateMatchesSecUuid){
885 bestCandidate = newCanditate;
886 countEqualCandidates = 1;
887 bestCandidateMatchesSecUuid = true;
888 continue;
889 }
890
891 boolean newCandidateInClassification = isInClassification(newCanditate, config);
892 if (! newCandidateInClassification && config.isOnlyMatchingClassificationUuid()){
893 continue;
894 }else if (newCandidateInClassification && ! bestCandidateIsInClassification){
895 bestCandidate = newCanditate;
896 countEqualCandidates = 1;
897 bestCandidateIsInClassification = true;
898 continue;
899 }
900 if (bestCandidate == null){
901 bestCandidate = newCanditate;
902 countEqualCandidates = 1;
903 continue;
904 }
905
906 }else{ //not Taxon.class
907 continue;
908 }
909 countEqualCandidates++;
910
911 }
912 if (bestCandidate != null){
913 if(countEqualCandidates > 1){
914 logger.info(countEqualCandidates + " equally matching TaxonBases found, using first accepted Taxon: " + bestCandidate.getTitleCache());
915 return bestCandidate;
916 } else {
917 logger.info("using accepted Taxon: " + bestCandidate.getTitleCache());
918 return bestCandidate;
919 }
920 }
921
922
923 // 2. search for synonyms
924 if (config.isIncludeSynonyms()){
925 List<TaxonBase> synonymList = dao.findByNameTitleCache(false, true, config.getTaxonNameTitle(), null, MatchMode.EXACT, null, 0, null, null);
926 for(TaxonBase taxonBase : synonymList){
927 if(taxonBase instanceof Synonym){
928 Synonym synonym = CdmBase.deproxy(taxonBase, Synonym.class);
929 Set<Taxon> acceptetdCandidates = synonym.getAcceptedTaxa();
930 if(!acceptetdCandidates.isEmpty()){
931 bestCandidate = acceptetdCandidates.iterator().next();
932 if(acceptetdCandidates.size() == 1){
933 logger.info(acceptetdCandidates.size() + " Accepted taxa found for synonym " + taxonBase.getTitleCache() + ", using first one: " + bestCandidate.getTitleCache());
934 return bestCandidate;
935 } else {
936 logger.info("using accepted Taxon " + bestCandidate.getTitleCache() + "for synonym " + taxonBase.getTitleCache());
937 return bestCandidate;
938 }
939 //TODO extend method: search using treeUUID, using SecUUID, first find accepted then include synonyms until a matching taxon is found
940 }
941 }
942 }
943 }
944
945 } catch (Exception e){
946 logger.error(e);
947 }
948
949 return bestCandidate;
950 }
951
952 private boolean isInClassification(Taxon taxon, MatchingTaxonConfigurator config) {
953 UUID configClassificationUuid = config.getClassificationUuid();
954 if (configClassificationUuid == null){
955 return false;
956 }
957 for (TaxonNode node : taxon.getTaxonNodes()){
958 UUID classUuid = node.getClassification().getUuid();
959 if (configClassificationUuid.equals(classUuid)){
960 return true;
961 }
962 }
963 return false;
964 }
965
966 private boolean isMatchesSecUuid(Taxon taxon, MatchingTaxonConfigurator config) {
967 UUID configSecUuid = config.getSecUuid();
968 if (configSecUuid == null){
969 return false;
970 }
971 UUID taxonSecUuid = (taxon.getSec() == null)? null : taxon.getSec().getUuid();
972 return configSecUuid.equals(taxonSecUuid);
973 }
974
975 /* (non-Javadoc)
976 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findBestMatchingSynonym(java.lang.String)
977 */
978 @Override
979 public Synonym findBestMatchingSynonym(String taxonName) {
980 List<TaxonBase> synonymList = dao.findByNameTitleCache(false, true, taxonName, null, MatchMode.EXACT, null, 0, null, null);
981 if(! synonymList.isEmpty()){
982 Synonym result = CdmBase.deproxy(synonymList.iterator().next(), Synonym.class);
983 if(synonymList.size() == 1){
984 logger.info(synonymList.size() + " Synonym found " + result.getTitleCache() );
985 return result;
986 } else {
987 logger.info("Several matching synonyms found. Using first: " + result.getTitleCache());
988 return result;
989 }
990 }
991 return null;
992 }
993
994
995 /* (non-Javadoc)
996 * @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)
997 */
998 @Override
999 public SynonymRelationship moveSynonymToAnotherTaxon(SynonymRelationship oldSynonymRelation, Taxon newTaxon, boolean moveHomotypicGroup,
1000 SynonymRelationshipType newSynonymRelationshipType, Reference reference, String referenceDetail, boolean keepReference) throws HomotypicalGroupChangeException {
1001
1002 Synonym synonym = oldSynonymRelation.getSynonym();
1003 Taxon fromTaxon = oldSynonymRelation.getAcceptedTaxon();
1004 //TODO what if there is no name ?? Concepts may be cached (e.g. via TCS import)
1005 TaxonNameBase<?,?> synonymName = synonym.getName();
1006 TaxonNameBase<?,?> fromTaxonName = fromTaxon.getName();
1007 //set default relationship type
1008 if (newSynonymRelationshipType == null){
1009 newSynonymRelationshipType = SynonymRelationshipType.HETEROTYPIC_SYNONYM_OF();
1010 }
1011 boolean newRelTypeIsHomotypic = newSynonymRelationshipType.equals(SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF());
1012
1013 HomotypicalGroup homotypicGroup = synonymName.getHomotypicalGroup();
1014 int hgSize = homotypicGroup.getTypifiedNames().size();
1015 boolean isSingleInGroup = !(hgSize > 1);
1016
1017 if (! isSingleInGroup){
1018 boolean isHomotypicToAccepted = synonymName.isHomotypic(fromTaxonName);
1019 boolean hasHomotypicSynonymRelatives = isHomotypicToAccepted ? hgSize > 2 : hgSize > 1;
1020 if (isHomotypicToAccepted){
1021 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.";
1022 String homotypicRelatives = hasHomotypicSynonymRelatives ? " and other synonym(s)":"";
1023 message = String.format(message, homotypicRelatives);
1024 throw new HomotypicalGroupChangeException(message);
1025 }
1026 if (! moveHomotypicGroup){
1027 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.";
1028 throw new HomotypicalGroupChangeException(message);
1029 }
1030 }else{
1031 moveHomotypicGroup = true; //single synonym always allows to moveCompleteGroup
1032 }
1033 // Assert.assertTrue("Synonym can only be moved with complete homotypic group", moveHomotypicGroup);
1034
1035 SynonymRelationship result = null;
1036 //move all synonyms to new taxon
1037 List<Synonym> homotypicSynonyms = fromTaxon.getSynonymsInGroup(homotypicGroup);
1038 for (Synonym syn: homotypicSynonyms){
1039 Set<SynonymRelationship> synRelations = syn.getSynonymRelations();
1040 for (SynonymRelationship synRelation : synRelations){
1041 if (fromTaxon.equals(synRelation.getAcceptedTaxon())){
1042 Reference<?> newReference = reference;
1043 if (newReference == null && keepReference){
1044 newReference = synRelation.getCitation();
1045 }
1046 String newRefDetail = referenceDetail;
1047 if (newRefDetail == null && keepReference){
1048 newRefDetail = synRelation.getCitationMicroReference();
1049 }
1050 SynonymRelationship newSynRelation = newTaxon.addSynonym(syn, newSynonymRelationshipType, newReference, newRefDetail);
1051 fromTaxon.removeSynonymRelation(synRelation, false);
1052 //
1053 //change homotypic group of synonym if relType is 'homotypic'
1054 // if (newRelTypeIsHomotypic){
1055 // newTaxon.getName().getHomotypicalGroup().addTypifiedName(syn.getName());
1056 // }
1057 //set result
1058 if (synRelation.equals(oldSynonymRelation)){
1059 result = newSynRelation;
1060 }
1061 }
1062 }
1063
1064 }
1065 saveOrUpdate(newTaxon);
1066 //Assert that there is a result
1067 if (result == null){
1068 String message = "Old synonym relation could not be transformed into new relation. This should not happen.";
1069 throw new IllegalStateException(message);
1070 }
1071 return result;
1072 }
1073
1074 /* (non-Javadoc)
1075 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getUuidAndTitleCacheTaxon()
1076 */
1077 @Override
1078 public List<UuidAndTitleCache<TaxonBase>> getUuidAndTitleCacheTaxon() {
1079 return dao.getUuidAndTitleCacheTaxon();
1080 }
1081
1082 /* (non-Javadoc)
1083 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getUuidAndTitleCacheSynonym()
1084 */
1085 @Override
1086 public List<UuidAndTitleCache<TaxonBase>> getUuidAndTitleCacheSynonym() {
1087 return dao.getUuidAndTitleCacheSynonym();
1088 }
1089
1090 @Override
1091 public Pager<SearchResult<TaxonBase>> findByDescriptionElementFullText(Class<? extends DescriptionElementBase> clazz, String queryString, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints,
1092 List<String> propertyPaths) throws CorruptIndexException, IOException, ParseException {
1093
1094 String luceneQueryTemplate = "titleCache:%1$s OR text.ALL:%1$s OR name:%1$s";
1095 String luceneQuery = String.format(luceneQueryTemplate, queryString);
1096
1097 LuceneSearch luceneSearch = new LuceneSearch(getSession(), clazz);
1098 TopDocs topDocsResultSet = luceneSearch.executeSearch(luceneQuery);
1099 List<SearchResult<TaxonBase>> searchResults = searchResultBuilder.createResultSetFromIds(luceneSearch, topDocsResultSet, dao, "inDescription.taxon.id");
1100
1101 return new DefaultPagerImpl<SearchResult<TaxonBase>>(pageNumber, searchResults.size(), pageSize, searchResults);
1102
1103 }
1104
1105 public List<Synonym> createInferredSynonyms(Taxon taxon, Classification classification, SynonymRelationshipType type, boolean doWithMisappliedNames){
1106 List <Synonym> inferredSynonyms = new ArrayList<Synonym>();
1107 List<Synonym> inferredSynonymsToBeRemoved = new ArrayList<Synonym>();
1108
1109 HashMap <UUID, ZoologicalName> zooHashMap = new HashMap<UUID, ZoologicalName>();
1110
1111
1112 UUID uuid= taxon.getName().getUuid();
1113 ZoologicalName taxonName = getZoologicalName(uuid, zooHashMap);
1114 String epithetOfTaxon = null;
1115 String infragenericEpithetOfTaxon = null;
1116 String infraspecificEpithetOfTaxon = null;
1117 if (taxonName.isSpecies()){
1118 epithetOfTaxon= taxonName.getSpecificEpithet();
1119 } else if (taxonName.isInfraGeneric()){
1120 infragenericEpithetOfTaxon = taxonName.getInfraGenericEpithet();
1121 } else if (taxonName.isInfraSpecific()){
1122 infraspecificEpithetOfTaxon = taxonName.getInfraSpecificEpithet();
1123 }
1124 String genusOfTaxon = taxonName.getGenusOrUninomial();
1125 Set<TaxonNode> nodes = taxon.getTaxonNodes();
1126 List<String> taxonNames = new ArrayList<String>();
1127
1128 for (TaxonNode node: nodes){
1129 // HashMap<String, String> synonymsGenus = new HashMap<String, String>(); // Changed this to be able to store the idInSource to a genusName
1130 // List<String> synonymsEpithet = new ArrayList<String>();
1131
1132 if (node.getClassification().equals(classification)){
1133 if (!node.isTopmostNode()){
1134 TaxonNode parent = (TaxonNode)node.getParent();
1135 parent = (TaxonNode)HibernateProxyHelper.deproxy(parent);
1136 TaxonNameBase parentName = parent.getTaxon().getName();
1137 ZoologicalName zooParentName = HibernateProxyHelper.deproxy(parentName, ZoologicalName.class);
1138 Taxon parentTaxon = (Taxon)HibernateProxyHelper.deproxy(parent.getTaxon());
1139 Rank rankOfTaxon = taxonName.getRank();
1140
1141
1142 //create inferred synonyms for species, subspecies
1143 if ((parentName.isGenus() || parentName.isSpecies() || parentName.getRank().equals(Rank.SUBGENUS())) ){
1144
1145 Synonym inferredEpithet = null;
1146 Synonym inferredGenus = null;
1147 Synonym potentialCombination = null;
1148
1149 List<String> propertyPaths = new ArrayList<String>();
1150 propertyPaths.add("synonym");
1151 propertyPaths.add("synonym.name");
1152 List<OrderHint> orderHints = new ArrayList<OrderHint>();
1153 orderHints.add(new OrderHint("relatedFrom.titleCache", SortOrder.ASCENDING));
1154
1155 List<SynonymRelationship> synonymRelationshipsOfParent = dao.getSynonyms(parentTaxon, SynonymRelationshipType.HETEROTYPIC_SYNONYM_OF(), null, null,orderHints,propertyPaths);
1156 List<SynonymRelationship> synonymRelationshipsOfTaxon= dao.getSynonyms(taxon, SynonymRelationshipType.HETEROTYPIC_SYNONYM_OF(), null, null,orderHints,propertyPaths);
1157
1158 List<TaxonRelationship> taxonRelListParent = null;
1159 List<TaxonRelationship> taxonRelListTaxon = null;
1160 if (doWithMisappliedNames){
1161 taxonRelListParent = dao.getTaxonRelationships(parentTaxon, TaxonRelationshipType.MISAPPLIED_NAME_FOR(), null, null, orderHints, propertyPaths, Direction.relatedTo);
1162 taxonRelListTaxon = dao.getTaxonRelationships(taxon, TaxonRelationshipType.MISAPPLIED_NAME_FOR(), null, null, orderHints, propertyPaths, Direction.relatedTo);
1163 }
1164
1165
1166 if (type.equals(SynonymRelationshipType.INFERRED_EPITHET_OF())){
1167 Set<String> genusNames = new HashSet<String>();
1168
1169 for (SynonymRelationship synonymRelationOfParent:synonymRelationshipsOfParent){
1170 Synonym syn = synonymRelationOfParent.getSynonym();
1171
1172 inferredEpithet = createInferredEpithets(taxon,
1173 zooHashMap, taxonName, epithetOfTaxon,
1174 infragenericEpithetOfTaxon,
1175 infraspecificEpithetOfTaxon,
1176 taxonNames, parentName,
1177 syn);
1178
1179
1180 inferredSynonyms.add(inferredEpithet);
1181 zooHashMap.put(inferredEpithet.getName().getUuid(), (ZoologicalName)inferredEpithet.getName());
1182 taxonNames.add(((ZoologicalName)inferredEpithet.getName()).getNameCache());
1183 }
1184
1185 if (doWithMisappliedNames){
1186
1187 for (TaxonRelationship taxonRelationship: taxonRelListParent){
1188 Taxon misappliedName = taxonRelationship.getFromTaxon();
1189
1190 inferredEpithet = createInferredEpithets(taxon,
1191 zooHashMap, taxonName, epithetOfTaxon,
1192 infragenericEpithetOfTaxon,
1193 infraspecificEpithetOfTaxon,
1194 taxonNames, parentName,
1195 misappliedName);
1196
1197 inferredSynonyms.add(inferredEpithet);
1198 zooHashMap.put(inferredEpithet.getName().getUuid(), (ZoologicalName)inferredEpithet.getName());
1199 taxonNames.add(((ZoologicalName)inferredEpithet.getName()).getNameCache());
1200 }
1201 }
1202
1203 if (!taxonNames.isEmpty()){
1204 List<String> synNotInCDM = dao.taxaByNameNotInDB(taxonNames);
1205 ZoologicalName name;
1206 if (!synNotInCDM.isEmpty()){
1207 inferredSynonymsToBeRemoved.clear();
1208
1209 for (Synonym syn :inferredSynonyms){
1210 name = getZoologicalName(syn.getName().getUuid(), zooHashMap);
1211 if (!synNotInCDM.contains(name.getNameCache())){
1212 inferredSynonymsToBeRemoved.add(syn);
1213 }
1214 }
1215
1216 // Remove identified Synonyms from inferredSynonyms
1217 for (Synonym synonym : inferredSynonymsToBeRemoved) {
1218 inferredSynonyms.remove(synonym);
1219 }
1220 }
1221 }
1222
1223 }else if (type.equals(SynonymRelationshipType.INFERRED_GENUS_OF())){
1224
1225
1226 for (SynonymRelationship synonymRelationOfTaxon:synonymRelationshipsOfTaxon){
1227 TaxonNameBase synName;
1228 ZoologicalName inferredSynName;
1229
1230 Synonym syn = synonymRelationOfTaxon.getSynonym();
1231 inferredGenus = createInferredGenus(taxon,
1232 zooHashMap, taxonName, epithetOfTaxon,
1233 genusOfTaxon, taxonNames, zooParentName, syn);
1234
1235 inferredSynonyms.add(inferredGenus);
1236 zooHashMap.put(inferredGenus.getName().getUuid(), (ZoologicalName)inferredGenus.getName());
1237 taxonNames.add(( (ZoologicalName)inferredGenus.getName()).getNameCache());
1238
1239
1240 }
1241
1242 if (doWithMisappliedNames){
1243
1244 for (TaxonRelationship taxonRelationship: taxonRelListTaxon){
1245 Taxon misappliedName = taxonRelationship.getFromTaxon();
1246 inferredGenus = createInferredGenus(taxon, zooHashMap, taxonName, infraspecificEpithetOfTaxon, genusOfTaxon, taxonNames, zooParentName, misappliedName);
1247
1248 inferredSynonyms.add(inferredGenus);
1249 zooHashMap.put(inferredGenus.getName().getUuid(), (ZoologicalName)inferredGenus.getName());
1250 taxonNames.add(( (ZoologicalName)inferredGenus.getName()).getNameCache());
1251 }
1252 }
1253
1254
1255 if (!taxonNames.isEmpty()){
1256 List<String> synNotInCDM = dao.taxaByNameNotInDB(taxonNames);
1257 ZoologicalName name;
1258 if (!synNotInCDM.isEmpty()){
1259 inferredSynonymsToBeRemoved.clear();
1260
1261 for (Synonym syn :inferredSynonyms){
1262 name = getZoologicalName(syn.getName().getUuid(), zooHashMap);
1263 if (!synNotInCDM.contains(name.getNameCache())){
1264 inferredSynonymsToBeRemoved.add(syn);
1265 }
1266 }
1267
1268 // Remove identified Synonyms from inferredSynonyms
1269 for (Synonym synonym : inferredSynonymsToBeRemoved) {
1270 inferredSynonyms.remove(synonym);
1271 }
1272 }
1273 }
1274
1275 }else if (type.equals(SynonymRelationshipType.POTENTIAL_COMBINATION_OF())){
1276
1277 Reference sourceReference = null; // TODO: Determination of sourceReference is redundant
1278 ZoologicalName inferredSynName;
1279 //for all synonyms of the parent...
1280 for (SynonymRelationship synonymRelationOfParent:synonymRelationshipsOfParent){
1281 TaxonNameBase synName;
1282 Synonym synParent = synonymRelationOfParent.getSynonym();
1283 synName = synParent.getName();
1284
1285 HibernateProxyHelper.deproxy(synParent);
1286
1287 // Set the sourceReference
1288 sourceReference = synParent.getSec();
1289
1290 // Determine the idInSource
1291 String idInSourceParent = getIdInSource(synParent);
1292
1293 ZoologicalName parentSynZooName = getZoologicalName(synName.getUuid(), zooHashMap);
1294 String synParentGenus = parentSynZooName.getGenusOrUninomial();
1295 String synParentInfragenericName = null;
1296 String synParentSpecificEpithet = null;
1297
1298 if (parentSynZooName.isInfraGeneric()){
1299 synParentInfragenericName = parentSynZooName.getInfraGenericEpithet();
1300 }
1301 if (parentSynZooName.isSpecies()){
1302 synParentSpecificEpithet = parentSynZooName.getSpecificEpithet();
1303 }
1304
1305 /* if (synGenusName != null && !synonymsGenus.containsKey(synGenusName)){
1306 synonymsGenus.put(synGenusName, idInSource);
1307 }*/
1308
1309 //for all synonyms of the taxon
1310
1311 for (SynonymRelationship synonymRelationOfTaxon:synonymRelationshipsOfTaxon){
1312
1313 Synonym syn = synonymRelationOfTaxon.getSynonym();
1314 ZoologicalName zooSynName = getZoologicalName(syn.getName().getUuid(), zooHashMap);
1315 potentialCombination = createPotentialCombination(idInSourceParent, parentSynZooName, zooSynName,
1316 synParentGenus,
1317 synParentInfragenericName,
1318 synParentSpecificEpithet, syn, zooHashMap);
1319
1320 taxon.addSynonym(potentialCombination, SynonymRelationshipType.POTENTIAL_COMBINATION_OF());
1321 inferredSynonyms.add(potentialCombination);
1322 zooHashMap.put(potentialCombination.getName().getUuid(), (ZoologicalName)potentialCombination.getName());
1323 taxonNames.add(( (ZoologicalName)potentialCombination.getName()).getNameCache());
1324
1325 }
1326
1327
1328 }
1329
1330 if (doWithMisappliedNames){
1331
1332 for (TaxonRelationship parentRelationship: taxonRelListParent){
1333
1334 TaxonNameBase misappliedParentName;
1335
1336 Taxon misappliedParent = parentRelationship.getFromTaxon();
1337 misappliedParentName = misappliedParent.getName();
1338
1339 HibernateProxyHelper.deproxy(misappliedParent);
1340
1341 // Set the sourceReference
1342 sourceReference = misappliedParent.getSec();
1343
1344 // Determine the idInSource
1345 String idInSourceParent = getIdInSource(misappliedParent);
1346
1347 ZoologicalName parentSynZooName = getZoologicalName(misappliedParentName.getUuid(), zooHashMap);
1348 String synParentGenus = parentSynZooName.getGenusOrUninomial();
1349 String synParentInfragenericName = null;
1350 String synParentSpecificEpithet = null;
1351
1352 if (parentSynZooName.isInfraGeneric()){
1353 synParentInfragenericName = parentSynZooName.getInfraGenericEpithet();
1354 }
1355 if (parentSynZooName.isSpecies()){
1356 synParentSpecificEpithet = parentSynZooName.getSpecificEpithet();
1357 }
1358
1359
1360 for (TaxonRelationship taxonRelationship: taxonRelListTaxon){
1361 Taxon misappliedName = taxonRelationship.getFromTaxon();
1362 ZoologicalName zooMisappliedName = getZoologicalName(misappliedName.getName().getUuid(), zooHashMap);
1363 potentialCombination = createPotentialCombination(
1364 idInSourceParent, parentSynZooName, zooMisappliedName,
1365 synParentGenus,
1366 synParentInfragenericName,
1367 synParentSpecificEpithet, misappliedName, zooHashMap);
1368
1369
1370 taxon.addSynonym(potentialCombination, SynonymRelationshipType.POTENTIAL_COMBINATION_OF());
1371 inferredSynonyms.add(potentialCombination);
1372 zooHashMap.put(potentialCombination.getName().getUuid(), (ZoologicalName)potentialCombination.getName());
1373 taxonNames.add(( (ZoologicalName)potentialCombination.getName()).getNameCache());
1374 }
1375 }
1376 }
1377
1378 if (!taxonNames.isEmpty()){
1379 List<String> synNotInCDM = dao.taxaByNameNotInDB(taxonNames);
1380 ZoologicalName name;
1381 if (!synNotInCDM.isEmpty()){
1382 inferredSynonymsToBeRemoved.clear();
1383 for (Synonym syn :inferredSynonyms){
1384 try{
1385 name = (ZoologicalName) syn.getName();
1386 }catch (ClassCastException e){
1387 name = getZoologicalName(syn.getName().getUuid(), zooHashMap);
1388 }
1389 if (!synNotInCDM.contains(name.getNameCache())){
1390 inferredSynonymsToBeRemoved.add(syn);
1391 }
1392 }
1393 // Remove identified Synonyms from inferredSynonyms
1394 for (Synonym synonym : inferredSynonymsToBeRemoved) {
1395 inferredSynonyms.remove(synonym);
1396 }
1397 }
1398 }
1399 }
1400 }else {
1401 logger.info("The synonymrelationship type is not defined.");
1402 return inferredSynonyms;
1403 }
1404 }
1405 }
1406
1407 }
1408
1409 return inferredSynonyms;
1410 }
1411
1412 private Synonym createPotentialCombination(String idInSourceParent,
1413 ZoologicalName parentSynZooName, ZoologicalName zooSynName, String synParentGenus,
1414 String synParentInfragenericName, String synParentSpecificEpithet,
1415 TaxonBase syn, HashMap<UUID, ZoologicalName> zooHashMap) {
1416 Synonym potentialCombination;
1417 Reference sourceReference;
1418 ZoologicalName inferredSynName;
1419 HibernateProxyHelper.deproxy(syn);
1420
1421 // Set sourceReference
1422 sourceReference = syn.getSec();
1423
1424
1425 String synTaxonSpecificEpithet = zooSynName.getSpecificEpithet();
1426
1427 String synTaxonInfraSpecificName= null;
1428
1429 if (parentSynZooName.isSpecies()){
1430 synTaxonInfraSpecificName = zooSynName.getInfraSpecificEpithet();
1431 }
1432
1433 /*if (epithetName != null && !synonymsEpithet.contains(epithetName)){
1434 synonymsEpithet.add(epithetName);
1435 }*/
1436
1437 //create potential combinations...
1438 inferredSynName = ZoologicalName.NewInstance(syn.getName().getRank());
1439
1440 inferredSynName.setGenusOrUninomial(synParentGenus);
1441 if (zooSynName.isSpecies()){
1442 inferredSynName.setSpecificEpithet(synTaxonSpecificEpithet);
1443 if (parentSynZooName.isInfraGeneric()){
1444 inferredSynName.setInfraGenericEpithet(synParentInfragenericName);
1445 }
1446 }
1447 if (zooSynName.isInfraSpecific()){
1448 inferredSynName.setSpecificEpithet(synParentSpecificEpithet);
1449 inferredSynName.setInfraSpecificEpithet(synTaxonInfraSpecificName);
1450 }
1451 if (parentSynZooName.isInfraGeneric()){
1452 inferredSynName.setInfraGenericEpithet(synParentInfragenericName);
1453 }
1454
1455
1456 potentialCombination = Synonym.NewInstance(inferredSynName, null);
1457
1458 // Set the sourceReference
1459 potentialCombination.setSec(sourceReference);
1460
1461
1462 // Determine the idInSource
1463 String idInSourceSyn= getIdInSource(syn);
1464
1465 if (idInSourceParent != null && idInSourceSyn != null) {
1466 IdentifiableSource originalSource = IdentifiableSource.NewInstance(idInSourceSyn + "; " + idInSourceParent, POTENTIAL_COMBINATION_NAMESPACE, sourceReference, null);
1467 inferredSynName.addSource(originalSource);
1468 originalSource = IdentifiableSource.NewInstance(idInSourceSyn + "; " + idInSourceParent, POTENTIAL_COMBINATION_NAMESPACE, sourceReference, null);
1469 potentialCombination.addSource(originalSource);
1470 }
1471
1472 inferredSynName.generateTitle();
1473
1474 return potentialCombination;
1475 }
1476
1477 private Synonym createInferredGenus(Taxon taxon,
1478 HashMap<UUID, ZoologicalName> zooHashMap, ZoologicalName taxonName,
1479 String epithetOfTaxon, String genusOfTaxon,
1480 List<String> taxonNames, ZoologicalName zooParentName,
1481 TaxonBase syn) {
1482
1483 Synonym inferredGenus;
1484 TaxonNameBase synName;
1485 ZoologicalName inferredSynName;
1486 synName =syn.getName();
1487 HibernateProxyHelper.deproxy(syn);
1488
1489 // Determine the idInSource
1490 String idInSourceSyn = getIdInSource(syn);
1491 String idInSourceTaxon = getIdInSource(taxon);
1492 // Determine the sourceReference
1493 Reference sourceReference = syn.getSec();
1494
1495 synName = syn.getName();
1496 ZoologicalName synZooName = getZoologicalName(synName.getUuid(), zooHashMap);
1497 String synSpeciesEpithetName = synZooName.getSpecificEpithet();
1498 /* if (synonymsEpithet != null && !synonymsEpithet.contains(synSpeciesEpithetName)){
1499 synonymsEpithet.add(synSpeciesEpithetName);
1500 }*/
1501
1502 inferredSynName = ZoologicalName.NewInstance(taxon.getName().getRank());
1503 //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...
1504
1505
1506 inferredSynName.setGenusOrUninomial(genusOfTaxon);
1507 if (zooParentName.isInfraGeneric()){
1508 inferredSynName.setInfraGenericEpithet(zooParentName.getInfraGenericEpithet());
1509 }
1510
1511 if (taxonName.isSpecies()){
1512 inferredSynName.setSpecificEpithet(synSpeciesEpithetName);
1513 }
1514 if (taxonName.isInfraSpecific()){
1515 inferredSynName.setSpecificEpithet(epithetOfTaxon);
1516 inferredSynName.setInfraSpecificEpithet(synZooName.getInfraGenericEpithet());
1517 }
1518
1519
1520 inferredGenus = Synonym.NewInstance(inferredSynName, null);
1521
1522 // Set the sourceReference
1523 inferredGenus.setSec(sourceReference);
1524
1525 // Add the original source
1526 if (idInSourceSyn != null && idInSourceTaxon != null) {
1527 IdentifiableSource originalSource = IdentifiableSource.NewInstance(idInSourceSyn + "; " + idInSourceTaxon, INFERRED_GENUS_NAMESPACE, sourceReference, null);
1528 inferredGenus.addSource(originalSource);
1529
1530 originalSource = IdentifiableSource.NewInstance(idInSourceSyn + "; " + idInSourceTaxon, INFERRED_GENUS_NAMESPACE, sourceReference, null);
1531 inferredSynName.addSource(originalSource);
1532
1533 }
1534
1535 taxon.addSynonym(inferredGenus, SynonymRelationshipType.INFERRED_GENUS_OF());
1536
1537 inferredSynName.generateTitle();
1538
1539
1540 return inferredGenus;
1541 }
1542
1543 private Synonym createInferredEpithets(Taxon taxon,
1544 HashMap<UUID, ZoologicalName> zooHashMap, ZoologicalName taxonName,
1545 String epithetOfTaxon, String infragenericEpithetOfTaxon,
1546 String infraspecificEpithetOfTaxon, List<String> taxonNames,
1547 TaxonNameBase parentName, TaxonBase syn) {
1548
1549 Synonym inferredEpithet;
1550 TaxonNameBase synName;
1551 ZoologicalName inferredSynName;
1552 HibernateProxyHelper.deproxy(syn);
1553
1554 // Determine the idInSource
1555 String idInSourceSyn = getIdInSource(syn);
1556 String idInSourceTaxon = getIdInSource(taxon);
1557 // Determine the sourceReference
1558 Reference sourceReference = syn.getSec();
1559
1560 synName = syn.getName();
1561 ZoologicalName zooSynName = getZoologicalName(synName.getUuid(), zooHashMap);
1562 String synGenusName = zooSynName.getGenusOrUninomial();
1563 String synInfraGenericEpithet = null;
1564 String synSpecificEpithet = null;
1565
1566 if (zooSynName.getInfraGenericEpithet() != null){
1567 synInfraGenericEpithet = zooSynName.getInfraGenericEpithet();
1568 }
1569
1570 if (zooSynName.isInfraSpecific()){
1571 synSpecificEpithet = zooSynName.getSpecificEpithet();
1572 }
1573
1574 /* if (synGenusName != null && !synonymsGenus.containsKey(synGenusName)){
1575 synonymsGenus.put(synGenusName, idInSource);
1576 }*/
1577
1578 inferredSynName = ZoologicalName.NewInstance(taxon.getName().getRank());
1579
1580 // DEBUG TODO: for subgenus or subspecies the infrageneric or infraspecific epithet should be used!!!
1581 if (epithetOfTaxon == null && infragenericEpithetOfTaxon == null && infraspecificEpithetOfTaxon == null) {
1582 logger.error("This specificEpithet is NULL" + taxon.getTitleCache());
1583 }
1584 inferredSynName.setGenusOrUninomial(synGenusName);
1585
1586 if (parentName.isInfraGeneric()){
1587 inferredSynName.setInfraGenericEpithet(synInfraGenericEpithet);
1588 }
1589 if (taxonName.isSpecies()){
1590 inferredSynName.setSpecificEpithet(epithetOfTaxon);
1591 }else if (taxonName.isInfraSpecific()){
1592 inferredSynName.setSpecificEpithet(synSpecificEpithet);
1593 inferredSynName.setInfraSpecificEpithet(infraspecificEpithetOfTaxon);
1594 }
1595
1596 inferredEpithet = Synonym.NewInstance(inferredSynName, null);
1597
1598 // Set the sourceReference
1599 inferredEpithet.setSec(sourceReference);
1600
1601 /* Add the original source
1602 if (idInSource != null) {
1603 IdentifiableSource originalSource = IdentifiableSource.NewInstance(idInSource, "InferredEpithetOf", syn.getSec(), null);
1604
1605 // Add the citation
1606 Reference citation = getCitation(syn);
1607 if (citation != null) {
1608 originalSource.setCitation(citation);
1609 inferredEpithet.addSource(originalSource);
1610 }
1611 }*/
1612 String taxonId = idInSourceTaxon+ "; " + idInSourceSyn;
1613
1614 IdentifiableSource originalSource;
1615 originalSource = IdentifiableSource.NewInstance(taxonId, INFERRED_EPITHET_NAMESPACE, sourceReference, null);
1616
1617 inferredEpithet.addSource(originalSource);
1618
1619 originalSource = IdentifiableSource.NewInstance(taxonId, INFERRED_EPITHET_NAMESPACE, sourceReference, null);
1620
1621 inferredSynName.addSource(originalSource);
1622
1623
1624
1625 taxon.addSynonym(inferredEpithet, SynonymRelationshipType.INFERRED_EPITHET_OF());
1626
1627 inferredSynName.generateTitle();
1628 return inferredEpithet;
1629 }
1630
1631 /**
1632 * Returns an existing ZoologicalName or extends an internal hashmap if it does not exist.
1633 * Very likely only useful for createInferredSynonyms().
1634 * @param uuid
1635 * @param zooHashMap
1636 * @return
1637 */
1638 private ZoologicalName getZoologicalName(UUID uuid, HashMap <UUID, ZoologicalName> zooHashMap) {
1639 ZoologicalName taxonName =nameDao.findZoologicalNameByUUID(uuid);
1640 if (taxonName == null) {
1641 taxonName = zooHashMap.get(uuid);
1642 }
1643 return taxonName;
1644 }
1645
1646 /**
1647 * Returns the idInSource for a given Synonym.
1648 * @param syn
1649 */
1650 private String getIdInSource(TaxonBase taxonBase) {
1651 String idInSource = null;
1652 Set<IdentifiableSource> sources = taxonBase.getSources();
1653 if (sources.size() == 1) {
1654 IdentifiableSource source = sources.iterator().next();
1655 if (source != null) {
1656 idInSource = source.getIdInSource();
1657 }
1658 } else if (sources.size() > 1) {
1659 int count = 1;
1660 idInSource = "";
1661 for (IdentifiableSource source : sources) {
1662 idInSource += source.getIdInSource();
1663 if (count < sources.size()) {
1664 idInSource += "; ";
1665 }
1666 count++;
1667 }
1668 }
1669
1670 return idInSource;
1671 }
1672
1673
1674 /**
1675 * Returns the citation for a given Synonym.
1676 * @param syn
1677 */
1678 private Reference getCitation(Synonym syn) {
1679 Reference citation = null;
1680 Set<IdentifiableSource> sources = syn.getSources();
1681 if (sources.size() == 1) {
1682 IdentifiableSource source = sources.iterator().next();
1683 if (source != null) {
1684 citation = source.getCitation();
1685 }
1686 } else if (sources.size() > 1) {
1687 logger.warn("This Synonym has more than one source: " + syn.getUuid() + " (" + syn.getTitleCache() +")");
1688 }
1689
1690 return citation;
1691 }
1692
1693 public List<Synonym> createAllInferredSynonyms(Taxon taxon, Classification tree, boolean doWithMisappliedNames){
1694 List <Synonym> inferredSynonyms = new ArrayList<Synonym>();
1695
1696 inferredSynonyms.addAll(createInferredSynonyms(taxon, tree, SynonymRelationshipType.INFERRED_EPITHET_OF(), doWithMisappliedNames));
1697 inferredSynonyms.addAll(createInferredSynonyms(taxon, tree, SynonymRelationshipType.INFERRED_GENUS_OF(), doWithMisappliedNames));
1698 inferredSynonyms.addAll(createInferredSynonyms(taxon, tree, SynonymRelationshipType.POTENTIAL_COMBINATION_OF(), doWithMisappliedNames));
1699
1700 return inferredSynonyms;
1701 }
1702
1703
1704
1705
1706 }