change getSynonymsInGroup to synonymRelationship dependency (not sec dependency anymore).
[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.util.ArrayList;
14 import java.util.Comparator;
15 import java.util.HashSet;
16 import java.util.List;
17 import java.util.Set;
18 import java.util.UUID;
19
20 import org.apache.log4j.Logger;
21 import org.springframework.beans.factory.annotation.Autowired;
22 import org.springframework.stereotype.Service;
23 import org.springframework.transaction.annotation.Propagation;
24 import org.springframework.transaction.annotation.Transactional;
25
26 import eu.etaxonomy.cdm.api.service.config.ITaxonServiceConfigurator;
27 import eu.etaxonomy.cdm.api.service.config.MatchingTaxonConfigurator;
28 import eu.etaxonomy.cdm.api.service.pager.Pager;
29 import eu.etaxonomy.cdm.api.service.pager.impl.DefaultPagerImpl;
30 import eu.etaxonomy.cdm.common.IProgressMonitor;
31 import eu.etaxonomy.cdm.model.common.CdmBase;
32 import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
33 import eu.etaxonomy.cdm.model.common.OrderedTermVocabulary;
34 import eu.etaxonomy.cdm.model.common.RelationshipBase;
35 import eu.etaxonomy.cdm.model.common.RelationshipBase.Direction;
36 import eu.etaxonomy.cdm.model.common.UuidAndTitleCache;
37 import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
38 import eu.etaxonomy.cdm.model.description.TaxonDescription;
39 import eu.etaxonomy.cdm.model.media.Media;
40 import eu.etaxonomy.cdm.model.media.MediaRepresentation;
41 import eu.etaxonomy.cdm.model.media.MediaUtils;
42 import eu.etaxonomy.cdm.model.name.HomotypicalGroup;
43 import eu.etaxonomy.cdm.model.name.Rank;
44 import eu.etaxonomy.cdm.model.name.TaxonNameBase;
45 import eu.etaxonomy.cdm.model.reference.Reference;
46 import eu.etaxonomy.cdm.model.taxon.Classification;
47 import eu.etaxonomy.cdm.model.taxon.Synonym;
48 import eu.etaxonomy.cdm.model.taxon.SynonymRelationship;
49 import eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType;
50 import eu.etaxonomy.cdm.model.taxon.Taxon;
51 import eu.etaxonomy.cdm.model.taxon.TaxonBase;
52 import eu.etaxonomy.cdm.model.taxon.TaxonNode;
53 import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;
54 import eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType;
55 import eu.etaxonomy.cdm.persistence.dao.common.IOrderedTermVocabularyDao;
56 import eu.etaxonomy.cdm.persistence.dao.name.ITaxonNameDao;
57 import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao;
58 import eu.etaxonomy.cdm.persistence.fetch.CdmFetch;
59 import eu.etaxonomy.cdm.persistence.query.MatchMode;
60 import eu.etaxonomy.cdm.persistence.query.OrderHint;
61 import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
62
63
64 /**
65 * @author a.kohlbecker
66 * @date 10.09.2010
67 *
68 */
69 @Service
70 @Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
71 public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDao> implements ITaxonService{
72 private static final Logger logger = Logger.getLogger(TaxonServiceImpl.class);
73
74 @Autowired
75 private ITaxonNameDao nameDao;
76
77 @Autowired
78 private IOrderedTermVocabularyDao orderedVocabularyDao;
79
80 @Autowired
81 private INameService nameService;
82
83 /**
84 * Constructor
85 */
86 public TaxonServiceImpl(){
87 if (logger.isDebugEnabled()) { logger.debug("Load TaxonService Bean"); }
88 }
89
90 /**
91 * FIXME Candidate for harmonization
92 * rename searchByName ?
93 */
94 public List<TaxonBase> searchTaxaByName(String name, Reference sec) {
95 return dao.getTaxaByName(name, sec);
96 }
97
98 /**
99 * FIXME Candidate for harmonization
100 * list(Synonym.class, ...)
101 * (non-Javadoc)
102 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllSynonyms(int, int)
103 */
104 public List<Synonym> getAllSynonyms(int limit, int start) {
105 return dao.getAllSynonyms(limit, start);
106 }
107
108 /**
109 * FIXME Candidate for harmonization
110 * list(Taxon.class, ...)
111 * (non-Javadoc)
112 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllTaxa(int, int)
113 */
114 public List<Taxon> getAllTaxa(int limit, int start) {
115 return dao.getAllTaxa(limit, start);
116 }
117
118 /**
119 * FIXME Candidate for harmonization
120 * merge with getRootTaxa(Reference sec, ..., ...)
121 * (non-Javadoc)
122 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getRootTaxa(eu.etaxonomy.cdm.model.reference.Reference, boolean)
123 */
124 public List<Taxon> getRootTaxa(Reference sec, CdmFetch cdmFetch, boolean onlyWithChildren) {
125 if (cdmFetch == null){
126 cdmFetch = CdmFetch.NO_FETCH();
127 }
128 return dao.getRootTaxa(sec, cdmFetch, onlyWithChildren, false);
129 }
130
131
132 /* (non-Javadoc)
133 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getRootTaxa(eu.etaxonomy.cdm.model.name.Rank, eu.etaxonomy.cdm.model.reference.Reference, boolean, boolean)
134 */
135 public List<Taxon> getRootTaxa(Rank rank, Reference sec, boolean onlyWithChildren,boolean withMisapplications, List<String> propertyPaths) {
136 return dao.getRootTaxa(rank, sec, null, onlyWithChildren, withMisapplications, propertyPaths);
137 }
138
139 /* (non-Javadoc)
140 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllRelationships(int, int)
141 */
142 public List<RelationshipBase> getAllRelationships(int limit, int start){
143 return dao.getAllRelationships(limit, start);
144 }
145
146 /**
147 * FIXME Candidate for harmonization
148 * is this the same as termService.getVocabulary(VocabularyEnum.TaxonRelationshipType) ?
149 */
150 @Deprecated
151 public OrderedTermVocabulary<TaxonRelationshipType> getTaxonRelationshipTypeVocabulary() {
152
153 String taxonRelTypeVocabularyId = "15db0cf7-7afc-4a86-a7d4-221c73b0c9ac";
154 UUID uuid = UUID.fromString(taxonRelTypeVocabularyId);
155 OrderedTermVocabulary<TaxonRelationshipType> taxonRelTypeVocabulary =
156 (OrderedTermVocabulary)orderedVocabularyDao.findByUuid(uuid);
157 return taxonRelTypeVocabulary;
158 }
159
160
161
162 /*
163 * (non-Javadoc)
164 * @see eu.etaxonomy.cdm.api.service.ITaxonService#swapSynonymWithAcceptedTaxon(eu.etaxonomy.cdm.model.taxon.Synonym)
165 */
166 @Transactional(readOnly = false)
167 public void swapSynonymAndAcceptedTaxon(Synonym synonym, Taxon acceptedTaxon){
168
169 TaxonNameBase synonymName = synonym.getName();
170 synonymName.removeTaxonBase(synonym);
171 TaxonNameBase taxonName = acceptedTaxon.getName();
172 taxonName.removeTaxonBase(acceptedTaxon);
173
174 synonym.setName(taxonName);
175 acceptedTaxon.setName(synonymName);
176
177 // the accepted taxon needs a new uuid because the concept has changed
178 // FIXME this leads to an error "HibernateException: immutable natural identifier of an instance of eu.etaxonomy.cdm.model.taxon.Taxon was altered"
179 //acceptedTaxon.setUuid(UUID.randomUUID());
180 }
181
182
183 /* (non-Javadoc)
184 * @see eu.etaxonomy.cdm.api.service.ITaxonService#changeSynonymToAcceptedTaxon(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon)
185 */
186 //TODO correct delete handling still needs to be implemented / checked
187 @Override
188 @Transactional(readOnly = false)
189 public Taxon changeSynonymToAcceptedTaxon(Synonym synonym, Taxon acceptedTaxon, boolean deleteSynonym, boolean copyCitationInfo, Reference citation, String microCitation) throws IllegalArgumentException{
190
191 TaxonNameBase<?,?> acceptedName = acceptedTaxon.getName();
192 TaxonNameBase<?,?> synonymName = synonym.getName();
193 HomotypicalGroup synonymHomotypicGroup = synonymName.getHomotypicalGroup();
194
195 //check synonym is not homotypic
196 if (acceptedName.getHomotypicalGroup().equals(synonymHomotypicGroup)){
197 String message = "The accepted taxon and the synonym are part of the same homotypical group and therefore can not be both accepted.";
198 throw new IllegalArgumentException(message);
199 }
200
201 Taxon newAcceptedTaxon = Taxon.NewInstance(synonymName, acceptedTaxon.getSec());
202
203 SynonymRelationshipType relTypeForGroup = SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF();
204 List<Synonym> heteroSynonyms = acceptedTaxon.getSynonymsInGroup(synonymHomotypicGroup);
205
206 for (Synonym heteroSynonym : heteroSynonyms){
207 if (synonym.equals(heteroSynonym)){
208 acceptedTaxon.removeSynonym(heteroSynonym, false);
209 }else{
210 //move synonyms in same homotypic group to new accepted taxon
211 heteroSynonym.replaceAcceptedTaxon(newAcceptedTaxon, relTypeForGroup, copyCitationInfo, citation, microCitation);
212 }
213 }
214
215 //synonym.getName().removeTaxonBase(synonym);
216 //TODO correct delete handling still needs to be implemented / checked
217 if (deleteSynonym){
218 // deleteSynonym(synonym, taxon, false);
219 try {
220 this.dao.flush();
221 this.delete(synonym);
222
223 } catch (Exception e) {
224 logger.info("Can't delete old synonym from database");
225 }
226 }
227
228 return newAcceptedTaxon;
229 }
230
231
232 public Taxon changeSynonymToRelatedTaxon(Synonym synonym, Taxon toTaxon, TaxonRelationshipType taxonRelationshipType, Reference citation, String microcitation){
233
234 // Get name from synonym
235 TaxonNameBase<?, ?> synonymName = synonym.getName();
236
237 // remove synonym from taxon
238 toTaxon.removeSynonym(synonym);
239
240 // Create a taxon with synonym name
241 Taxon fromTaxon = Taxon.NewInstance(synonymName, null);
242
243 // Add taxon relation
244 fromTaxon.addTaxonRelation(toTaxon, taxonRelationshipType, citation, microcitation);
245
246 // since we are swapping names, we have to detach the name from the synonym completely.
247 // Otherwise the synonym will still be in the list of typified names.
248 synonym.getName().removeTaxonBase(synonym);
249
250 return fromTaxon;
251 }
252
253
254 /* (non-Javadoc)
255 * @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)
256 */
257 @Transactional(readOnly = false)
258 @Override
259 public void changeHomotypicalGroupOfSynonym(Synonym synonym, HomotypicalGroup newHomotypicalGroup, Taxon targetTaxon,
260 boolean removeFromOtherTaxa, boolean setBasionymRelationIfApplicable){
261 // Get synonym name
262 TaxonNameBase synonymName = synonym.getName();
263 HomotypicalGroup oldHomotypicalGroup = synonymName.getHomotypicalGroup();
264
265
266 // Switch groups
267 oldHomotypicalGroup.removeTypifiedName(synonymName);
268 newHomotypicalGroup.addTypifiedName(synonymName);
269
270 //remove existing basionym relationships
271 synonymName.removeBasionyms();
272
273 //add basionym relationship
274 if (setBasionymRelationIfApplicable){
275 Set<TaxonNameBase> basionyms = newHomotypicalGroup.getBasionyms();
276 for (TaxonNameBase basionym : basionyms){
277 synonymName.addBasionym(basionym);
278 }
279 }
280
281 //set synonym relationship correctly
282 // SynonymRelationship relToTaxon = null;
283 boolean relToTargetTaxonExists = false;
284 Set<SynonymRelationship> existingRelations = synonym.getSynonymRelations();
285 for (SynonymRelationship rel : existingRelations){
286 Taxon acceptedTaxon = rel.getAcceptedTaxon();
287 boolean isTargetTaxon = acceptedTaxon != null && acceptedTaxon.equals(targetTaxon);
288 HomotypicalGroup acceptedGroup = acceptedTaxon.getHomotypicGroup();
289 boolean isHomotypicToTaxon = acceptedGroup.equals(newHomotypicalGroup);
290 SynonymRelationshipType newRelationType = isHomotypicToTaxon? SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF() : SynonymRelationshipType.HETEROTYPIC_SYNONYM_OF();
291 rel.setType(newRelationType);
292 //TODO handle citation and microCitation
293
294 if (isTargetTaxon){
295 relToTargetTaxonExists = true;
296 }else{
297 if (removeFromOtherTaxa){
298 acceptedTaxon.removeSynonym(synonym, false);
299 }else{
300 //do nothing
301 }
302 }
303 }
304 if (targetTaxon != null && ! relToTargetTaxonExists ){
305 Taxon acceptedTaxon = targetTaxon;
306 HomotypicalGroup acceptedGroup = acceptedTaxon.getHomotypicGroup();
307 boolean isHomotypicToTaxon = acceptedGroup.equals(newHomotypicalGroup);
308 SynonymRelationshipType relType = isHomotypicToTaxon? SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF() : SynonymRelationshipType.HETEROTYPIC_SYNONYM_OF();
309 //TODO handle citation and microCitation
310 Reference citation = null;
311 String microCitation = null;
312 acceptedTaxon.addSynonym(synonym, relType, citation, microCitation);
313 }
314
315 }
316
317
318 /* (non-Javadoc)
319 * @see eu.etaxonomy.cdm.api.service.IIdentifiableEntityService#updateTitleCache(java.lang.Integer, eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy)
320 */
321 @Override
322 public void updateTitleCache(Class<? extends TaxonBase> clazz, Integer stepSize, IIdentifiableEntityCacheStrategy<TaxonBase> cacheStrategy, IProgressMonitor monitor) {
323 if (clazz == null){
324 clazz = TaxonBase.class;
325 }
326 super.updateTitleCacheImpl(clazz, stepSize, cacheStrategy, monitor);
327 }
328
329 @Autowired
330 protected void setDao(ITaxonDao dao) {
331 this.dao = dao;
332 }
333
334 /* (non-Javadoc)
335 * @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)
336 */
337 public Pager<TaxonBase> findTaxaByName(Class<? extends TaxonBase> clazz, String uninomial, String infragenericEpithet, String specificEpithet, String infraspecificEpithet, Rank rank, Integer pageSize,Integer pageNumber) {
338 Integer numberOfResults = dao.countTaxaByName(clazz, uninomial, infragenericEpithet, specificEpithet, infraspecificEpithet, rank);
339
340 List<TaxonBase> results = new ArrayList<TaxonBase>();
341 if(numberOfResults > 0) { // no point checking again
342 results = dao.findTaxaByName(clazz, uninomial, infragenericEpithet, specificEpithet, infraspecificEpithet, rank, pageSize, pageNumber);
343 }
344
345 return new DefaultPagerImpl<TaxonBase>(pageNumber, numberOfResults, pageSize, results);
346 }
347
348 /* (non-Javadoc)
349 * @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)
350 */
351 public List<TaxonBase> listTaxaByName(Class<? extends TaxonBase> clazz, String uninomial, String infragenericEpithet, String specificEpithet, String infraspecificEpithet, Rank rank, Integer pageSize,Integer pageNumber) {
352 Integer numberOfResults = dao.countTaxaByName(clazz, uninomial, infragenericEpithet, specificEpithet, infraspecificEpithet, rank);
353
354 List<TaxonBase> results = new ArrayList<TaxonBase>();
355 if(numberOfResults > 0) { // no point checking again
356 results = dao.findTaxaByName(clazz, uninomial, infragenericEpithet, specificEpithet, infraspecificEpithet, rank, pageSize, pageNumber);
357 }
358
359 return results;
360 }
361
362 /* (non-Javadoc)
363 * @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)
364 */
365 public List<TaxonRelationship> listToTaxonRelationships(Taxon taxon, TaxonRelationshipType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths){
366 Integer numberOfResults = dao.countTaxonRelationships(taxon, type, TaxonRelationship.Direction.relatedTo);
367
368 List<TaxonRelationship> results = new ArrayList<TaxonRelationship>();
369 if(numberOfResults > 0) { // no point checking again
370 results = dao.getTaxonRelationships(taxon, type, pageSize, pageNumber, orderHints, propertyPaths, TaxonRelationship.Direction.relatedTo);
371 }
372 return results;
373 }
374
375 /* (non-Javadoc)
376 * @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)
377 */
378 public Pager<TaxonRelationship> pageToTaxonRelationships(Taxon taxon, TaxonRelationshipType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
379 Integer numberOfResults = dao.countTaxonRelationships(taxon, type, TaxonRelationship.Direction.relatedTo);
380
381 List<TaxonRelationship> results = new ArrayList<TaxonRelationship>();
382 if(numberOfResults > 0) { // no point checking again
383 results = dao.getTaxonRelationships(taxon, type, pageSize, pageNumber, orderHints, propertyPaths, TaxonRelationship.Direction.relatedTo);
384 }
385 return new DefaultPagerImpl<TaxonRelationship>(pageNumber, numberOfResults, pageSize, results);
386 }
387
388 /* (non-Javadoc)
389 * @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)
390 */
391 public List<TaxonRelationship> listFromTaxonRelationships(Taxon taxon, TaxonRelationshipType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths){
392 Integer numberOfResults = dao.countTaxonRelationships(taxon, type, TaxonRelationship.Direction.relatedFrom);
393
394 List<TaxonRelationship> results = new ArrayList<TaxonRelationship>();
395 if(numberOfResults > 0) { // no point checking again
396 results = dao.getTaxonRelationships(taxon, type, pageSize, pageNumber, orderHints, propertyPaths, TaxonRelationship.Direction.relatedFrom);
397 }
398 return results;
399 }
400
401 /* (non-Javadoc)
402 * @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)
403 */
404 public Pager<TaxonRelationship> pageFromTaxonRelationships(Taxon taxon, TaxonRelationshipType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
405 Integer numberOfResults = dao.countTaxonRelationships(taxon, type, TaxonRelationship.Direction.relatedFrom);
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.relatedFrom);
410 }
411 return new DefaultPagerImpl<TaxonRelationship>(pageNumber, numberOfResults, pageSize, results);
412 }
413
414 /* (non-Javadoc)
415 * @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)
416 */
417 public Pager<SynonymRelationship> getSynonyms(Taxon taxon, SynonymRelationshipType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
418 Integer numberOfResults = dao.countSynonyms(taxon, type);
419
420 List<SynonymRelationship> results = new ArrayList<SynonymRelationship>();
421 if(numberOfResults > 0) { // no point checking again
422 results = dao.getSynonyms(taxon, type, pageSize, pageNumber, orderHints, propertyPaths);
423 }
424
425 return new DefaultPagerImpl<SynonymRelationship>(pageNumber, numberOfResults, pageSize, results);
426 }
427
428 /* (non-Javadoc)
429 * @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)
430 */
431 public Pager<SynonymRelationship> getSynonyms(Synonym synonym, SynonymRelationshipType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
432 Integer numberOfResults = dao.countSynonyms(synonym, type);
433
434 List<SynonymRelationship> results = new ArrayList<SynonymRelationship>();
435 if(numberOfResults > 0) { // no point checking again
436 results = dao.getSynonyms(synonym, type, pageSize, pageNumber, orderHints, propertyPaths);
437 }
438
439 return new DefaultPagerImpl<SynonymRelationship>(pageNumber, numberOfResults, pageSize, results);
440 }
441
442 /* (non-Javadoc)
443 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getHomotypicSynonymsByHomotypicGroup(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.List)
444 */
445 public List<Synonym> getHomotypicSynonymsByHomotypicGroup(Taxon taxon, List<String> propertyPaths){
446 Taxon t = (Taxon)dao.load(taxon.getUuid(), propertyPaths);
447 return t.getHomotypicSynonymsByHomotypicGroup();
448 }
449
450 /* (non-Javadoc)
451 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getHeterotypicSynonymyGroups(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.List)
452 */
453 public List<List<Synonym>> getHeterotypicSynonymyGroups(Taxon taxon, List<String> propertyPaths){
454 Taxon t = (Taxon)dao.load(taxon.getUuid(), propertyPaths);
455 List<HomotypicalGroup> homotypicalGroups = t.getHeterotypicSynonymyGroups();
456 List<List<Synonym>> heterotypicSynonymyGroups = new ArrayList<List<Synonym>>(homotypicalGroups.size());
457 for(HomotypicalGroup homotypicalGroup : homotypicalGroups){
458 heterotypicSynonymyGroups.add(t.getSynonymsInGroup(homotypicalGroup));
459 }
460 return heterotypicSynonymyGroups;
461 }
462
463 public List<UuidAndTitleCache<TaxonBase>> findTaxaAndNamesForEditor(ITaxonServiceConfigurator configurator){
464
465 List<UuidAndTitleCache<TaxonBase>> result = new ArrayList<UuidAndTitleCache<TaxonBase>>();
466 Class<? extends TaxonBase> clazz = null;
467 if ((configurator.isDoTaxa() && configurator.isDoSynonyms())) {
468 clazz = TaxonBase.class;
469 //propertyPath.addAll(configurator.getTaxonPropertyPath());
470 //propertyPath.addAll(configurator.getSynonymPropertyPath());
471 } else if(configurator.isDoTaxa()) {
472 clazz = Taxon.class;
473 //propertyPath = configurator.getTaxonPropertyPath();
474 } else if (configurator.isDoSynonyms()) {
475 clazz = Synonym.class;
476 //propertyPath = configurator.getSynonymPropertyPath();
477 }
478
479
480 result = dao.getTaxaByNameForEditor(clazz, configurator.getTitleSearchStringSqlized(), configurator.getClassification(), configurator.getMatchMode(), configurator.getNamedAreas());
481 return result;
482 }
483
484 /* (non-Javadoc)
485 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxaAndNames(eu.etaxonomy.cdm.api.service.config.ITaxonServiceConfigurator)
486 */
487 public Pager<IdentifiableEntity> findTaxaAndNames(ITaxonServiceConfigurator configurator) {
488
489 List<IdentifiableEntity> results = new ArrayList<IdentifiableEntity>();
490 int numberOfResults = 0; // overall number of results (as opposed to number of results per page)
491 List<TaxonBase> taxa = null;
492
493 // Taxa and synonyms
494 long numberTaxaResults = 0L;
495
496 Class<? extends TaxonBase> clazz = null;
497 List<String> propertyPath = new ArrayList<String>();
498 if(configurator.getTaxonPropertyPath() != null){
499 propertyPath.addAll(configurator.getTaxonPropertyPath());
500 }
501 if ((configurator.isDoTaxa() && configurator.isDoSynonyms())) {
502 clazz = TaxonBase.class;
503 //propertyPath.addAll(configurator.getTaxonPropertyPath());
504 //propertyPath.addAll(configurator.getSynonymPropertyPath());
505 } else if(configurator.isDoTaxa()) {
506 clazz = Taxon.class;
507 //propertyPath = configurator.getTaxonPropertyPath();
508 } else if (configurator.isDoSynonyms()) {
509 clazz = Synonym.class;
510 //propertyPath = configurator.getSynonymPropertyPath();
511 }
512
513 if(clazz != null){
514 if(configurator.getPageSize() != null){ // no point counting if we need all anyway
515 numberTaxaResults =
516 dao.countTaxaByName(clazz,
517 configurator.getTitleSearchStringSqlized(), configurator.getClassification(), configurator.getMatchMode(),
518 configurator.getNamedAreas());
519 }
520
521 if(configurator.getPageSize() == null || numberTaxaResults > configurator.getPageSize() * configurator.getPageNumber()){ // no point checking again if less results
522 taxa = dao.getTaxaByName(clazz,
523 configurator.getTitleSearchStringSqlized(), configurator.getClassification(), configurator.getMatchMode(),
524 configurator.getNamedAreas(), configurator.getPageSize(),
525 configurator.getPageNumber(), propertyPath);
526 }
527 }
528
529 if (logger.isDebugEnabled()) { logger.debug(numberTaxaResults + " matching taxa counted"); }
530
531 if(taxa != null){
532 results.addAll(taxa);
533 }
534
535 numberOfResults += numberTaxaResults;
536
537 // Names without taxa
538 if (configurator.isDoNamesWithoutTaxa()) {
539 int numberNameResults = 0;
540
541 List<? extends TaxonNameBase<?,?>> names =
542 nameDao.findByName(configurator.getTitleSearchStringSqlized(), configurator.getMatchMode(),
543 configurator.getPageSize(), configurator.getPageNumber(), null, configurator.getTaxonNamePropertyPath());
544 if (logger.isDebugEnabled()) { logger.debug(names.size() + " matching name(s) found"); }
545 if (names.size() > 0) {
546 for (TaxonNameBase<?,?> taxonName : names) {
547 if (taxonName.getTaxonBases().size() == 0) {
548 results.add(taxonName);
549 numberNameResults++;
550 }
551 }
552 if (logger.isDebugEnabled()) { logger.debug(numberNameResults + " matching name(s) without taxa found"); }
553 numberOfResults += numberNameResults;
554 }
555 }
556
557 // Taxa from common names
558
559 if (configurator.isDoTaxaByCommonNames()) {
560 taxa = null;
561 numberTaxaResults = 0;
562 if(configurator.getPageSize() != null){// no point counting if we need all anyway
563 numberTaxaResults = dao.countTaxaByCommonName(configurator.getTitleSearchStringSqlized(), configurator.getClassification(), configurator.getMatchMode(), configurator.getNamedAreas());
564 }
565 if(configurator.getPageSize() == null || numberTaxaResults > configurator.getPageSize() * configurator.getPageNumber()){
566 taxa = dao.getTaxaByCommonName(configurator.getTitleSearchStringSqlized(), configurator.getClassification(), configurator.getMatchMode(), configurator.getNamedAreas(), configurator.getPageSize(), configurator.getPageNumber(), configurator.getTaxonPropertyPath());
567 }
568 if(taxa != null){
569 results.addAll(taxa);
570 }
571 numberOfResults += numberTaxaResults;
572
573 }
574
575 return new DefaultPagerImpl<IdentifiableEntity>
576 (configurator.getPageNumber(), numberOfResults, configurator.getPageSize(), results);
577 }
578
579 public List<UuidAndTitleCache<TaxonBase>> getTaxonUuidAndTitleCache(){
580 return dao.getUuidAndTitleCache();
581 }
582
583 /* (non-Javadoc)
584 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllMedia(eu.etaxonomy.cdm.model.taxon.Taxon, int, int, int, java.lang.String[])
585 */
586 public List<MediaRepresentation> getAllMedia(Taxon taxon, int size, int height, int widthOrDuration, String[] mimeTypes){
587 List<MediaRepresentation> medRep = new ArrayList<MediaRepresentation>();
588 taxon = (Taxon)dao.load(taxon.getUuid());
589 Set<TaxonDescription> descriptions = taxon.getDescriptions();
590 for (TaxonDescription taxDesc: descriptions){
591 Set<DescriptionElementBase> elements = taxDesc.getElements();
592 for (DescriptionElementBase descElem: elements){
593 for(Media media : descElem.getMedia()){
594
595 //find the best matching representation
596 medRep.add(MediaUtils.findBestMatchingRepresentation(media, null, size, height, widthOrDuration, mimeTypes));
597
598 }
599 }
600 }
601 return medRep;
602 }
603
604 /* (non-Javadoc)
605 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxaByID(java.util.Set)
606 */
607 public List<TaxonBase> findTaxaByID(Set<Integer> listOfIDs) {
608 return this.dao.findById(listOfIDs);
609 }
610
611 /* (non-Javadoc)
612 * @see eu.etaxonomy.cdm.api.service.ITaxonService#countAllRelationships()
613 */
614 public int countAllRelationships() {
615 return this.dao.countAllRelationships();
616 }
617
618 /* (non-Javadoc)
619 * @see eu.etaxonomy.cdm.api.service.ITaxonService#createAllInferredSynonyms(eu.etaxonomy.cdm.model.taxon.Classification, eu.etaxonomy.cdm.model.taxon.Taxon)
620 */
621 public List<Synonym> createAllInferredSynonyms(Classification tree,
622 Taxon taxon) {
623
624 return this.dao.createAllInferredSynonyms(taxon, tree);
625 }
626
627 /* (non-Javadoc)
628 * @see eu.etaxonomy.cdm.api.service.ITaxonService#createInferredSynonyms(eu.etaxonomy.cdm.model.taxon.Classification, eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType)
629 */
630 public List<Synonym> createInferredSynonyms(Classification tree, Taxon taxon, SynonymRelationshipType type) {
631
632 return this.dao.createInferredSynonyms(taxon, tree, type);
633 }
634
635 /* (non-Javadoc)
636 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findIdenticalTaxonNames(java.util.List)
637 */
638 public List<TaxonNameBase> findIdenticalTaxonNames(List<String> propertyPath) {
639
640 return this.dao.findIdenticalTaxonNames(propertyPath);
641 }
642
643
644 /* (non-Javadoc)
645 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonym(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.model.taxon.Synonym, boolean)
646 */
647 //TODO move to dao??
648 @Transactional(readOnly = false)
649 @Override
650 public void deleteSynonym(Synonym synonym, Taxon taxon, boolean removeNameIfPossible) {
651 //remove synonymRelationship
652 Set<Taxon> taxonSet = new HashSet<Taxon>();
653 if (taxon != null){
654 taxonSet.add(taxon);
655 }else{
656 taxonSet.addAll(synonym.getAcceptedTaxa());
657 }
658 Set<SynonymRelationship> synRels = synonym.getSynonymRelations();
659 for (Taxon taxon2 : taxonSet){
660 dao.deleteSynonymRelationships(synonym, taxon2);
661 }
662
663 //TODO remove name from homotypical group?
664
665 //remove synonym (if necessary)
666 if (synonym.getSynonymRelations().isEmpty()){
667 dao.delete(synonym);
668 }
669
670 if (removeNameIfPossible){
671 TaxonNameBase name = synonym.getName();
672 nameService.delete(name);
673 //check is used
674 //name relationship
675 //concept
676 //descriptionElementSource
677 //
678 }
679 }
680
681
682 /* (non-Javadoc)
683 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findIdenticalTaxonNameIds(java.util.List)
684 */
685 public List<TaxonNameBase> findIdenticalTaxonNameIds(List<String> propertyPath) {
686
687 return this.dao.findIdenticalNamesNew(propertyPath);
688 }
689
690 /* (non-Javadoc)
691 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getPhylumName(eu.etaxonomy.cdm.model.name.TaxonNameBase)
692 */
693 public String getPhylumName(TaxonNameBase name){
694 return this.dao.getPhylumName(name);
695 }
696
697 /* (non-Javadoc)
698 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonymRelationships(eu.etaxonomy.cdm.model.taxon.Synonym)
699 */
700 public long deleteSynonymRelationships(Synonym syn) {
701 return dao.deleteSynonymRelationships(syn, null);
702 }
703
704
705 /* (non-Javadoc)
706 * @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)
707 */
708 public List<SynonymRelationship> listSynonymRelationships(
709 TaxonBase taxonBase, SynonymRelationshipType type, Integer pageSize, Integer pageNumber,
710 List<OrderHint> orderHints, List<String> propertyPaths, Direction direction) {
711 Integer numberOfResults = dao.countSynonymRelationships(taxonBase, type, direction);
712
713 List<SynonymRelationship> results = new ArrayList<SynonymRelationship>();
714 if(numberOfResults > 0) { // no point checking again
715 results = dao.getSynonymRelationships(taxonBase, type, pageSize, pageNumber, orderHints, propertyPaths, direction);
716 }
717 return results;
718 }
719
720 /* (non-Javadoc)
721 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findBestMatchingTaxon(java.lang.String)
722 */
723 @Override
724 public Taxon findBestMatchingTaxon(String taxonName) {
725 MatchingTaxonConfigurator config = MatchingTaxonConfigurator.NewInstance();
726 config.setTaxonNameTitle(taxonName);
727 return findBestMatchingTaxon(config);
728 }
729
730
731
732 @Override
733 public Taxon findBestMatchingTaxon(MatchingTaxonConfigurator config) {
734
735 Taxon bestCandidate = null;
736 try{
737 // 1. search for acceptet taxa
738 List<TaxonBase> taxonList = dao.findByNameTitleCache(Taxon.class, config.getTaxonNameTitle(), null, MatchMode.EXACT, null, 0, null, null);
739 boolean bestCandidateMatchesSecUuid = false;
740 boolean bestCandidateIsInClassification = false;
741 int countEqualCandidates = 0;
742 for(TaxonBase taxonBaseCandidate : taxonList){
743 if(taxonBaseCandidate instanceof Taxon){
744 Taxon newCanditate = CdmBase.deproxy(taxonBaseCandidate, Taxon.class);
745 boolean newCandidateMatchesSecUuid = isMatchesSecUuid(newCanditate, config);
746 if (! newCandidateMatchesSecUuid && config.isOnlyMatchingSecUuid() ){
747 continue;
748 }else if(newCandidateMatchesSecUuid && ! bestCandidateMatchesSecUuid){
749 bestCandidate = newCanditate;
750 countEqualCandidates = 1;
751 bestCandidateMatchesSecUuid = true;
752 continue;
753 }
754
755 boolean newCandidateInClassification = isInClassification(newCanditate, config);
756 if (! newCandidateInClassification && config.isOnlyMatchingClassificationUuid()){
757 continue;
758 }else if (newCandidateInClassification && ! bestCandidateIsInClassification){
759 bestCandidate = newCanditate;
760 countEqualCandidates = 1;
761 bestCandidateIsInClassification = true;
762 continue;
763 }
764 if (bestCandidate == null){
765 bestCandidate = newCanditate;
766 countEqualCandidates = 1;
767 continue;
768 }
769
770 }else{ //not Taxon.class
771 continue;
772 }
773 countEqualCandidates++;
774
775 }
776 if (bestCandidate != null){
777 if(countEqualCandidates > 1){
778 logger.info(countEqualCandidates + " equally matching TaxonBases found, using first accepted Taxon: " + bestCandidate.getTitleCache());
779 return bestCandidate;
780 } else {
781 logger.info("using accepted Taxon: " + bestCandidate.getTitleCache());
782 return bestCandidate;
783 }
784 }
785
786
787 // 2. search for synonyms
788 if (config.isIncludeSynonyms()){
789 List<TaxonBase> synonymList = dao.findByNameTitleCache(Synonym.class, config.getTaxonNameTitle(), null, MatchMode.EXACT, null, 0, null, null);
790 for(TaxonBase taxonBase : synonymList){
791 if(taxonBase instanceof Synonym){
792 Synonym synonym = CdmBase.deproxy(taxonBase, Synonym.class);
793 Set<Taxon> acceptetdCandidates = synonym.getAcceptedTaxa();
794 if(!acceptetdCandidates.isEmpty()){
795 bestCandidate = acceptetdCandidates.iterator().next();
796 if(acceptetdCandidates.size() == 1){
797 logger.info(acceptetdCandidates.size() + " Accepted taxa found for synonym " + taxonBase.getTitleCache() + ", using first one: " + bestCandidate.getTitleCache());
798 return bestCandidate;
799 } else {
800 logger.info("using accepted Taxon " + bestCandidate.getTitleCache() + "for synonym " + taxonBase.getTitleCache());
801 return bestCandidate;
802 }
803 //TODO extend method: search using treeUUID, using SecUUID, first find accepted then include synonyms until a matching taxon is found
804 }
805 }
806 }
807 }
808
809 } catch (Exception e){
810 logger.error(e);
811 }
812
813 return bestCandidate;
814 }
815
816 private boolean isInClassification(Taxon taxon, MatchingTaxonConfigurator config) {
817 UUID configClassificationUuid = config.getClassificationUuid();
818 if (configClassificationUuid == null){
819 return false;
820 }
821 for (TaxonNode node : taxon.getTaxonNodes()){
822 UUID classUuid = node.getClassification().getUuid();
823 if (configClassificationUuid.equals(classUuid)){
824 return true;
825 }
826 }
827 return false;
828 }
829
830 private boolean isMatchesSecUuid(Taxon taxon, MatchingTaxonConfigurator config) {
831 UUID configSecUuid = config.getSecUuid();
832 if (configSecUuid == null){
833 return false;
834 }
835 UUID taxonSecUuid = (taxon.getSec() == null)? null : taxon.getSec().getUuid();
836 return configSecUuid.equals(taxonSecUuid);
837 }
838
839 /* (non-Javadoc)
840 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findBestMatchingSynonym(java.lang.String)
841 */
842 @Override
843 public Synonym findBestMatchingSynonym(String taxonName) {
844 List<TaxonBase> synonymList = dao.findByNameTitleCache(Synonym.class, taxonName, null, MatchMode.EXACT, null, 0, null, null);
845 if(! synonymList.isEmpty()){
846 Synonym result = CdmBase.deproxy(synonymList.iterator().next(), Synonym.class);
847 if(synonymList.size() == 1){
848 logger.info(synonymList.size() + " Synonym found " + result.getTitleCache() );
849 return result;
850 } else {
851 logger.info("Several matching synonyms found. Using first: " + result.getTitleCache());
852 return result;
853 }
854 }
855 return null;
856 }
857
858 /* (non-Javadoc)
859 * @see eu.etaxonomy.cdm.api.service.ITaxonService#moveSynonymToAnotherTaxon(eu.etaxonomy.cdm.model.taxon.SynonymRelationship, eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.model.reference.Reference, java.lang.String)
860 */
861 @Override
862 public Taxon moveSynonymToAnotherTaxon(SynonymRelationship synonymRelation,
863 Taxon toTaxon, SynonymRelationshipType synonymRelationshipType, Reference reference, String referenceDetail) {
864 Taxon fromTaxon = synonymRelation.getAcceptedTaxon();
865
866 toTaxon.addSynonym(synonymRelation.getSynonym(), synonymRelationshipType, reference, referenceDetail);
867
868 fromTaxon.removeSynonymRelation(synonymRelation);
869
870 return toTaxon;
871 }
872
873 /* (non-Javadoc)
874 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getUuidAndTitleCacheTaxon()
875 */
876 @Override
877 public List<UuidAndTitleCache<TaxonBase>> getUuidAndTitleCacheTaxon() {
878 return dao.getUuidAndTitleCacheTaxon();
879 }
880
881 /* (non-Javadoc)
882 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getUuidAndTitleCacheSynonym()
883 */
884 @Override
885 public List<UuidAndTitleCache<TaxonBase>> getUuidAndTitleCacheSynonym() {
886 return dao.getUuidAndTitleCacheSynonym();
887 }
888
889 }