change some names in molecular and update the update script
[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.Map;
19 import java.util.Set;
20 import java.util.UUID;
21
22 import org.apache.log4j.Logger;
23 import org.apache.lucene.index.CorruptIndexException;
24 import org.apache.lucene.queryParser.ParseException;
25 import org.apache.lucene.search.BooleanClause.Occur;
26 import org.apache.lucene.search.BooleanQuery;
27 import org.apache.lucene.search.Query;
28 import org.apache.lucene.search.SortField;
29 import org.springframework.beans.factory.annotation.Autowired;
30 import org.springframework.stereotype.Service;
31 import org.springframework.transaction.annotation.Transactional;
32
33 import eu.etaxonomy.cdm.api.service.config.IFindTaxaAndNamesConfigurator;
34 import eu.etaxonomy.cdm.api.service.config.MatchingTaxonConfigurator;
35 import eu.etaxonomy.cdm.api.service.config.NameDeletionConfigurator;
36 import eu.etaxonomy.cdm.api.service.config.TaxonDeletionConfigurator;
37 import eu.etaxonomy.cdm.api.service.exception.DataChangeNoRollbackException;
38 import eu.etaxonomy.cdm.api.service.exception.HomotypicalGroupChangeException;
39 import eu.etaxonomy.cdm.api.service.exception.ReferencedObjectUndeletableException;
40 import eu.etaxonomy.cdm.api.service.pager.Pager;
41 import eu.etaxonomy.cdm.api.service.pager.impl.DefaultPagerImpl;
42 import eu.etaxonomy.cdm.api.service.search.ISearchResultBuilder;
43 import eu.etaxonomy.cdm.api.service.search.LuceneMultiSearch;
44 import eu.etaxonomy.cdm.api.service.search.LuceneSearch;
45 import eu.etaxonomy.cdm.api.service.search.LuceneSearch.TopGroupsWithMaxScore;
46 import eu.etaxonomy.cdm.api.service.search.QueryFactory;
47 import eu.etaxonomy.cdm.api.service.search.SearchResult;
48 import eu.etaxonomy.cdm.api.service.search.SearchResultBuilder;
49 import eu.etaxonomy.cdm.api.service.util.TaxonRelationshipEdge;
50 import eu.etaxonomy.cdm.common.monitor.IProgressMonitor;
51 import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
52 import eu.etaxonomy.cdm.hibernate.search.DefinedTermBaseClassBridge;
53 import eu.etaxonomy.cdm.hibernate.search.GroupByTaxonClassBridge;
54 import eu.etaxonomy.cdm.hibernate.search.MultilanguageTextFieldBridge;
55 import eu.etaxonomy.cdm.model.CdmBaseType;
56 import eu.etaxonomy.cdm.model.common.CdmBase;
57 import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
58 import eu.etaxonomy.cdm.model.common.IdentifiableSource;
59 import eu.etaxonomy.cdm.model.common.Language;
60 import eu.etaxonomy.cdm.model.common.OrderedTermVocabulary;
61 import eu.etaxonomy.cdm.model.common.OriginalSourceType;
62 import eu.etaxonomy.cdm.model.common.RelationshipBase;
63 import eu.etaxonomy.cdm.model.common.RelationshipBase.Direction;
64 import eu.etaxonomy.cdm.model.common.UuidAndTitleCache;
65 import eu.etaxonomy.cdm.model.description.DescriptionBase;
66 import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
67 import eu.etaxonomy.cdm.model.description.Feature;
68 import eu.etaxonomy.cdm.model.description.IIdentificationKey;
69 import eu.etaxonomy.cdm.model.description.PolytomousKeyNode;
70 import eu.etaxonomy.cdm.model.description.SpecimenDescription;
71 import eu.etaxonomy.cdm.model.description.TaxonDescription;
72 import eu.etaxonomy.cdm.model.description.TaxonInteraction;
73 import eu.etaxonomy.cdm.model.description.TaxonNameDescription;
74 import eu.etaxonomy.cdm.model.media.Media;
75 import eu.etaxonomy.cdm.model.media.MediaRepresentation;
76 import eu.etaxonomy.cdm.model.media.MediaUtils;
77 import eu.etaxonomy.cdm.model.molecular.Amplification;
78 import eu.etaxonomy.cdm.model.molecular.DnaSample;
79 import eu.etaxonomy.cdm.model.molecular.Sequence;
80 import eu.etaxonomy.cdm.model.molecular.SingleRead;
81 import eu.etaxonomy.cdm.model.name.HomotypicalGroup;
82 import eu.etaxonomy.cdm.model.name.Rank;
83 import eu.etaxonomy.cdm.model.name.TaxonNameBase;
84 import eu.etaxonomy.cdm.model.name.ZoologicalName;
85 import eu.etaxonomy.cdm.model.occurrence.DerivedUnit;
86 import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
87 import eu.etaxonomy.cdm.model.reference.Reference;
88 import eu.etaxonomy.cdm.model.taxon.Classification;
89 import eu.etaxonomy.cdm.model.taxon.Synonym;
90 import eu.etaxonomy.cdm.model.taxon.SynonymRelationship;
91 import eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType;
92 import eu.etaxonomy.cdm.model.taxon.Taxon;
93 import eu.etaxonomy.cdm.model.taxon.TaxonBase;
94 import eu.etaxonomy.cdm.model.taxon.TaxonNode;
95 import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;
96 import eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType;
97 import eu.etaxonomy.cdm.persistence.dao.AbstractBeanInitializer;
98 import eu.etaxonomy.cdm.persistence.dao.common.ICdmGenericDao;
99 import eu.etaxonomy.cdm.persistence.dao.common.IOrderedTermVocabularyDao;
100 import eu.etaxonomy.cdm.persistence.dao.name.ITaxonNameDao;
101 import eu.etaxonomy.cdm.persistence.dao.occurrence.IOccurrenceDao;
102 import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao;
103 import eu.etaxonomy.cdm.persistence.fetch.CdmFetch;
104 import eu.etaxonomy.cdm.persistence.query.MatchMode;
105 import eu.etaxonomy.cdm.persistence.query.OrderHint;
106 import eu.etaxonomy.cdm.persistence.query.OrderHint.SortOrder;
107 import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
108
109
110 /**
111 * @author a.kohlbecker
112 * @date 10.09.2010
113 *
114 */
115 @Service
116 @Transactional(readOnly = true)
117 public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDao> implements ITaxonService{
118 private static final Logger logger = Logger.getLogger(TaxonServiceImpl.class);
119
120 public static final String POTENTIAL_COMBINATION_NAMESPACE = "Potential combination";
121
122 public static final String INFERRED_EPITHET_NAMESPACE = "Inferred epithet";
123
124 public static final String INFERRED_GENUS_NAMESPACE = "Inferred genus";
125
126
127 @Autowired
128 private ITaxonNameDao nameDao;
129
130 @Autowired
131 private INameService nameService;
132
133 @Autowired
134 private ICdmGenericDao genericDao;
135
136 @Autowired
137 private IDescriptionService descriptionService;
138
139 @Autowired
140 private IOrderedTermVocabularyDao orderedVocabularyDao;
141
142 @Autowired
143 private IOccurrenceDao occurrenceDao;
144
145 @Autowired
146 private AbstractBeanInitializer beanInitializer;
147
148 /**
149 * Constructor
150 */
151 public TaxonServiceImpl(){
152 if (logger.isDebugEnabled()) { logger.debug("Load TaxonService Bean"); }
153 }
154
155 /**
156 * FIXME Candidate for harmonization
157 * rename searchByName ?
158 */
159 @Override
160 public List<TaxonBase> searchTaxaByName(String name, Reference sec) {
161 return dao.getTaxaByName(name, sec);
162 }
163
164 /**
165 * FIXME Candidate for harmonization
166 * list(Synonym.class, ...)
167 * (non-Javadoc)
168 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllSynonyms(int, int)
169 */
170 @Override
171 public List<Synonym> getAllSynonyms(int limit, int start) {
172 return dao.getAllSynonyms(limit, start);
173 }
174
175 /**
176 * FIXME Candidate for harmonization
177 * list(Taxon.class, ...)
178 * (non-Javadoc)
179 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllTaxa(int, int)
180 */
181 @Override
182 public List<Taxon> getAllTaxa(int limit, int start) {
183 return dao.getAllTaxa(limit, start);
184 }
185
186 /**
187 * FIXME Candidate for harmonization
188 * merge with getRootTaxa(Reference sec, ..., ...)
189 * (non-Javadoc)
190 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getRootTaxa(eu.etaxonomy.cdm.model.reference.Reference, boolean)
191 */
192 @Override
193 public List<Taxon> getRootTaxa(Reference sec, CdmFetch cdmFetch, boolean onlyWithChildren) {
194 if (cdmFetch == null){
195 cdmFetch = CdmFetch.NO_FETCH();
196 }
197 return dao.getRootTaxa(sec, cdmFetch, onlyWithChildren, false);
198 }
199
200
201 /* (non-Javadoc)
202 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getRootTaxa(eu.etaxonomy.cdm.model.name.Rank, eu.etaxonomy.cdm.model.reference.Reference, boolean, boolean)
203 */
204 @Override
205 public List<Taxon> getRootTaxa(Rank rank, Reference sec, boolean onlyWithChildren,boolean withMisapplications, List<String> propertyPaths) {
206 return dao.getRootTaxa(rank, sec, null, onlyWithChildren, withMisapplications, propertyPaths);
207 }
208
209 /* (non-Javadoc)
210 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllRelationships(int, int)
211 */
212 @Override
213 public List<RelationshipBase> getAllRelationships(int limit, int start){
214 return dao.getAllRelationships(limit, start);
215 }
216
217 /**
218 * FIXME Candidate for harmonization
219 * is this the same as termService.getVocabulary(VocabularyEnum.TaxonRelationshipType) ?
220 */
221 @Override
222 @Deprecated
223 public OrderedTermVocabulary<TaxonRelationshipType> getTaxonRelationshipTypeVocabulary() {
224
225 String taxonRelTypeVocabularyId = "15db0cf7-7afc-4a86-a7d4-221c73b0c9ac";
226 UUID uuid = UUID.fromString(taxonRelTypeVocabularyId);
227 OrderedTermVocabulary<TaxonRelationshipType> taxonRelTypeVocabulary =
228 (OrderedTermVocabulary)orderedVocabularyDao.findByUuid(uuid);
229 return taxonRelTypeVocabulary;
230 }
231
232
233
234 /*
235 * (non-Javadoc)
236 * @see eu.etaxonomy.cdm.api.service.ITaxonService#swapSynonymWithAcceptedTaxon(eu.etaxonomy.cdm.model.taxon.Synonym)
237 */
238 @Override
239 @Transactional(readOnly = false)
240 public void swapSynonymAndAcceptedTaxon(Synonym synonym, Taxon acceptedTaxon){
241
242 TaxonNameBase<?,?> synonymName = synonym.getName();
243 synonymName.removeTaxonBase(synonym);
244 TaxonNameBase<?,?> taxonName = acceptedTaxon.getName();
245 taxonName.removeTaxonBase(acceptedTaxon);
246
247 synonym.setName(taxonName);
248 acceptedTaxon.setName(synonymName);
249
250 // the accepted taxon needs a new uuid because the concept has changed
251 // FIXME this leads to an error "HibernateException: immutable natural identifier of an instance of eu.etaxonomy.cdm.model.taxon.Taxon was altered"
252 //acceptedTaxon.setUuid(UUID.randomUUID());
253 }
254
255
256 /* (non-Javadoc)
257 * @see eu.etaxonomy.cdm.api.service.ITaxonService#changeSynonymToAcceptedTaxon(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon)
258 */
259 //TODO correct delete handling still needs to be implemented / checked
260 @Override
261 @Transactional(readOnly = false)
262 public Taxon changeSynonymToAcceptedTaxon(Synonym synonym, Taxon acceptedTaxon, boolean deleteSynonym, boolean copyCitationInfo, Reference citation, String microCitation) throws HomotypicalGroupChangeException{
263
264 TaxonNameBase<?,?> acceptedName = acceptedTaxon.getName();
265 TaxonNameBase<?,?> synonymName = synonym.getName();
266 HomotypicalGroup synonymHomotypicGroup = synonymName.getHomotypicalGroup();
267
268 //check synonym is not homotypic
269 if (acceptedName.getHomotypicalGroup().equals(synonymHomotypicGroup)){
270 String message = "The accepted taxon and the synonym are part of the same homotypical group and therefore can not be both accepted.";
271 throw new HomotypicalGroupChangeException(message);
272 }
273
274 Taxon newAcceptedTaxon = Taxon.NewInstance(synonymName, acceptedTaxon.getSec());
275
276 SynonymRelationshipType relTypeForGroup = SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF();
277 List<Synonym> heteroSynonyms = acceptedTaxon.getSynonymsInGroup(synonymHomotypicGroup);
278
279 for (Synonym heteroSynonym : heteroSynonyms){
280 if (synonym.equals(heteroSynonym)){
281 acceptedTaxon.removeSynonym(heteroSynonym, false);
282 }else{
283 //move synonyms in same homotypic group to new accepted taxon
284 heteroSynonym.replaceAcceptedTaxon(newAcceptedTaxon, relTypeForGroup, copyCitationInfo, citation, microCitation);
285 }
286 }
287
288 //synonym.getName().removeTaxonBase(synonym);
289 //TODO correct delete handling still needs to be implemented / checked
290 if (deleteSynonym){
291 // deleteSynonym(synonym, taxon, false);
292 try {
293 this.dao.flush();
294 this.delete(synonym);
295
296 } catch (Exception e) {
297 logger.info("Can't delete old synonym from database");
298 }
299 }
300
301 return newAcceptedTaxon;
302 }
303
304
305 @Override
306 public Taxon changeSynonymToRelatedTaxon(Synonym synonym, Taxon toTaxon, TaxonRelationshipType taxonRelationshipType, Reference citation, String microcitation){
307
308 // Get name from synonym
309 TaxonNameBase<?, ?> synonymName = synonym.getName();
310
311 // remove synonym from taxon
312 toTaxon.removeSynonym(synonym);
313
314 // Create a taxon with synonym name
315 Taxon fromTaxon = Taxon.NewInstance(synonymName, null);
316
317 // Add taxon relation
318 fromTaxon.addTaxonRelation(toTaxon, taxonRelationshipType, citation, microcitation);
319
320 // since we are swapping names, we have to detach the name from the synonym completely.
321 // Otherwise the synonym will still be in the list of typified names.
322 synonym.getName().removeTaxonBase(synonym);
323
324 return fromTaxon;
325 }
326
327
328 /* (non-Javadoc)
329 * @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)
330 */
331 @Transactional(readOnly = false)
332 @Override
333 public void changeHomotypicalGroupOfSynonym(Synonym synonym, HomotypicalGroup newHomotypicalGroup, Taxon targetTaxon,
334 boolean removeFromOtherTaxa, boolean setBasionymRelationIfApplicable){
335 // Get synonym name
336 TaxonNameBase synonymName = synonym.getName();
337 HomotypicalGroup oldHomotypicalGroup = synonymName.getHomotypicalGroup();
338
339
340 // Switch groups
341 oldHomotypicalGroup.removeTypifiedName(synonymName);
342 newHomotypicalGroup.addTypifiedName(synonymName);
343
344 //remove existing basionym relationships
345 synonymName.removeBasionyms();
346
347 //add basionym relationship
348 if (setBasionymRelationIfApplicable){
349 Set<TaxonNameBase> basionyms = newHomotypicalGroup.getBasionyms();
350 for (TaxonNameBase basionym : basionyms){
351 synonymName.addBasionym(basionym);
352 }
353 }
354
355 //set synonym relationship correctly
356 // SynonymRelationship relToTaxon = null;
357 boolean relToTargetTaxonExists = false;
358 Set<SynonymRelationship> existingRelations = synonym.getSynonymRelations();
359 for (SynonymRelationship rel : existingRelations){
360 Taxon acceptedTaxon = rel.getAcceptedTaxon();
361 boolean isTargetTaxon = acceptedTaxon != null && acceptedTaxon.equals(targetTaxon);
362 HomotypicalGroup acceptedGroup = acceptedTaxon.getHomotypicGroup();
363 boolean isHomotypicToTaxon = acceptedGroup.equals(newHomotypicalGroup);
364 SynonymRelationshipType newRelationType = isHomotypicToTaxon? SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF() : SynonymRelationshipType.HETEROTYPIC_SYNONYM_OF();
365 rel.setType(newRelationType);
366 //TODO handle citation and microCitation
367
368 if (isTargetTaxon){
369 relToTargetTaxonExists = true;
370 }else{
371 if (removeFromOtherTaxa){
372 acceptedTaxon.removeSynonym(synonym, false);
373 }else{
374 //do nothing
375 }
376 }
377 }
378 if (targetTaxon != null && ! relToTargetTaxonExists ){
379 Taxon acceptedTaxon = targetTaxon;
380 HomotypicalGroup acceptedGroup = acceptedTaxon.getHomotypicGroup();
381 boolean isHomotypicToTaxon = acceptedGroup.equals(newHomotypicalGroup);
382 SynonymRelationshipType relType = isHomotypicToTaxon? SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF() : SynonymRelationshipType.HETEROTYPIC_SYNONYM_OF();
383 //TODO handle citation and microCitation
384 Reference citation = null;
385 String microCitation = null;
386 acceptedTaxon.addSynonym(synonym, relType, citation, microCitation);
387 }
388
389 }
390
391
392 /* (non-Javadoc)
393 * @see eu.etaxonomy.cdm.api.service.IIdentifiableEntityService#updateTitleCache(java.lang.Integer, eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy)
394 */
395 @Override
396 @Transactional(readOnly = false)
397 public void updateTitleCache(Class<? extends TaxonBase> clazz, Integer stepSize, IIdentifiableEntityCacheStrategy<TaxonBase> cacheStrategy, IProgressMonitor monitor) {
398 if (clazz == null){
399 clazz = TaxonBase.class;
400 }
401 super.updateTitleCacheImpl(clazz, stepSize, cacheStrategy, monitor);
402 }
403
404 @Override
405 @Autowired
406 protected void setDao(ITaxonDao dao) {
407 this.dao = dao;
408 }
409
410 /* (non-Javadoc)
411 * @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)
412 */
413 @Override
414 public Pager<TaxonBase> findTaxaByName(Class<? extends TaxonBase> clazz, String uninomial, String infragenericEpithet, String specificEpithet, String infraspecificEpithet, Rank rank, Integer pageSize,Integer pageNumber) {
415 Integer numberOfResults = dao.countTaxaByName(clazz, uninomial, infragenericEpithet, specificEpithet, infraspecificEpithet, rank);
416
417 List<TaxonBase> results = new ArrayList<TaxonBase>();
418 if(numberOfResults > 0) { // no point checking again
419 results = dao.findTaxaByName(clazz, uninomial, infragenericEpithet, specificEpithet, infraspecificEpithet, rank, pageSize, pageNumber);
420 }
421
422 return new DefaultPagerImpl<TaxonBase>(pageNumber, numberOfResults, pageSize, results);
423 }
424
425 /* (non-Javadoc)
426 * @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)
427 */
428 @Override
429 public List<TaxonBase> listTaxaByName(Class<? extends TaxonBase> clazz, String uninomial, String infragenericEpithet, String specificEpithet, String infraspecificEpithet, Rank rank, Integer pageSize,Integer pageNumber) {
430 Integer numberOfResults = dao.countTaxaByName(clazz, uninomial, infragenericEpithet, specificEpithet, infraspecificEpithet, rank);
431
432 List<TaxonBase> results = new ArrayList<TaxonBase>();
433 if(numberOfResults > 0) { // no point checking again
434 results = dao.findTaxaByName(clazz, uninomial, infragenericEpithet, specificEpithet, infraspecificEpithet, rank, pageSize, pageNumber);
435 }
436
437 return results;
438 }
439
440 /* (non-Javadoc)
441 * @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)
442 */
443 @Override
444 public List<TaxonRelationship> listToTaxonRelationships(Taxon taxon, TaxonRelationshipType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths){
445 Integer numberOfResults = dao.countTaxonRelationships(taxon, type, TaxonRelationship.Direction.relatedTo);
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.relatedTo);
450 }
451 return results;
452 }
453
454 /* (non-Javadoc)
455 * @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)
456 */
457 @Override
458 public Pager<TaxonRelationship> pageToTaxonRelationships(Taxon taxon, TaxonRelationshipType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
459 Integer numberOfResults = dao.countTaxonRelationships(taxon, type, TaxonRelationship.Direction.relatedTo);
460
461 List<TaxonRelationship> results = new ArrayList<TaxonRelationship>();
462 if(numberOfResults > 0) { // no point checking again
463 results = dao.getTaxonRelationships(taxon, type, pageSize, pageNumber, orderHints, propertyPaths, TaxonRelationship.Direction.relatedTo);
464 }
465 return new DefaultPagerImpl<TaxonRelationship>(pageNumber, numberOfResults, pageSize, results);
466 }
467
468 /* (non-Javadoc)
469 * @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)
470 */
471 @Override
472 public List<TaxonRelationship> listFromTaxonRelationships(Taxon taxon, TaxonRelationshipType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths){
473 Integer numberOfResults = dao.countTaxonRelationships(taxon, type, TaxonRelationship.Direction.relatedFrom);
474
475 List<TaxonRelationship> results = new ArrayList<TaxonRelationship>();
476 if(numberOfResults > 0) { // no point checking again
477 results = dao.getTaxonRelationships(taxon, type, pageSize, pageNumber, orderHints, propertyPaths, TaxonRelationship.Direction.relatedFrom);
478 }
479 return results;
480 }
481
482 /* (non-Javadoc)
483 * @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)
484 */
485 @Override
486 public Pager<TaxonRelationship> pageFromTaxonRelationships(Taxon taxon, TaxonRelationshipType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
487 Integer numberOfResults = dao.countTaxonRelationships(taxon, type, TaxonRelationship.Direction.relatedFrom);
488
489 List<TaxonRelationship> results = new ArrayList<TaxonRelationship>();
490 if(numberOfResults > 0) { // no point checking again
491 results = dao.getTaxonRelationships(taxon, type, pageSize, pageNumber, orderHints, propertyPaths, TaxonRelationship.Direction.relatedFrom);
492 }
493 return new DefaultPagerImpl<TaxonRelationship>(pageNumber, numberOfResults, pageSize, results);
494 }
495
496 /**
497 * @param taxon
498 * @param includeRelationships
499 * @param maxDepth
500 * @param limit
501 * @param starts
502 * @param propertyPaths
503 * @return an List which is not specifically ordered
504 */
505 @Override
506 public Set<Taxon> listRelatedTaxa(Taxon taxon, Set<TaxonRelationshipEdge> includeRelationships, Integer maxDepth,
507 Integer limit, Integer start, List<String> propertyPaths) {
508
509 Set<Taxon> relatedTaxa = collectRelatedTaxa(taxon, includeRelationships, new HashSet<Taxon>(), maxDepth);
510 relatedTaxa.remove(taxon);
511 beanInitializer.initializeAll(relatedTaxa, propertyPaths);
512 return relatedTaxa;
513 }
514
515
516 /**
517 * recursively collect related taxa for the given <code>taxon</code> . The returned list will also include the
518 * <code>taxon</code> supplied as parameter.
519 *
520 * @param taxon
521 * @param includeRelationships
522 * @param taxa
523 * @param maxDepth can be <code>null</code> for infinite depth
524 * @return
525 */
526 private Set<Taxon> collectRelatedTaxa(Taxon taxon, Set<TaxonRelationshipEdge> includeRelationships, Set<Taxon> taxa, Integer maxDepth) {
527
528 if(taxa.isEmpty()) {
529 taxa.add(taxon);
530 }
531
532 if(maxDepth != null) {
533 maxDepth--;
534 }
535 if(logger.isDebugEnabled()){
536 logger.debug("collecting related taxa for " + taxon + " with maxDepth=" + maxDepth);
537 }
538 List<TaxonRelationship> taxonRelationships = dao.getTaxonRelationships(taxon, null, null, null, null, null, null);
539 for (TaxonRelationship taxRel : taxonRelationships) {
540
541 // skip invalid data
542 if (taxRel.getToTaxon() == null || taxRel.getFromTaxon() == null || taxRel.getType() == null) {
543 continue;
544 }
545 // filter by includeRelationships
546 for (TaxonRelationshipEdge relationshipEdgeFilter : includeRelationships) {
547 if ( relationshipEdgeFilter.getTaxonRelationshipType().equals(taxRel.getType()) ) {
548 if (relationshipEdgeFilter.getDirections().contains(Direction.relatedTo) && !taxa.contains(taxRel.getToTaxon())) {
549 if(logger.isDebugEnabled()){
550 logger.debug(maxDepth + ": " + taxon.getTitleCache() + " --[" + taxRel.getType().getLabel() + "]--> " + taxRel.getToTaxon().getTitleCache());
551 }
552 taxa.add(taxRel.getToTaxon());
553 if(maxDepth == null || maxDepth > 0) {
554 taxa.addAll(collectRelatedTaxa(taxRel.getToTaxon(), includeRelationships, taxa, maxDepth));
555 }
556 }
557 if(relationshipEdgeFilter.getDirections().contains(Direction.relatedFrom) && !taxa.contains(taxRel.getFromTaxon())) {
558 taxa.add(taxRel.getFromTaxon());
559 if(logger.isDebugEnabled()){
560 logger.debug(maxDepth + ": " +taxRel.getFromTaxon().getTitleCache() + " --[" + taxRel.getType().getLabel() + "]--> " + taxon.getTitleCache() );
561 }
562 if(maxDepth == null || maxDepth > 0) {
563 taxa.addAll(collectRelatedTaxa(taxRel.getFromTaxon(), includeRelationships, taxa, maxDepth));
564 }
565 }
566 }
567 }
568 }
569 return taxa;
570 }
571
572 /* (non-Javadoc)
573 * @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)
574 */
575 @Override
576 public Pager<SynonymRelationship> getSynonyms(Taxon taxon, SynonymRelationshipType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
577 Integer numberOfResults = dao.countSynonyms(taxon, type);
578
579 List<SynonymRelationship> results = new ArrayList<SynonymRelationship>();
580 if(numberOfResults > 0) { // no point checking again
581 results = dao.getSynonyms(taxon, type, pageSize, pageNumber, orderHints, propertyPaths);
582 }
583
584 return new DefaultPagerImpl<SynonymRelationship>(pageNumber, numberOfResults, pageSize, results);
585 }
586
587 /* (non-Javadoc)
588 * @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)
589 */
590 @Override
591 public Pager<SynonymRelationship> getSynonyms(Synonym synonym, SynonymRelationshipType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
592 Integer numberOfResults = dao.countSynonyms(synonym, type);
593
594 List<SynonymRelationship> results = new ArrayList<SynonymRelationship>();
595 if(numberOfResults > 0) { // no point checking again
596 results = dao.getSynonyms(synonym, type, pageSize, pageNumber, orderHints, propertyPaths);
597 }
598
599 return new DefaultPagerImpl<SynonymRelationship>(pageNumber, numberOfResults, pageSize, results);
600 }
601
602 /* (non-Javadoc)
603 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getHomotypicSynonymsByHomotypicGroup(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.List)
604 */
605 @Override
606 public List<Synonym> getHomotypicSynonymsByHomotypicGroup(Taxon taxon, List<String> propertyPaths){
607 Taxon t = (Taxon)dao.load(taxon.getUuid(), propertyPaths);
608 return t.getHomotypicSynonymsByHomotypicGroup();
609 }
610
611 /* (non-Javadoc)
612 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getHeterotypicSynonymyGroups(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.List)
613 */
614 @Override
615 public List<List<Synonym>> getHeterotypicSynonymyGroups(Taxon taxon, List<String> propertyPaths){
616 Taxon t = (Taxon)dao.load(taxon.getUuid(), propertyPaths);
617 List<HomotypicalGroup> homotypicalGroups = t.getHeterotypicSynonymyGroups();
618 List<List<Synonym>> heterotypicSynonymyGroups = new ArrayList<List<Synonym>>(homotypicalGroups.size());
619 for(HomotypicalGroup homotypicalGroup : homotypicalGroups){
620 heterotypicSynonymyGroups.add(t.getSynonymsInGroup(homotypicalGroup));
621 }
622 return heterotypicSynonymyGroups;
623 }
624
625 @Override
626 public List<UuidAndTitleCache<TaxonBase>> findTaxaAndNamesForEditor(IFindTaxaAndNamesConfigurator configurator){
627
628 List<UuidAndTitleCache<TaxonBase>> result = new ArrayList<UuidAndTitleCache<TaxonBase>>();
629 // Class<? extends TaxonBase> clazz = null;
630 // if ((configurator.isDoTaxa() && configurator.isDoSynonyms())) {
631 // clazz = TaxonBase.class;
632 // //propertyPath.addAll(configurator.getTaxonPropertyPath());
633 // //propertyPath.addAll(configurator.getSynonymPropertyPath());
634 // } else if(configurator.isDoTaxa()) {
635 // clazz = Taxon.class;
636 // //propertyPath = configurator.getTaxonPropertyPath();
637 // } else if (configurator.isDoSynonyms()) {
638 // clazz = Synonym.class;
639 // //propertyPath = configurator.getSynonymPropertyPath();
640 // }
641
642
643 result = dao.getTaxaByNameForEditor(configurator.isDoTaxa(), configurator.isDoSynonyms(), configurator.getTitleSearchStringSqlized(), configurator.getClassification(), configurator.getMatchMode(), configurator.getNamedAreas());
644 return result;
645 }
646
647 /* (non-Javadoc)
648 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxaAndNames(eu.etaxonomy.cdm.api.service.config.ITaxonServiceConfigurator)
649 */
650 @Override
651 public Pager<IdentifiableEntity> findTaxaAndNames(IFindTaxaAndNamesConfigurator configurator) {
652
653 List<IdentifiableEntity> results = new ArrayList<IdentifiableEntity>();
654 int numberOfResults = 0; // overall number of results (as opposed to number of results per page)
655 List<TaxonBase> taxa = null;
656
657 // Taxa and synonyms
658 long numberTaxaResults = 0L;
659
660
661 List<String> propertyPath = new ArrayList<String>();
662 if(configurator.getTaxonPropertyPath() != null){
663 propertyPath.addAll(configurator.getTaxonPropertyPath());
664 }
665
666
667 if (configurator.isDoMisappliedNames() || configurator.isDoSynonyms() || configurator.isDoTaxa()){
668 if(configurator.getPageSize() != null){ // no point counting if we need all anyway
669 numberTaxaResults =
670 dao.countTaxaByName(configurator.isDoTaxa(),configurator.isDoSynonyms(), configurator.isDoMisappliedNames(),
671 configurator.getTitleSearchStringSqlized(), configurator.getClassification(), configurator.getMatchMode(),
672 configurator.getNamedAreas());
673 }
674
675 if(configurator.getPageSize() == null || numberTaxaResults > configurator.getPageSize() * configurator.getPageNumber()){ // no point checking again if less results
676 taxa = dao.getTaxaByName(configurator.isDoTaxa(), configurator.isDoSynonyms(),
677 configurator.isDoMisappliedNames(), configurator.getTitleSearchStringSqlized(), configurator.getClassification(),
678 configurator.getMatchMode(), configurator.getNamedAreas(),
679 configurator.getPageSize(), configurator.getPageNumber(), propertyPath);
680 }
681 }
682
683 if (logger.isDebugEnabled()) { logger.debug(numberTaxaResults + " matching taxa counted"); }
684
685 if(taxa != null){
686 results.addAll(taxa);
687 }
688
689 numberOfResults += numberTaxaResults;
690
691 // Names without taxa
692 if (configurator.isDoNamesWithoutTaxa()) {
693 int numberNameResults = 0;
694
695 List<? extends TaxonNameBase<?,?>> names =
696 nameDao.findByName(configurator.getTitleSearchStringSqlized(), configurator.getMatchMode(),
697 configurator.getPageSize(), configurator.getPageNumber(), null, configurator.getTaxonNamePropertyPath());
698 if (logger.isDebugEnabled()) { logger.debug(names.size() + " matching name(s) found"); }
699 if (names.size() > 0) {
700 for (TaxonNameBase<?,?> taxonName : names) {
701 if (taxonName.getTaxonBases().size() == 0) {
702 results.add(taxonName);
703 numberNameResults++;
704 }
705 }
706 if (logger.isDebugEnabled()) { logger.debug(numberNameResults + " matching name(s) without taxa found"); }
707 numberOfResults += numberNameResults;
708 }
709 }
710
711 // Taxa from common names
712
713 if (configurator.isDoTaxaByCommonNames()) {
714 taxa = new ArrayList<TaxonBase>();
715 numberTaxaResults = 0;
716 if(configurator.getPageSize() != null){// no point counting if we need all anyway
717 numberTaxaResults = dao.countTaxaByCommonName(configurator.getTitleSearchStringSqlized(), configurator.getClassification(), configurator.getMatchMode(), configurator.getNamedAreas());
718 }
719 if(configurator.getPageSize() == null || numberTaxaResults > configurator.getPageSize() * configurator.getPageNumber()){
720 List<Object[]> commonNameResults = dao.getTaxaByCommonName(configurator.getTitleSearchStringSqlized(), configurator.getClassification(), configurator.getMatchMode(), configurator.getNamedAreas(), configurator.getPageSize(), configurator.getPageNumber(), configurator.getTaxonPropertyPath());
721 for( Object[] entry : commonNameResults ) {
722 taxa.add((TaxonBase) entry[0]);
723 }
724 }
725 if(taxa != null){
726 results.addAll(taxa);
727 }
728 numberOfResults += numberTaxaResults;
729
730 }
731
732 return new DefaultPagerImpl<IdentifiableEntity>
733 (configurator.getPageNumber(), numberOfResults, configurator.getPageSize(), results);
734 }
735
736 public List<UuidAndTitleCache<TaxonBase>> getTaxonUuidAndTitleCache(){
737 return dao.getUuidAndTitleCache();
738 }
739
740 /* (non-Javadoc)
741 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllMedia(eu.etaxonomy.cdm.model.taxon.Taxon, int, int, int, java.lang.String[])
742 */
743 @Override
744 public List<MediaRepresentation> getAllMedia(Taxon taxon, int size, int height, int widthOrDuration, String[] mimeTypes){
745 List<MediaRepresentation> medRep = new ArrayList<MediaRepresentation>();
746 taxon = (Taxon)dao.load(taxon.getUuid());
747 Set<TaxonDescription> descriptions = taxon.getDescriptions();
748 for (TaxonDescription taxDesc: descriptions){
749 Set<DescriptionElementBase> elements = taxDesc.getElements();
750 for (DescriptionElementBase descElem: elements){
751 for(Media media : descElem.getMedia()){
752
753 //find the best matching representation
754 medRep.add(MediaUtils.findBestMatchingRepresentation(media, null, size, height, widthOrDuration, mimeTypes));
755
756 }
757 }
758 }
759 return medRep;
760 }
761
762 /* (non-Javadoc)
763 * @see eu.etaxonomy.cdm.api.service.ITaxonService#listTaxonDescriptionMedia(eu.etaxonomy.cdm.model.taxon.Taxon, boolean)
764 */
765 @Override
766 public List<Media> listTaxonDescriptionMedia(Taxon taxon, Set<TaxonRelationshipEdge> includeRelationships, boolean limitToGalleries, List<String> propertyPath){
767 return listMedia(taxon, includeRelationships, limitToGalleries, true, false, false, propertyPath);
768 }
769
770
771 /* (non-Javadoc)
772 * @see eu.etaxonomy.cdm.api.service.ITaxonService#listMedia(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.Set, boolean, java.util.List)
773 */
774 @Override
775 public List<Media> listMedia(Taxon taxon, Set<TaxonRelationshipEdge> includeRelationships,
776 Boolean limitToGalleries, Boolean includeTaxonDescriptions, Boolean includeOccurrences,
777 Boolean includeTaxonNameDescriptions, List<String> propertyPath) {
778
779 Set<Taxon> taxa = new HashSet<Taxon>();
780 List<Media> taxonMedia = new ArrayList<Media>();
781
782 if (limitToGalleries == null) {
783 limitToGalleries = false;
784 }
785
786 // --- resolve related taxa
787 if (includeRelationships != null) {
788 taxa = listRelatedTaxa(taxon, includeRelationships, null, null, null, null);
789 }
790
791 taxa.add((Taxon) dao.load(taxon.getUuid()));
792
793 if(includeTaxonDescriptions != null && includeTaxonDescriptions){
794 List<TaxonDescription> taxonDescriptions = new ArrayList<TaxonDescription>();
795 // --- TaxonDescriptions
796 for (Taxon t : taxa) {
797 taxonDescriptions.addAll(descriptionService.listTaxonDescriptions(t, null, null, null, null, propertyPath));
798 }
799 for (TaxonDescription taxonDescription : taxonDescriptions) {
800 if (!limitToGalleries || taxonDescription.isImageGallery()) {
801 for (DescriptionElementBase element : taxonDescription.getElements()) {
802 for (Media media : element.getMedia()) {
803 taxonMedia.add(media);
804 }
805 }
806 }
807 }
808 }
809
810 if(includeOccurrences != null && includeOccurrences) {
811 Set<SpecimenOrObservationBase> specimensOrObservations = new HashSet<SpecimenOrObservationBase>();
812 // --- Specimens
813 for (Taxon t : taxa) {
814 specimensOrObservations.addAll(occurrenceDao.listByAssociatedTaxon(null, t, null, null, null, null));
815 }
816 for (SpecimenOrObservationBase occurrence : specimensOrObservations) {
817
818 // direct media removed from specimen #3597
819 // taxonMedia.addAll(occurrence.getMedia());
820
821 // SpecimenDescriptions
822 Set<SpecimenDescription> specimenDescriptions = occurrence.getSpecimenDescriptions();
823 for (DescriptionBase specimenDescription : specimenDescriptions) {
824 if (!limitToGalleries || specimenDescription.isImageGallery()) {
825 Set<DescriptionElementBase> elements = specimenDescription.getElements();
826 for (DescriptionElementBase element : elements) {
827 for (Media media : element.getMedia()) {
828 taxonMedia.add(media);
829 }
830 }
831 }
832 }
833
834 // Collection
835 //TODO why may collections have media attached? #
836 if (occurrence.isInstanceOf(DerivedUnit.class)) {
837 DerivedUnit derivedUnit = CdmBase.deproxy(occurrence, DerivedUnit.class);
838 if (derivedUnit.getCollection() != null){
839 taxonMedia.addAll(derivedUnit.getCollection().getMedia());
840 }
841 }
842
843 // pherograms & gelPhotos
844 if (occurrence.isInstanceOf(DnaSample.class)) {
845 DnaSample dnaSample = CdmBase.deproxy(occurrence, DnaSample.class);
846 Set<Sequence> sequences = dnaSample.getSequences();
847 //we do show only those gelPhotos which lead to a consensus sequence
848 for (Sequence sequence : sequences) {
849 Set<Media> dnaRelatedMedia = new HashSet<Media>();
850 for (SingleRead singleRead : sequence.getSingleReads()){
851 Amplification amplification = singleRead.getAmplification();
852 dnaRelatedMedia.add(amplification.getGelPhoto());
853 dnaRelatedMedia.add(singleRead.getPherogram());
854 dnaRelatedMedia.remove(null);
855 }
856 taxonMedia.addAll(dnaRelatedMedia);
857 }
858 }
859
860 }
861 }
862
863 if(includeTaxonNameDescriptions != null && includeTaxonNameDescriptions) {
864 // --- TaxonNameDescription
865 Set<TaxonNameDescription> nameDescriptions = new HashSet<TaxonNameDescription>();
866 for (Taxon t : taxa) {
867 nameDescriptions .addAll(t.getName().getDescriptions());
868 }
869 for(TaxonNameDescription nameDescription: nameDescriptions){
870 if (!limitToGalleries || nameDescription.isImageGallery()) {
871 Set<DescriptionElementBase> elements = nameDescription.getElements();
872 for (DescriptionElementBase element : elements) {
873 for (Media media : element.getMedia()) {
874 taxonMedia.add(media);
875 }
876 }
877 }
878 }
879 }
880
881 beanInitializer.initializeAll(taxonMedia, propertyPath);
882 return taxonMedia;
883 }
884
885 /* (non-Javadoc)
886 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxaByID(java.util.Set)
887 */
888 @Override
889 public List<TaxonBase> findTaxaByID(Set<Integer> listOfIDs) {
890 return this.dao.listByIds(listOfIDs, null, null, null, null);
891 }
892
893 /* (non-Javadoc)
894 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxonByUuid(UUID uuid, List<String> propertyPaths)
895 */
896 @Override
897 public TaxonBase findTaxonByUuid(UUID uuid, List<String> propertyPaths){
898 return this.dao.findByUuid(uuid, null ,propertyPaths);
899 }
900
901 /* (non-Javadoc)
902 * @see eu.etaxonomy.cdm.api.service.ITaxonService#countAllRelationships()
903 */
904 @Override
905 public int countAllRelationships() {
906 return this.dao.countAllRelationships();
907 }
908
909
910
911
912 /* (non-Javadoc)
913 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findIdenticalTaxonNames(java.util.List)
914 */
915 @Override
916 public List<TaxonNameBase> findIdenticalTaxonNames(List<String> propertyPath) {
917 return this.dao.findIdenticalTaxonNames(propertyPath);
918 }
919
920
921 /* (non-Javadoc)
922 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteTaxon(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.api.service.config.TaxonDeletionConfigurator)
923 */
924 @Override
925 public void deleteTaxon(Taxon taxon, TaxonDeletionConfigurator config) throws ReferencedObjectUndeletableException {
926 if (config == null){
927 config = new TaxonDeletionConfigurator();
928 }
929
930 // TaxonNode
931 if (! config.isDeleteTaxonNodes()){
932 if (taxon.getTaxonNodes().size() > 0){
933 String message = "Taxon can't be deleted as it is used in a classification node. Remove taxon from all classifications prior to deletion.";
934 throw new ReferencedObjectUndeletableException(message);
935 }
936 }
937
938
939 // SynonymRelationShip
940 if (config.isDeleteSynonymRelations()){
941 boolean removeSynonymNameFromHomotypicalGroup = false;
942 for (SynonymRelationship synRel : taxon.getSynonymRelations()){
943 Synonym synonym = synRel.getSynonym();
944 taxon.removeSynonymRelation(synRel, removeSynonymNameFromHomotypicalGroup);
945 if (config.isDeleteSynonymsIfPossible()){
946 //TODO which value
947 boolean newHomotypicGroupIfNeeded = true;
948 deleteSynonym(synonym, taxon, config.isDeleteNameIfPossible(), newHomotypicGroupIfNeeded);
949 }else{
950 deleteSynonymRelationships(synonym, taxon);
951 }
952 }
953 }
954
955 // TaxonRelationship
956 if (! config.isDeleteTaxonRelationships()){
957 if (taxon.getTaxonRelations().size() > 0){
958 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.";
959 throw new ReferencedObjectUndeletableException(message);
960 }
961 }
962
963
964 // TaxonDescription
965 Set<TaxonDescription> descriptions = taxon.getDescriptions();
966
967 for (TaxonDescription desc: descriptions){
968 if (config.isDeleteDescriptions()){
969 //TODO use description delete configurator ?
970 //FIXME check if description is ALWAYS deletable
971 descriptionService.delete(desc);
972 }else{
973 if (desc.getDescribedSpecimenOrObservation() != null){
974 String message = "Taxon can't be deleted as it is used in a TaxonDescription" +
975 " which also describes specimens or abservations";
976 throw new ReferencedObjectUndeletableException(message);
977 }
978 }
979 }
980
981
982 //check references with only reverse mapping
983 Set<CdmBase> referencingObjects = genericDao.getReferencingObjects(taxon);
984 for (CdmBase referencingObject : referencingObjects){
985 //IIdentificationKeys (Media, Polytomous, MultiAccess)
986 if (HibernateProxyHelper.isInstanceOf(referencingObject, IIdentificationKey.class)){
987 String message = "Taxon can't be deleted as it is used in an identification key. Remove from identification key prior to deleting this name";
988 message = String.format(message, CdmBase.deproxy(referencingObject, DerivedUnit.class).getTitleCache());
989 throw new ReferencedObjectUndeletableException(message);
990 }
991
992
993 //PolytomousKeyNode
994 if (referencingObject.isInstanceOf(PolytomousKeyNode.class)){
995 String message = "Taxon can't be deleted as it is used in polytomous key node";
996 throw new ReferencedObjectUndeletableException(message);
997 }
998
999 //TaxonInteraction
1000 if (referencingObject.isInstanceOf(TaxonInteraction.class)){
1001 String message = "Taxon can't be deleted as it is used in taxonInteraction#taxon2";
1002 throw new ReferencedObjectUndeletableException(message);
1003 }
1004 }
1005
1006
1007 //TaxonNameBase
1008 if (config.isDeleteNameIfPossible()){
1009 try {
1010 nameService.delete(taxon.getName(), config.getNameDeletionConfig());
1011 } catch (ReferencedObjectUndeletableException e) {
1012 //do nothing
1013 if (logger.isDebugEnabled()){logger.debug("Name could not be deleted");}
1014 }
1015 }
1016
1017 }
1018
1019 /* (non-Javadoc)
1020 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonym(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon, boolean, boolean)
1021 */
1022 @Transactional(readOnly = false)
1023 @Override
1024 public void deleteSynonym(Synonym synonym, Taxon taxon, boolean removeNameIfPossible,boolean newHomotypicGroupIfNeeded) {
1025 if (synonym == null){
1026 return;
1027 }
1028 synonym = CdmBase.deproxy(dao.merge(synonym), Synonym.class);
1029
1030 //remove synonymRelationship
1031 Set<Taxon> taxonSet = new HashSet<Taxon>();
1032 if (taxon != null){
1033 taxonSet.add(taxon);
1034 }else{
1035 taxonSet.addAll(synonym.getAcceptedTaxa());
1036 }
1037 for (Taxon relatedTaxon : taxonSet){
1038 // dao.deleteSynonymRelationships(synonym, relatedTaxon);
1039 relatedTaxon.removeSynonym(synonym, newHomotypicGroupIfNeeded);
1040 }
1041 this.saveOrUpdate(synonym);
1042
1043 //TODO remove name from homotypical group?
1044
1045 //remove synonym (if necessary)
1046 if (synonym.getSynonymRelations().isEmpty()){
1047 TaxonNameBase<?,?> name = synonym.getName();
1048 synonym.setName(null);
1049 dao.delete(synonym);
1050
1051 //remove name if possible (and required)
1052 if (name != null && removeNameIfPossible){
1053 try{
1054 nameService.delete(name, new NameDeletionConfigurator());
1055 }catch (DataChangeNoRollbackException ex){
1056 if (logger.isDebugEnabled()) {
1057 logger.debug("Name wasn't deleted as it is referenced");
1058 }
1059 }
1060 }
1061 }
1062 }
1063
1064
1065 /* (non-Javadoc)
1066 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findIdenticalTaxonNameIds(java.util.List)
1067 */
1068 @Override
1069 public List<TaxonNameBase> findIdenticalTaxonNameIds(List<String> propertyPath) {
1070
1071 return this.dao.findIdenticalNamesNew(propertyPath);
1072 }
1073
1074 /* (non-Javadoc)
1075 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getPhylumName(eu.etaxonomy.cdm.model.name.TaxonNameBase)
1076 */
1077 @Override
1078 public String getPhylumName(TaxonNameBase name){
1079 return this.dao.getPhylumName(name);
1080 }
1081
1082 /* (non-Javadoc)
1083 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonymRelationships(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon)
1084 */
1085 @Override
1086 public long deleteSynonymRelationships(Synonym syn, Taxon taxon) {
1087 return dao.deleteSynonymRelationships(syn, taxon);
1088 }
1089
1090 /* (non-Javadoc)
1091 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonymRelationships(eu.etaxonomy.cdm.model.taxon.Synonym)
1092 */
1093 @Override
1094 public long deleteSynonymRelationships(Synonym syn) {
1095 return dao.deleteSynonymRelationships(syn, null);
1096 }
1097
1098
1099 /* (non-Javadoc)
1100 * @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)
1101 */
1102 @Override
1103 public List<SynonymRelationship> listSynonymRelationships(
1104 TaxonBase taxonBase, SynonymRelationshipType type, Integer pageSize, Integer pageNumber,
1105 List<OrderHint> orderHints, List<String> propertyPaths, Direction direction) {
1106 Integer numberOfResults = dao.countSynonymRelationships(taxonBase, type, direction);
1107
1108 List<SynonymRelationship> results = new ArrayList<SynonymRelationship>();
1109 if(numberOfResults > 0) { // no point checking again
1110 results = dao.getSynonymRelationships(taxonBase, type, pageSize, pageNumber, orderHints, propertyPaths, direction);
1111 }
1112 return results;
1113 }
1114
1115 /* (non-Javadoc)
1116 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findBestMatchingTaxon(java.lang.String)
1117 */
1118 @Override
1119 public Taxon findBestMatchingTaxon(String taxonName) {
1120 MatchingTaxonConfigurator config = MatchingTaxonConfigurator.NewInstance();
1121 config.setTaxonNameTitle(taxonName);
1122 return findBestMatchingTaxon(config);
1123 }
1124
1125
1126
1127 @Override
1128 public Taxon findBestMatchingTaxon(MatchingTaxonConfigurator config) {
1129
1130 Taxon bestCandidate = null;
1131 try{
1132 // 1. search for acceptet taxa
1133 List<TaxonBase> taxonList = dao.findByNameTitleCache(true, false, config.getTaxonNameTitle(), null, MatchMode.EXACT, null, 0, null, null);
1134 boolean bestCandidateMatchesSecUuid = false;
1135 boolean bestCandidateIsInClassification = false;
1136 int countEqualCandidates = 0;
1137 for(TaxonBase taxonBaseCandidate : taxonList){
1138 if(taxonBaseCandidate instanceof Taxon){
1139 Taxon newCanditate = CdmBase.deproxy(taxonBaseCandidate, Taxon.class);
1140 boolean newCandidateMatchesSecUuid = isMatchesSecUuid(newCanditate, config);
1141 if (! newCandidateMatchesSecUuid && config.isOnlyMatchingSecUuid() ){
1142 continue;
1143 }else if(newCandidateMatchesSecUuid && ! bestCandidateMatchesSecUuid){
1144 bestCandidate = newCanditate;
1145 countEqualCandidates = 1;
1146 bestCandidateMatchesSecUuid = true;
1147 continue;
1148 }
1149
1150 boolean newCandidateInClassification = isInClassification(newCanditate, config);
1151 if (! newCandidateInClassification && config.isOnlyMatchingClassificationUuid()){
1152 continue;
1153 }else if (newCandidateInClassification && ! bestCandidateIsInClassification){
1154 bestCandidate = newCanditate;
1155 countEqualCandidates = 1;
1156 bestCandidateIsInClassification = true;
1157 continue;
1158 }
1159 if (bestCandidate == null){
1160 bestCandidate = newCanditate;
1161 countEqualCandidates = 1;
1162 continue;
1163 }
1164
1165 }else{ //not Taxon.class
1166 continue;
1167 }
1168 countEqualCandidates++;
1169
1170 }
1171 if (bestCandidate != null){
1172 if(countEqualCandidates > 1){
1173 logger.info(countEqualCandidates + " equally matching TaxonBases found, using first accepted Taxon: " + bestCandidate.getTitleCache());
1174 return bestCandidate;
1175 } else {
1176 logger.info("using accepted Taxon: " + bestCandidate.getTitleCache());
1177 return bestCandidate;
1178 }
1179 }
1180
1181
1182 // 2. search for synonyms
1183 if (config.isIncludeSynonyms()){
1184 List<TaxonBase> synonymList = dao.findByNameTitleCache(false, true, config.getTaxonNameTitle(), null, MatchMode.EXACT, null, 0, null, null);
1185 for(TaxonBase taxonBase : synonymList){
1186 if(taxonBase instanceof Synonym){
1187 Synonym synonym = CdmBase.deproxy(taxonBase, Synonym.class);
1188 Set<Taxon> acceptetdCandidates = synonym.getAcceptedTaxa();
1189 if(!acceptetdCandidates.isEmpty()){
1190 bestCandidate = acceptetdCandidates.iterator().next();
1191 if(acceptetdCandidates.size() == 1){
1192 logger.info(acceptetdCandidates.size() + " Accepted taxa found for synonym " + taxonBase.getTitleCache() + ", using first one: " + bestCandidate.getTitleCache());
1193 return bestCandidate;
1194 } else {
1195 logger.info("using accepted Taxon " + bestCandidate.getTitleCache() + "for synonym " + taxonBase.getTitleCache());
1196 return bestCandidate;
1197 }
1198 //TODO extend method: search using treeUUID, using SecUUID, first find accepted then include synonyms until a matching taxon is found
1199 }
1200 }
1201 }
1202 }
1203
1204 } catch (Exception e){
1205 logger.error(e);
1206 e.printStackTrace();
1207 }
1208
1209 return bestCandidate;
1210 }
1211
1212 private boolean isInClassification(Taxon taxon, MatchingTaxonConfigurator config) {
1213 UUID configClassificationUuid = config.getClassificationUuid();
1214 if (configClassificationUuid == null){
1215 return false;
1216 }
1217 for (TaxonNode node : taxon.getTaxonNodes()){
1218 UUID classUuid = node.getClassification().getUuid();
1219 if (configClassificationUuid.equals(classUuid)){
1220 return true;
1221 }
1222 }
1223 return false;
1224 }
1225
1226 private boolean isMatchesSecUuid(Taxon taxon, MatchingTaxonConfigurator config) {
1227 UUID configSecUuid = config.getSecUuid();
1228 if (configSecUuid == null){
1229 return false;
1230 }
1231 UUID taxonSecUuid = (taxon.getSec() == null)? null : taxon.getSec().getUuid();
1232 return configSecUuid.equals(taxonSecUuid);
1233 }
1234
1235 /* (non-Javadoc)
1236 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findBestMatchingSynonym(java.lang.String)
1237 */
1238 @Override
1239 public Synonym findBestMatchingSynonym(String taxonName) {
1240 List<TaxonBase> synonymList = dao.findByNameTitleCache(false, true, taxonName, null, MatchMode.EXACT, null, 0, null, null);
1241 if(! synonymList.isEmpty()){
1242 Synonym result = CdmBase.deproxy(synonymList.iterator().next(), Synonym.class);
1243 if(synonymList.size() == 1){
1244 logger.info(synonymList.size() + " Synonym found " + result.getTitleCache() );
1245 return result;
1246 } else {
1247 logger.info("Several matching synonyms found. Using first: " + result.getTitleCache());
1248 return result;
1249 }
1250 }
1251 return null;
1252 }
1253
1254
1255 /* (non-Javadoc)
1256 * @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)
1257 */
1258 @Override
1259 public SynonymRelationship moveSynonymToAnotherTaxon(SynonymRelationship oldSynonymRelation, Taxon newTaxon, boolean moveHomotypicGroup,
1260 SynonymRelationshipType newSynonymRelationshipType, Reference reference, String referenceDetail, boolean keepReference) throws HomotypicalGroupChangeException {
1261
1262 Synonym synonym = oldSynonymRelation.getSynonym();
1263 Taxon fromTaxon = oldSynonymRelation.getAcceptedTaxon();
1264 //TODO what if there is no name ?? Concepts may be cached (e.g. via TCS import)
1265 TaxonNameBase<?,?> synonymName = synonym.getName();
1266 TaxonNameBase<?,?> fromTaxonName = fromTaxon.getName();
1267 //set default relationship type
1268 if (newSynonymRelationshipType == null){
1269 newSynonymRelationshipType = SynonymRelationshipType.HETEROTYPIC_SYNONYM_OF();
1270 }
1271 boolean newRelTypeIsHomotypic = newSynonymRelationshipType.equals(SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF());
1272
1273 HomotypicalGroup homotypicGroup = synonymName.getHomotypicalGroup();
1274 int hgSize = homotypicGroup.getTypifiedNames().size();
1275 boolean isSingleInGroup = !(hgSize > 1);
1276
1277 if (! isSingleInGroup){
1278 boolean isHomotypicToAccepted = synonymName.isHomotypic(fromTaxonName);
1279 boolean hasHomotypicSynonymRelatives = isHomotypicToAccepted ? hgSize > 2 : hgSize > 1;
1280 if (isHomotypicToAccepted){
1281 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.";
1282 String homotypicRelatives = hasHomotypicSynonymRelatives ? " and other synonym(s)":"";
1283 message = String.format(message, homotypicRelatives);
1284 throw new HomotypicalGroupChangeException(message);
1285 }
1286 if (! moveHomotypicGroup){
1287 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.";
1288 throw new HomotypicalGroupChangeException(message);
1289 }
1290 }else{
1291 moveHomotypicGroup = true; //single synonym always allows to moveCompleteGroup
1292 }
1293 // Assert.assertTrue("Synonym can only be moved with complete homotypic group", moveHomotypicGroup);
1294
1295 SynonymRelationship result = null;
1296 //move all synonyms to new taxon
1297 List<Synonym> homotypicSynonyms = fromTaxon.getSynonymsInGroup(homotypicGroup);
1298 for (Synonym syn: homotypicSynonyms){
1299 Set<SynonymRelationship> synRelations = syn.getSynonymRelations();
1300 for (SynonymRelationship synRelation : synRelations){
1301 if (fromTaxon.equals(synRelation.getAcceptedTaxon())){
1302 Reference<?> newReference = reference;
1303 if (newReference == null && keepReference){
1304 newReference = synRelation.getCitation();
1305 }
1306 String newRefDetail = referenceDetail;
1307 if (newRefDetail == null && keepReference){
1308 newRefDetail = synRelation.getCitationMicroReference();
1309 }
1310 SynonymRelationship newSynRelation = newTaxon.addSynonym(syn, newSynonymRelationshipType, newReference, newRefDetail);
1311 fromTaxon.removeSynonymRelation(synRelation, false);
1312 //
1313 //change homotypic group of synonym if relType is 'homotypic'
1314 // if (newRelTypeIsHomotypic){
1315 // newTaxon.getName().getHomotypicalGroup().addTypifiedName(syn.getName());
1316 // }
1317 //set result
1318 if (synRelation.equals(oldSynonymRelation)){
1319 result = newSynRelation;
1320 }
1321 }
1322 }
1323
1324 }
1325 saveOrUpdate(newTaxon);
1326 //Assert that there is a result
1327 if (result == null){
1328 String message = "Old synonym relation could not be transformed into new relation. This should not happen.";
1329 throw new IllegalStateException(message);
1330 }
1331 return result;
1332 }
1333
1334 /* (non-Javadoc)
1335 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getUuidAndTitleCacheTaxon()
1336 */
1337 @Override
1338 public List<UuidAndTitleCache<TaxonBase>> getUuidAndTitleCacheTaxon() {
1339 return dao.getUuidAndTitleCacheTaxon();
1340 }
1341
1342 /* (non-Javadoc)
1343 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getUuidAndTitleCacheSynonym()
1344 */
1345 @Override
1346 public List<UuidAndTitleCache<TaxonBase>> getUuidAndTitleCacheSynonym() {
1347 return dao.getUuidAndTitleCacheSynonym();
1348 }
1349
1350 /* (non-Javadoc)
1351 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findByFullText(java.lang.Class, java.lang.String, eu.etaxonomy.cdm.model.taxon.Classification, java.util.List, boolean, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)
1352 */
1353 @Override
1354 public Pager<SearchResult<TaxonBase>> findByFullText(
1355 Class<? extends TaxonBase> clazz, String queryString,
1356 Classification classification, List<Language> languages,
1357 boolean highlightFragments, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) throws CorruptIndexException, IOException, ParseException {
1358
1359
1360 LuceneSearch luceneSearch = prepareFindByFullTextSearch(clazz, queryString, classification, languages, highlightFragments);
1361
1362 // --- execute search
1363 TopGroupsWithMaxScore topDocsResultSet = luceneSearch.executeSearch(pageSize, pageNumber);
1364
1365 Map<CdmBaseType, String> idFieldMap = new HashMap<CdmBaseType, String>();
1366 idFieldMap.put(CdmBaseType.TAXON, "id");
1367
1368 // --- initialize taxa, thighlight matches ....
1369 ISearchResultBuilder searchResultBuilder = new SearchResultBuilder(luceneSearch, luceneSearch.getQuery());
1370 List<SearchResult<TaxonBase>> searchResults = searchResultBuilder.createResultSet(
1371 topDocsResultSet, luceneSearch.getHighlightFields(), dao, idFieldMap, propertyPaths);
1372
1373 int totalHits = topDocsResultSet != null ? topDocsResultSet.topGroups.totalGroupedHitCount : 0;
1374 return new DefaultPagerImpl<SearchResult<TaxonBase>>(pageNumber, totalHits, pageSize, searchResults);
1375 }
1376
1377 /**
1378 * @param clazz
1379 * @param queryString
1380 * @param classification
1381 * @param languages
1382 * @param highlightFragments
1383 * @param directorySelectClass
1384 * @return
1385 */
1386 protected LuceneSearch prepareFindByFullTextSearch(Class<? extends CdmBase> clazz, String queryString, Classification classification, List<Language> languages,
1387 boolean highlightFragments) {
1388 BooleanQuery finalQuery = new BooleanQuery();
1389 BooleanQuery textQuery = new BooleanQuery();
1390
1391 LuceneSearch luceneSearch = new LuceneSearch(getSession(), TaxonBase.class);
1392 QueryFactory queryFactory = new QueryFactory(luceneSearch);
1393
1394 SortField[] sortFields = new SortField[]{SortField.FIELD_SCORE, new SortField("titleCache__sort", SortField.STRING, false)};
1395 luceneSearch.setSortFields(sortFields);
1396
1397 // ---- search criteria
1398 luceneSearch.setClazz(clazz);
1399
1400 textQuery.add(queryFactory.newTermQuery("titleCache", queryString), Occur.SHOULD);
1401 textQuery.add(queryFactory.newDefinedTermQuery("name.rank", queryString, languages), Occur.SHOULD);
1402
1403 finalQuery.add(textQuery, Occur.MUST);
1404
1405 if(classification != null){
1406 finalQuery.add(queryFactory.newEntityIdQuery("taxonNodes.classification.id", classification), Occur.MUST);
1407 }
1408 luceneSearch.setQuery(finalQuery);
1409
1410 if(highlightFragments){
1411 luceneSearch.setHighlightFields(queryFactory.getTextFieldNamesAsArray());
1412 }
1413 return luceneSearch;
1414 }
1415
1416
1417 /* (non-Javadoc)
1418 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findByDescriptionElementFullText(java.lang.Class, java.lang.String, eu.etaxonomy.cdm.model.taxon.Classification, java.util.List, java.util.List, boolean, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)
1419 */
1420 @Override
1421 public Pager<SearchResult<TaxonBase>> findByDescriptionElementFullText(
1422 Class<? extends DescriptionElementBase> clazz, String queryString,
1423 Classification classification, List<Feature> features, List<Language> languages,
1424 boolean highlightFragments, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) throws CorruptIndexException, IOException, ParseException {
1425
1426
1427 LuceneSearch luceneSearch = prepareByDescriptionElementFullTextSearch(clazz, queryString, classification, features, languages, highlightFragments);
1428
1429 // --- execute search
1430 TopGroupsWithMaxScore topDocsResultSet = luceneSearch.executeSearch(pageSize, pageNumber);
1431
1432 Map<CdmBaseType, String> idFieldMap = new HashMap<CdmBaseType, String>();
1433 idFieldMap.put(CdmBaseType.DESCRIPTION_ELEMENT, "inDescription.taxon.id");
1434
1435 // --- initialize taxa, highlight matches ....
1436 ISearchResultBuilder searchResultBuilder = new SearchResultBuilder(luceneSearch, luceneSearch.getQuery());
1437 @SuppressWarnings("rawtypes")
1438 List<SearchResult<TaxonBase>> searchResults = searchResultBuilder.createResultSet(
1439 topDocsResultSet, luceneSearch.getHighlightFields(), dao, idFieldMap, propertyPaths);
1440
1441 int totalHits = topDocsResultSet != null ? topDocsResultSet.topGroups.totalGroupCount : 0;
1442 return new DefaultPagerImpl<SearchResult<TaxonBase>>(pageNumber, totalHits, pageSize, searchResults);
1443
1444 }
1445
1446
1447 @Override
1448 public Pager<SearchResult<TaxonBase>> findByEverythingFullText(String queryString,
1449 Classification classification, List<Language> languages, boolean highlightFragments,
1450 Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) throws CorruptIndexException, IOException, ParseException {
1451
1452 LuceneSearch luceneSearchByDescriptionElement = prepareByDescriptionElementFullTextSearch(null, queryString, classification, null, languages, highlightFragments);
1453 LuceneSearch luceneSearchByTaxonBase = prepareFindByFullTextSearch(null, queryString, classification, languages, highlightFragments);
1454
1455 LuceneMultiSearch multiSearch = new LuceneMultiSearch(luceneSearchByDescriptionElement, luceneSearchByTaxonBase);
1456
1457 // --- execute search
1458 TopGroupsWithMaxScore topDocsResultSet = multiSearch.executeSearch(pageSize, pageNumber);
1459
1460 // --- initialize taxa, highlight matches ....
1461 ISearchResultBuilder searchResultBuilder = new SearchResultBuilder(multiSearch, multiSearch.getQuery());
1462
1463 Map<CdmBaseType, String> idFieldMap = new HashMap<CdmBaseType, String>();
1464 idFieldMap.put(CdmBaseType.TAXON, "id");
1465 idFieldMap.put(CdmBaseType.DESCRIPTION_ELEMENT, "inDescription.taxon.id");
1466
1467 List<SearchResult<TaxonBase>> searchResults = searchResultBuilder.createResultSet(
1468 topDocsResultSet, multiSearch.getHighlightFields(), dao, idFieldMap, propertyPaths);
1469
1470 int totalHits = topDocsResultSet != null ? topDocsResultSet.topGroups.totalGroupedHitCount : 0;
1471 return new DefaultPagerImpl<SearchResult<TaxonBase>>(pageNumber, totalHits, pageSize, searchResults);
1472
1473 }
1474
1475
1476 /**
1477 * @param clazz
1478 * @param queryString
1479 * @param classification
1480 * @param features
1481 * @param languages
1482 * @param highlightFragments
1483 * @param directorySelectClass
1484 * @return
1485 */
1486 protected LuceneSearch prepareByDescriptionElementFullTextSearch(Class<? extends CdmBase> clazz, String queryString, Classification classification, List<Feature> features,
1487 List<Language> languages, boolean highlightFragments) {
1488 BooleanQuery finalQuery = new BooleanQuery();
1489 BooleanQuery textQuery = new BooleanQuery();
1490
1491 LuceneSearch luceneSearch = new LuceneSearch(getSession(), GroupByTaxonClassBridge.GROUPBY_TAXON_FIELD, DescriptionElementBase.class);
1492 QueryFactory queryFactory = new QueryFactory(luceneSearch);
1493
1494 SortField[] sortFields = new SortField[]{SortField.FIELD_SCORE, new SortField("inDescription.taxon.titleCache__sort", SortField.STRING, false)};
1495 luceneSearch.setSortFields(sortFields);
1496
1497 // ---- search criteria
1498 luceneSearch.setClazz(clazz);
1499 textQuery.add(queryFactory.newTermQuery("titleCache", queryString), Occur.SHOULD);
1500
1501 // common name
1502 Query nameQuery;
1503 if(languages == null || languages.size() == 0){
1504 nameQuery = queryFactory.newTermQuery("name", queryString);
1505 } else {
1506 nameQuery = new BooleanQuery();
1507 BooleanQuery languageSubQuery = new BooleanQuery();
1508 for(Language lang : languages){
1509 languageSubQuery.add(queryFactory.newTermQuery("language.uuid", lang.getUuid().toString(), false), Occur.SHOULD);
1510 }
1511 ((BooleanQuery) nameQuery).add(queryFactory.newTermQuery("name", queryString), Occur.MUST);
1512 ((BooleanQuery) nameQuery).add(languageSubQuery, Occur.MUST);
1513 }
1514 textQuery.add(nameQuery, Occur.SHOULD);
1515
1516
1517 // text field from TextData
1518 textQuery.add(queryFactory.newMultilanguageTextQuery("text", queryString, languages), Occur.SHOULD);
1519
1520 // --- TermBase fields - by representation ----
1521 // state field from CategoricalData
1522 textQuery.add(queryFactory.newDefinedTermQuery("stateData.state", queryString, languages), Occur.SHOULD);
1523
1524 // state field from CategoricalData
1525 textQuery.add(queryFactory.newDefinedTermQuery("stateData.modifyingText", queryString, languages), Occur.SHOULD);
1526
1527 // area field from Distribution
1528 textQuery.add(queryFactory.newDefinedTermQuery("area", queryString, languages), Occur.SHOULD);
1529
1530 // status field from Distribution
1531 textQuery.add(queryFactory.newDefinedTermQuery("status", queryString, languages), Occur.SHOULD);
1532
1533 finalQuery.add(textQuery, Occur.MUST);
1534 // --- classification ----
1535
1536 if(classification != null){
1537 finalQuery.add(queryFactory.newEntityIdQuery("inDescription.taxon.taxonNodes.classification.id", classification), Occur.MUST);
1538 }
1539
1540 // --- IdentifieableEntity fields - by uuid
1541 if(features != null && features.size() > 0 ){
1542 finalQuery.add(queryFactory.newEntityUuidQuery("feature.uuid", features), Occur.MUST);
1543 }
1544
1545 // the description must be associated with a taxon
1546 finalQuery.add(queryFactory.newIsNotNullQuery("inDescription.taxon.id"), Occur.MUST);
1547
1548 logger.info("prepareByDescriptionElementFullTextSearch() query: " + finalQuery.toString());
1549 luceneSearch.setQuery(finalQuery);
1550
1551 if(highlightFragments){
1552 luceneSearch.setHighlightFields(queryFactory.getTextFieldNamesAsArray());
1553 }
1554 return luceneSearch;
1555 }
1556
1557 /**
1558 * DefinedTerm representations and MultilanguageString maps are stored in the Lucene index by the {@link DefinedTermBaseClassBridge}
1559 * and {@link MultilanguageTextFieldBridge } in a consistent way. One field per language and also in one additional field for all languages.
1560 * This method is a convenient means to retrieve a Lucene query string for such the fields.
1561 *
1562 * @param name name of the term field as in the Lucene index. Must be field created by {@link DefinedTermBaseClassBridge}
1563 * or {@link MultilanguageTextFieldBridge }
1564 * @param languages the languages to search for exclusively. Can be <code>null</code> to search in all languages
1565 * @param stringBuilder a StringBuilder to be reused, if <code>null</code> a new StringBuilder will be instantiated and is returned
1566 * @return the StringBuilder given a parameter or a new one if the stringBuilder parameter was null.
1567 *
1568 * TODO move to utiliy class !!!!!!!!
1569 */
1570 private StringBuilder appendLocalizedFieldQuery(String name, List<Language> languages, StringBuilder stringBuilder) {
1571
1572 if(stringBuilder == null){
1573 stringBuilder = new StringBuilder();
1574 }
1575 if(languages == null || languages.size() == 0){
1576 stringBuilder.append(name + ".ALL:(%1$s) ");
1577 } else {
1578 for(Language lang : languages){
1579 stringBuilder.append(name + "." + lang.getUuid().toString() + ":(%1$s) ");
1580 }
1581 }
1582 return stringBuilder;
1583 }
1584
1585 @Override
1586 public List<Synonym> createInferredSynonyms(Taxon taxon, Classification classification, SynonymRelationshipType type, boolean doWithMisappliedNames){
1587 List <Synonym> inferredSynonyms = new ArrayList<Synonym>();
1588 List<Synonym> inferredSynonymsToBeRemoved = new ArrayList<Synonym>();
1589
1590 HashMap <UUID, ZoologicalName> zooHashMap = new HashMap<UUID, ZoologicalName>();
1591
1592
1593 UUID nameUuid= taxon.getName().getUuid();
1594 ZoologicalName taxonName = getZoologicalName(nameUuid, zooHashMap);
1595 String epithetOfTaxon = null;
1596 String infragenericEpithetOfTaxon = null;
1597 String infraspecificEpithetOfTaxon = null;
1598 if (taxonName.isSpecies()){
1599 epithetOfTaxon= taxonName.getSpecificEpithet();
1600 } else if (taxonName.isInfraGeneric()){
1601 infragenericEpithetOfTaxon = taxonName.getInfraGenericEpithet();
1602 } else if (taxonName.isInfraSpecific()){
1603 infraspecificEpithetOfTaxon = taxonName.getInfraSpecificEpithet();
1604 }
1605 String genusOfTaxon = taxonName.getGenusOrUninomial();
1606 Set<TaxonNode> nodes = taxon.getTaxonNodes();
1607 List<String> taxonNames = new ArrayList<String>();
1608
1609 for (TaxonNode node: nodes){
1610 // HashMap<String, String> synonymsGenus = new HashMap<String, String>(); // Changed this to be able to store the idInSource to a genusName
1611 // List<String> synonymsEpithet = new ArrayList<String>();
1612
1613 if (node.getClassification().equals(classification)){
1614 if (!node.isTopmostNode()){
1615 TaxonNode parent = node.getParent();
1616 parent = (TaxonNode)HibernateProxyHelper.deproxy(parent);
1617 TaxonNameBase<?,?> parentName = parent.getTaxon().getName();
1618 ZoologicalName zooParentName = HibernateProxyHelper.deproxy(parentName, ZoologicalName.class);
1619 Taxon parentTaxon = (Taxon)HibernateProxyHelper.deproxy(parent.getTaxon());
1620 Rank rankOfTaxon = taxonName.getRank();
1621
1622
1623 //create inferred synonyms for species, subspecies
1624 if ((parentName.isGenus() || parentName.isSpecies() || parentName.getRank().equals(Rank.SUBGENUS())) ){
1625
1626 Synonym inferredEpithet = null;
1627 Synonym inferredGenus = null;
1628 Synonym potentialCombination = null;
1629
1630 List<String> propertyPaths = new ArrayList<String>();
1631 propertyPaths.add("synonym");
1632 propertyPaths.add("synonym.name");
1633 List<OrderHint> orderHints = new ArrayList<OrderHint>();
1634 orderHints.add(new OrderHint("relatedFrom.titleCache", SortOrder.ASCENDING));
1635
1636 List<SynonymRelationship> synonymRelationshipsOfParent = dao.getSynonyms(parentTaxon, SynonymRelationshipType.HETEROTYPIC_SYNONYM_OF(), null, null,orderHints,propertyPaths);
1637 List<SynonymRelationship> synonymRelationshipsOfTaxon= dao.getSynonyms(taxon, SynonymRelationshipType.HETEROTYPIC_SYNONYM_OF(), null, null,orderHints,propertyPaths);
1638
1639 List<TaxonRelationship> taxonRelListParent = null;
1640 List<TaxonRelationship> taxonRelListTaxon = null;
1641 if (doWithMisappliedNames){
1642 taxonRelListParent = dao.getTaxonRelationships(parentTaxon, TaxonRelationshipType.MISAPPLIED_NAME_FOR(), null, null, orderHints, propertyPaths, Direction.relatedTo);
1643 taxonRelListTaxon = dao.getTaxonRelationships(taxon, TaxonRelationshipType.MISAPPLIED_NAME_FOR(), null, null, orderHints, propertyPaths, Direction.relatedTo);
1644 }
1645
1646
1647 if (type.equals(SynonymRelationshipType.INFERRED_EPITHET_OF())){
1648
1649
1650 for (SynonymRelationship synonymRelationOfParent:synonymRelationshipsOfParent){
1651 Synonym syn = synonymRelationOfParent.getSynonym();
1652
1653 inferredEpithet = createInferredEpithets(taxon,
1654 zooHashMap, taxonName, epithetOfTaxon,
1655 infragenericEpithetOfTaxon,
1656 infraspecificEpithetOfTaxon,
1657 taxonNames, parentName,
1658 syn);
1659
1660
1661 inferredSynonyms.add(inferredEpithet);
1662 zooHashMap.put(inferredEpithet.getName().getUuid(), (ZoologicalName)inferredEpithet.getName());
1663 taxonNames.add(((ZoologicalName)inferredEpithet.getName()).getNameCache());
1664 }
1665
1666 if (doWithMisappliedNames){
1667
1668 for (TaxonRelationship taxonRelationship: taxonRelListParent){
1669 Taxon misappliedName = taxonRelationship.getFromTaxon();
1670
1671 inferredEpithet = createInferredEpithets(taxon,
1672 zooHashMap, taxonName, epithetOfTaxon,
1673 infragenericEpithetOfTaxon,
1674 infraspecificEpithetOfTaxon,
1675 taxonNames, parentName,
1676 misappliedName);
1677
1678 inferredSynonyms.add(inferredEpithet);
1679 zooHashMap.put(inferredEpithet.getName().getUuid(), (ZoologicalName)inferredEpithet.getName());
1680 taxonNames.add(((ZoologicalName)inferredEpithet.getName()).getNameCache());
1681 }
1682 }
1683
1684 if (!taxonNames.isEmpty()){
1685 List<String> synNotInCDM = dao.taxaByNameNotInDB(taxonNames);
1686 ZoologicalName name;
1687 if (!synNotInCDM.isEmpty()){
1688 inferredSynonymsToBeRemoved.clear();
1689
1690 for (Synonym syn :inferredSynonyms){
1691 name = getZoologicalName(syn.getName().getUuid(), zooHashMap);
1692 if (!synNotInCDM.contains(name.getNameCache())){
1693 inferredSynonymsToBeRemoved.add(syn);
1694 }
1695 }
1696
1697 // Remove identified Synonyms from inferredSynonyms
1698 for (Synonym synonym : inferredSynonymsToBeRemoved) {
1699 inferredSynonyms.remove(synonym);
1700 }
1701 }
1702 }
1703
1704 }else if (type.equals(SynonymRelationshipType.INFERRED_GENUS_OF())){
1705
1706
1707 for (SynonymRelationship synonymRelationOfTaxon:synonymRelationshipsOfTaxon){
1708 TaxonNameBase synName;
1709 ZoologicalName inferredSynName;
1710
1711 Synonym syn = synonymRelationOfTaxon.getSynonym();
1712 inferredGenus = createInferredGenus(taxon,
1713 zooHashMap, taxonName, epithetOfTaxon,
1714 genusOfTaxon, taxonNames, zooParentName, syn);
1715
1716 inferredSynonyms.add(inferredGenus);
1717 zooHashMap.put(inferredGenus.getName().getUuid(), (ZoologicalName)inferredGenus.getName());
1718 taxonNames.add(( (ZoologicalName)inferredGenus.getName()).getNameCache());
1719
1720
1721 }
1722
1723 if (doWithMisappliedNames){
1724
1725 for (TaxonRelationship taxonRelationship: taxonRelListTaxon){
1726 Taxon misappliedName = taxonRelationship.getFromTaxon();
1727 inferredGenus = createInferredGenus(taxon, zooHashMap, taxonName, infraspecificEpithetOfTaxon, genusOfTaxon, taxonNames, zooParentName, misappliedName);
1728
1729 inferredSynonyms.add(inferredGenus);
1730 zooHashMap.put(inferredGenus.getName().getUuid(), (ZoologicalName)inferredGenus.getName());
1731 taxonNames.add(( (ZoologicalName)inferredGenus.getName()).getNameCache());
1732 }
1733 }
1734
1735
1736 if (!taxonNames.isEmpty()){
1737 List<String> synNotInCDM = dao.taxaByNameNotInDB(taxonNames);
1738 ZoologicalName name;
1739 if (!synNotInCDM.isEmpty()){
1740 inferredSynonymsToBeRemoved.clear();
1741
1742 for (Synonym syn :inferredSynonyms){
1743 name = getZoologicalName(syn.getName().getUuid(), zooHashMap);
1744 if (!synNotInCDM.contains(name.getNameCache())){
1745 inferredSynonymsToBeRemoved.add(syn);
1746 }
1747 }
1748
1749 // Remove identified Synonyms from inferredSynonyms
1750 for (Synonym synonym : inferredSynonymsToBeRemoved) {
1751 inferredSynonyms.remove(synonym);
1752 }
1753 }
1754 }
1755
1756 }else if (type.equals(SynonymRelationshipType.POTENTIAL_COMBINATION_OF())){
1757
1758 Reference sourceReference = null; // TODO: Determination of sourceReference is redundant
1759 ZoologicalName inferredSynName;
1760 //for all synonyms of the parent...
1761 for (SynonymRelationship synonymRelationOfParent:synonymRelationshipsOfParent){
1762 TaxonNameBase synName;
1763 Synonym synParent = synonymRelationOfParent.getSynonym();
1764 synName = synParent.getName();
1765
1766 HibernateProxyHelper.deproxy(synParent);
1767
1768 // Set the sourceReference
1769 sourceReference = synParent.getSec();
1770
1771 // Determine the idInSource
1772 String idInSourceParent = getIdInSource(synParent);
1773
1774 ZoologicalName parentSynZooName = getZoologicalName(synName.getUuid(), zooHashMap);
1775 String synParentGenus = parentSynZooName.getGenusOrUninomial();
1776 String synParentInfragenericName = null;
1777 String synParentSpecificEpithet = null;
1778
1779 if (parentSynZooName.isInfraGeneric()){
1780 synParentInfragenericName = parentSynZooName.getInfraGenericEpithet();
1781 }
1782 if (parentSynZooName.isSpecies()){
1783 synParentSpecificEpithet = parentSynZooName.getSpecificEpithet();
1784 }
1785
1786 /* if (synGenusName != null && !synonymsGenus.containsKey(synGenusName)){
1787 synonymsGenus.put(synGenusName, idInSource);
1788 }*/
1789
1790 //for all synonyms of the taxon
1791
1792 for (SynonymRelationship synonymRelationOfTaxon:synonymRelationshipsOfTaxon){
1793
1794 Synonym syn = synonymRelationOfTaxon.getSynonym();
1795 ZoologicalName zooSynName = getZoologicalName(syn.getName().getUuid(), zooHashMap);
1796 potentialCombination = createPotentialCombination(idInSourceParent, parentSynZooName, zooSynName,
1797 synParentGenus,
1798 synParentInfragenericName,
1799 synParentSpecificEpithet, syn, zooHashMap);
1800
1801 taxon.addSynonym(potentialCombination, SynonymRelationshipType.POTENTIAL_COMBINATION_OF());
1802 inferredSynonyms.add(potentialCombination);
1803 zooHashMap.put(potentialCombination.getName().getUuid(), (ZoologicalName)potentialCombination.getName());
1804 taxonNames.add(( (ZoologicalName)potentialCombination.getName()).getNameCache());
1805
1806 }
1807
1808
1809 }
1810
1811 if (doWithMisappliedNames){
1812
1813 for (TaxonRelationship parentRelationship: taxonRelListParent){
1814
1815 TaxonNameBase misappliedParentName;
1816
1817 Taxon misappliedParent = parentRelationship.getFromTaxon();
1818 misappliedParentName = misappliedParent.getName();
1819
1820 HibernateProxyHelper.deproxy(misappliedParent);
1821
1822 // Set the sourceReference
1823 sourceReference = misappliedParent.getSec();
1824
1825 // Determine the idInSource
1826 String idInSourceParent = getIdInSource(misappliedParent);
1827
1828 ZoologicalName parentSynZooName = getZoologicalName(misappliedParentName.getUuid(), zooHashMap);
1829 String synParentGenus = parentSynZooName.getGenusOrUninomial();
1830 String synParentInfragenericName = null;
1831 String synParentSpecificEpithet = null;
1832
1833 if (parentSynZooName.isInfraGeneric()){
1834 synParentInfragenericName = parentSynZooName.getInfraGenericEpithet();
1835 }
1836 if (parentSynZooName.isSpecies()){
1837 synParentSpecificEpithet = parentSynZooName.getSpecificEpithet();
1838 }
1839
1840
1841 for (TaxonRelationship taxonRelationship: taxonRelListTaxon){
1842 Taxon misappliedName = taxonRelationship.getFromTaxon();
1843 ZoologicalName zooMisappliedName = getZoologicalName(misappliedName.getName().getUuid(), zooHashMap);
1844 potentialCombination = createPotentialCombination(
1845 idInSourceParent, parentSynZooName, zooMisappliedName,
1846 synParentGenus,
1847 synParentInfragenericName,
1848 synParentSpecificEpithet, misappliedName, zooHashMap);
1849
1850
1851 taxon.addSynonym(potentialCombination, SynonymRelationshipType.POTENTIAL_COMBINATION_OF());
1852 inferredSynonyms.add(potentialCombination);
1853 zooHashMap.put(potentialCombination.getName().getUuid(), (ZoologicalName)potentialCombination.getName());
1854 taxonNames.add(( (ZoologicalName)potentialCombination.getName()).getNameCache());
1855 }
1856 }
1857 }
1858
1859 if (!taxonNames.isEmpty()){
1860 List<String> synNotInCDM = dao.taxaByNameNotInDB(taxonNames);
1861 ZoologicalName name;
1862 if (!synNotInCDM.isEmpty()){
1863 inferredSynonymsToBeRemoved.clear();
1864 for (Synonym syn :inferredSynonyms){
1865 try{
1866 name = (ZoologicalName) syn.getName();
1867 }catch (ClassCastException e){
1868 name = getZoologicalName(syn.getName().getUuid(), zooHashMap);
1869 }
1870 if (!synNotInCDM.contains(name.getNameCache())){
1871 inferredSynonymsToBeRemoved.add(syn);
1872 }
1873 }
1874 // Remove identified Synonyms from inferredSynonyms
1875 for (Synonym synonym : inferredSynonymsToBeRemoved) {
1876 inferredSynonyms.remove(synonym);
1877 }
1878 }
1879 }
1880 }
1881 }else {
1882 logger.info("The synonymrelationship type is not defined.");
1883 return inferredSynonyms;
1884 }
1885 }
1886 }
1887
1888 }
1889
1890 return inferredSynonyms;
1891 }
1892
1893 private Synonym createPotentialCombination(String idInSourceParent,
1894 ZoologicalName parentSynZooName, ZoologicalName zooSynName, String synParentGenus,
1895 String synParentInfragenericName, String synParentSpecificEpithet,
1896 TaxonBase syn, HashMap<UUID, ZoologicalName> zooHashMap) {
1897 Synonym potentialCombination;
1898 Reference sourceReference;
1899 ZoologicalName inferredSynName;
1900 HibernateProxyHelper.deproxy(syn);
1901
1902 // Set sourceReference
1903 sourceReference = syn.getSec();
1904 if (sourceReference == null){
1905 logger.warn("The synonym has no sec reference because it is a misapplied name! Take the sec reference of taxon");
1906 //TODO:Remove
1907 if (!parentSynZooName.getTaxa().isEmpty()){
1908 TaxonBase taxon = parentSynZooName.getTaxa().iterator().next();
1909
1910 sourceReference = taxon.getSec();
1911 }
1912 }
1913 String synTaxonSpecificEpithet = zooSynName.getSpecificEpithet();
1914
1915 String synTaxonInfraSpecificName= null;
1916
1917 if (parentSynZooName.isSpecies()){
1918 synTaxonInfraSpecificName = zooSynName.getInfraSpecificEpithet();
1919 }
1920
1921 /*if (epithetName != null && !synonymsEpithet.contains(epithetName)){
1922 synonymsEpithet.add(epithetName);
1923 }*/
1924
1925 //create potential combinations...
1926 inferredSynName = ZoologicalName.NewInstance(syn.getName().getRank());
1927
1928 inferredSynName.setGenusOrUninomial(synParentGenus);
1929 if (zooSynName.isSpecies()){
1930 inferredSynName.setSpecificEpithet(synTaxonSpecificEpithet);
1931 if (parentSynZooName.isInfraGeneric()){
1932 inferredSynName.setInfraGenericEpithet(synParentInfragenericName);
1933 }
1934 }
1935 if (zooSynName.isInfraSpecific()){
1936 inferredSynName.setSpecificEpithet(synParentSpecificEpithet);
1937 inferredSynName.setInfraSpecificEpithet(synTaxonInfraSpecificName);
1938 }
1939 if (parentSynZooName.isInfraGeneric()){
1940 inferredSynName.setInfraGenericEpithet(synParentInfragenericName);
1941 }
1942
1943
1944 potentialCombination = Synonym.NewInstance(inferredSynName, null);
1945
1946 // Set the sourceReference
1947 potentialCombination.setSec(sourceReference);
1948
1949
1950 // Determine the idInSource
1951 String idInSourceSyn= getIdInSource(syn);
1952
1953 if (idInSourceParent != null && idInSourceSyn != null) {
1954 IdentifiableSource originalSource = IdentifiableSource.NewInstance(OriginalSourceType.Transformation, idInSourceSyn + "; " + idInSourceParent, POTENTIAL_COMBINATION_NAMESPACE, sourceReference, null);
1955 inferredSynName.addSource(originalSource);
1956 originalSource = IdentifiableSource.NewInstance(OriginalSourceType.Transformation, idInSourceSyn + "; " + idInSourceParent, POTENTIAL_COMBINATION_NAMESPACE, sourceReference, null);
1957 potentialCombination.addSource(originalSource);
1958 }
1959
1960 inferredSynName.generateTitle();
1961
1962 return potentialCombination;
1963 }
1964
1965 private Synonym createInferredGenus(Taxon taxon,
1966 HashMap<UUID, ZoologicalName> zooHashMap, ZoologicalName taxonName,
1967 String epithetOfTaxon, String genusOfTaxon,
1968 List<String> taxonNames, ZoologicalName zooParentName,
1969 TaxonBase syn) {
1970
1971 Synonym inferredGenus;
1972 TaxonNameBase synName;
1973 ZoologicalName inferredSynName;
1974 synName =syn.getName();
1975 HibernateProxyHelper.deproxy(syn);
1976
1977 // Determine the idInSource
1978 String idInSourceSyn = getIdInSource(syn);
1979 String idInSourceTaxon = getIdInSource(taxon);
1980 // Determine the sourceReference
1981 Reference sourceReference = syn.getSec();
1982
1983 //logger.warn(sourceReference.getTitleCache());
1984
1985 synName = syn.getName();
1986 ZoologicalName synZooName = getZoologicalName(synName.getUuid(), zooHashMap);
1987 String synSpeciesEpithetName = synZooName.getSpecificEpithet();
1988 /* if (synonymsEpithet != null && !synonymsEpithet.contains(synSpeciesEpithetName)){
1989 synonymsEpithet.add(synSpeciesEpithetName);
1990 }*/
1991
1992 inferredSynName = ZoologicalName.NewInstance(taxon.getName().getRank());
1993 //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...
1994
1995
1996 inferredSynName.setGenusOrUninomial(genusOfTaxon);
1997 if (zooParentName.isInfraGeneric()){
1998 inferredSynName.setInfraGenericEpithet(zooParentName.getInfraGenericEpithet());
1999 }
2000
2001 if (taxonName.isSpecies()){
2002 inferredSynName.setSpecificEpithet(synSpeciesEpithetName);
2003 }
2004 if (taxonName.isInfraSpecific()){
2005 inferredSynName.setSpecificEpithet(epithetOfTaxon);
2006 inferredSynName.setInfraSpecificEpithet(synZooName.getInfraGenericEpithet());
2007 }
2008
2009
2010 inferredGenus = Synonym.NewInstance(inferredSynName, null);
2011
2012 // Set the sourceReference
2013 inferredGenus.setSec(sourceReference);
2014
2015 // Add the original source
2016 if (idInSourceSyn != null && idInSourceTaxon != null) {
2017 IdentifiableSource originalSource = IdentifiableSource.NewInstance(OriginalSourceType.Transformation,
2018 idInSourceSyn + "; " + idInSourceTaxon, INFERRED_GENUS_NAMESPACE, sourceReference, null);
2019 inferredGenus.addSource(originalSource);
2020
2021 originalSource = IdentifiableSource.NewInstance(OriginalSourceType.Transformation,
2022 idInSourceSyn + "; " + idInSourceTaxon, INFERRED_GENUS_NAMESPACE, sourceReference, null);
2023 inferredSynName.addSource(originalSource);
2024 originalSource = null;
2025
2026 }else{
2027 logger.error("There is an idInSource missing: " + idInSourceSyn + " of Synonym or " + idInSourceTaxon + " of Taxon");
2028 IdentifiableSource originalSource = IdentifiableSource.NewInstance(OriginalSourceType.Transformation,
2029 idInSourceSyn + "; " + idInSourceTaxon, INFERRED_GENUS_NAMESPACE, sourceReference, null);
2030 inferredGenus.addSource(originalSource);
2031
2032 originalSource = IdentifiableSource.NewInstance(OriginalSourceType.Transformation,
2033 idInSourceSyn + "; " + idInSourceTaxon, INFERRED_GENUS_NAMESPACE, sourceReference, null);
2034 inferredSynName.addSource(originalSource);
2035 originalSource = null;
2036 }
2037
2038 taxon.addSynonym(inferredGenus, SynonymRelationshipType.INFERRED_GENUS_OF());
2039
2040 inferredSynName.generateTitle();
2041
2042
2043 return inferredGenus;
2044 }
2045
2046 private Synonym createInferredEpithets(Taxon taxon,
2047 HashMap<UUID, ZoologicalName> zooHashMap, ZoologicalName taxonName,
2048 String epithetOfTaxon, String infragenericEpithetOfTaxon,
2049 String infraspecificEpithetOfTaxon, List<String> taxonNames,
2050 TaxonNameBase parentName, TaxonBase syn) {
2051
2052 Synonym inferredEpithet;
2053 TaxonNameBase<?,?> synName;
2054 ZoologicalName inferredSynName;
2055 HibernateProxyHelper.deproxy(syn);
2056
2057 // Determine the idInSource
2058 String idInSourceSyn = getIdInSource(syn);
2059 String idInSourceTaxon = getIdInSource(taxon);
2060 // Determine the sourceReference
2061 Reference<?> sourceReference = syn.getSec();
2062
2063 if (sourceReference == null){
2064 logger.warn("The synonym has no sec reference because it is a misapplied name! Take the sec reference of taxon");
2065 //TODO:Remove
2066 System.out.println("The synonym has no sec reference because it is a misapplied name! Take the sec reference of taxon" + taxon.getSec());
2067 sourceReference = taxon.getSec();
2068 }
2069
2070 synName = syn.getName();
2071 ZoologicalName zooSynName = getZoologicalName(synName.getUuid(), zooHashMap);
2072 String synGenusName = zooSynName.getGenusOrUninomial();
2073 String synInfraGenericEpithet = null;
2074 String synSpecificEpithet = null;
2075
2076 if (zooSynName.getInfraGenericEpithet() != null){
2077 synInfraGenericEpithet = zooSynName.getInfraGenericEpithet();
2078 }
2079
2080 if (zooSynName.isInfraSpecific()){
2081 synSpecificEpithet = zooSynName.getSpecificEpithet();
2082 }
2083
2084 /* if (synGenusName != null && !synonymsGenus.containsKey(synGenusName)){
2085 synonymsGenus.put(synGenusName, idInSource);
2086 }*/
2087
2088 inferredSynName = ZoologicalName.NewInstance(taxon.getName().getRank());
2089
2090 // DEBUG TODO: for subgenus or subspecies the infrageneric or infraspecific epithet should be used!!!
2091 if (epithetOfTaxon == null && infragenericEpithetOfTaxon == null && infraspecificEpithetOfTaxon == null) {
2092 logger.error("This specificEpithet is NULL" + taxon.getTitleCache());
2093 }
2094 inferredSynName.setGenusOrUninomial(synGenusName);
2095
2096 if (parentName.isInfraGeneric()){
2097 inferredSynName.setInfraGenericEpithet(synInfraGenericEpithet);
2098 }
2099 if (taxonName.isSpecies()){
2100 inferredSynName.setSpecificEpithet(epithetOfTaxon);
2101 }else if (taxonName.isInfraSpecific()){
2102 inferredSynName.setSpecificEpithet(synSpecificEpithet);
2103 inferredSynName.setInfraSpecificEpithet(infraspecificEpithetOfTaxon);
2104 }
2105
2106 inferredEpithet = Synonym.NewInstance(inferredSynName, null);
2107
2108 // Set the sourceReference
2109 inferredEpithet.setSec(sourceReference);
2110
2111 /* Add the original source
2112 if (idInSource != null) {
2113 IdentifiableSource originalSource = IdentifiableSource.NewInstance(idInSource, "InferredEpithetOf", syn.getSec(), null);
2114
2115 // Add the citation
2116 Reference citation = getCitation(syn);
2117 if (citation != null) {
2118 originalSource.setCitation(citation);
2119 inferredEpithet.addSource(originalSource);
2120 }
2121 }*/
2122 String taxonId = idInSourceTaxon+ "; " + idInSourceSyn;
2123
2124
2125 IdentifiableSource originalSource = IdentifiableSource.NewInstance(OriginalSourceType.Transformation,
2126 taxonId, INFERRED_EPITHET_NAMESPACE, sourceReference, null);
2127
2128 inferredEpithet.addSource(originalSource);
2129
2130 originalSource = IdentifiableSource.NewInstance(OriginalSourceType.Transformation,
2131 taxonId, INFERRED_EPITHET_NAMESPACE, sourceReference, null);
2132
2133 inferredSynName.addSource(originalSource);
2134
2135
2136
2137 taxon.addSynonym(inferredEpithet, SynonymRelationshipType.INFERRED_EPITHET_OF());
2138
2139 inferredSynName.generateTitle();
2140 return inferredEpithet;
2141 }
2142
2143 /**
2144 * Returns an existing ZoologicalName or extends an internal hashmap if it does not exist.
2145 * Very likely only useful for createInferredSynonyms().
2146 * @param uuid
2147 * @param zooHashMap
2148 * @return
2149 */
2150 private ZoologicalName getZoologicalName(UUID uuid, HashMap <UUID, ZoologicalName> zooHashMap) {
2151 ZoologicalName taxonName =nameDao.findZoologicalNameByUUID(uuid);
2152 if (taxonName == null) {
2153 taxonName = zooHashMap.get(uuid);
2154 }
2155 return taxonName;
2156 }
2157
2158 /**
2159 * Returns the idInSource for a given Synonym.
2160 * @param syn
2161 */
2162 private String getIdInSource(TaxonBase taxonBase) {
2163 String idInSource = null;
2164 Set<IdentifiableSource> sources = taxonBase.getSources();
2165 if (sources.size() == 1) {
2166 IdentifiableSource source = sources.iterator().next();
2167 if (source != null) {
2168 idInSource = source.getIdInSource();
2169 }
2170 } else if (sources.size() > 1) {
2171 int count = 1;
2172 idInSource = "";
2173 for (IdentifiableSource source : sources) {
2174 idInSource += source.getIdInSource();
2175 if (count < sources.size()) {
2176 idInSource += "; ";
2177 }
2178 count++;
2179 }
2180 } else if (sources.size() == 0){
2181 logger.warn("No idInSource for TaxonBase " + taxonBase.getUuid() + " - " + taxonBase.getTitleCache());
2182 }
2183
2184
2185 return idInSource;
2186 }
2187
2188
2189 /**
2190 * Returns the citation for a given Synonym.
2191 * @param syn
2192 */
2193 private Reference getCitation(Synonym syn) {
2194 Reference citation = null;
2195 Set<IdentifiableSource> sources = syn.getSources();
2196 if (sources.size() == 1) {
2197 IdentifiableSource source = sources.iterator().next();
2198 if (source != null) {
2199 citation = source.getCitation();
2200 }
2201 } else if (sources.size() > 1) {
2202 logger.warn("This Synonym has more than one source: " + syn.getUuid() + " (" + syn.getTitleCache() +")");
2203 }
2204
2205 return citation;
2206 }
2207
2208 @Override
2209 public List<Synonym> createAllInferredSynonyms(Taxon taxon, Classification tree, boolean doWithMisappliedNames){
2210 List <Synonym> inferredSynonyms = new ArrayList<Synonym>();
2211
2212 inferredSynonyms.addAll(createInferredSynonyms(taxon, tree, SynonymRelationshipType.INFERRED_EPITHET_OF(), doWithMisappliedNames));
2213 inferredSynonyms.addAll(createInferredSynonyms(taxon, tree, SynonymRelationshipType.INFERRED_GENUS_OF(), doWithMisappliedNames));
2214 inferredSynonyms.addAll(createInferredSynonyms(taxon, tree, SynonymRelationshipType.POTENTIAL_COMBINATION_OF(), doWithMisappliedNames));
2215
2216 return inferredSynonyms;
2217 }
2218
2219 /* (non-Javadoc)
2220 * @see eu.etaxonomy.cdm.api.service.ITaxonService#listClassifications(eu.etaxonomy.cdm.model.taxon.TaxonBase, java.lang.Integer, java.lang.Integer, java.util.List)
2221 */
2222 @Override
2223 public List<Classification> listClassifications(TaxonBase taxonBase, Integer limit, Integer start, List<String> propertyPaths) {
2224
2225 // TODO quickly implemented, create according dao !!!!
2226 Set<TaxonNode> nodes = new HashSet<TaxonNode>();
2227 Set<Classification> classifications = new HashSet<Classification>();
2228 List<Classification> list = new ArrayList<Classification>();
2229
2230 if (taxonBase == null) {
2231 return list;
2232 }
2233
2234 taxonBase = load(taxonBase.getUuid());
2235
2236 if (taxonBase instanceof Taxon) {
2237 nodes.addAll(((Taxon)taxonBase).getTaxonNodes());
2238 } else {
2239 for (Taxon taxon : ((Synonym)taxonBase).getAcceptedTaxa() ) {
2240 nodes.addAll(taxon.getTaxonNodes());
2241 }
2242 }
2243 for (TaxonNode node : nodes) {
2244 classifications.add(node.getClassification());
2245 }
2246 list.addAll(classifications);
2247 return list;
2248 }
2249
2250
2251
2252
2253
2254
2255 }