Project

General

Profile

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