Project

General

Profile

Download (23.5 KB) Statistics
| Branch: | Revision:
1
/**
2
* Copyright (C) 2009 EDIT
3
* European Distributed Institute of Taxonomy
4
* http://www.e-taxonomy.eu
5
*
6
* The contents of this file are subject to the Mozilla Public License Version 1.1
7
* See LICENSE.TXT at the top of this package for the full license terms.
8
*/
9
package eu.etaxonomy.cdm.io.pesi.out;
10

    
11
import java.util.ArrayList;
12
import java.util.EnumSet;
13
import java.util.HashSet;
14
import java.util.Iterator;
15
import java.util.List;
16
import java.util.Set;
17
import java.util.UUID;
18

    
19
import org.apache.log4j.Logger;
20

    
21
import eu.etaxonomy.cdm.api.service.pager.Pager;
22
import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
23
import eu.etaxonomy.cdm.io.berlinModel.BerlinModelTransformer;
24
import eu.etaxonomy.cdm.io.common.DbExportBase;
25
import eu.etaxonomy.cdm.io.common.mapping.out.DbLastActionMapper;
26
import eu.etaxonomy.cdm.io.pesi.erms.ErmsTransformer;
27
import eu.etaxonomy.cdm.model.common.AnnotationType;
28
import eu.etaxonomy.cdm.model.common.CdmBase;
29
import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
30
import eu.etaxonomy.cdm.model.common.IdentifiableSource;
31
import eu.etaxonomy.cdm.model.common.Marker;
32
import eu.etaxonomy.cdm.model.common.MarkerType;
33
import eu.etaxonomy.cdm.model.common.RelationshipBase;
34
import eu.etaxonomy.cdm.model.description.Feature;
35
import eu.etaxonomy.cdm.model.description.TaxonNameDescription;
36
import eu.etaxonomy.cdm.model.description.TextData;
37
import eu.etaxonomy.cdm.model.name.HybridRelationship;
38
import eu.etaxonomy.cdm.model.name.INonViralName;
39
import eu.etaxonomy.cdm.model.name.NameRelationship;
40
import eu.etaxonomy.cdm.model.name.NameRelationshipType;
41
import eu.etaxonomy.cdm.model.name.TaxonName;
42
import eu.etaxonomy.cdm.model.reference.Reference;
43
import eu.etaxonomy.cdm.model.taxon.Synonym;
44
import eu.etaxonomy.cdm.model.taxon.Taxon;
45
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
46
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
47
import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;
48
import eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType;
49
import eu.etaxonomy.cdm.persistence.query.OrderHint;
50
import eu.etaxonomy.cdm.strategy.cache.name.TaxonNameDefaultCacheStrategy;
51
import eu.etaxonomy.cdm.strategy.cache.name.ZooNameNoMarkerCacheStrategy;
52

    
53
/**
54
 * @author e.-m.lee
55
 * @since 12.02.2010
56
 */
57
public abstract class PesiExportBase
58
              extends DbExportBase<PesiExportConfigurator, PesiExportState, PesiTransformer> {
59

    
60
    private static final long serialVersionUID = 6226747017958138156L;
61
    private static final Logger logger = Logger.getLogger(PesiExportBase.class);
62

    
63
	protected static final boolean IS_CACHE = true;
64

    
65
	private static Set<NameRelationshipType> excludedRelTypes = new HashSet<>();
66

    
67
	private static TaxonNameDefaultCacheStrategy zooNameStrategy = ZooNameNoMarkerCacheStrategy.NewInstance();
68
	private static TaxonNameDefaultCacheStrategy botanicalNameStrategy = TaxonNameDefaultCacheStrategy.NewInstance();
69

    
70
	public PesiExportBase() {
71
		super();
72
	}
73

    
74
	protected <CLASS extends TaxonBase> List<CLASS> getNextTaxonPartition(Class<CLASS> clazz, int limit,
75
	        int partitionCount, List<String> propertyPath) {
76

    
77
	    List<OrderHint> orderHints = new ArrayList<>();
78
		orderHints.add(new OrderHint("id", OrderHint.SortOrder.ASCENDING ));
79

    
80
		List<CLASS> list = getTaxonService().list(clazz, limit, partitionCount * limit, orderHints, propertyPath);
81

    
82
		if (list.isEmpty()){
83
			return null;
84
		}
85

    
86
		Iterator<CLASS> it = list.iterator();
87
		while (it.hasNext()){
88
			TaxonBase<?> taxonBase = it.next();
89
			if (! isPesiTaxon(taxonBase)){
90
				it.remove();
91
			}
92
			taxonBase = null;
93
		}
94
		it = null;
95
		return list;
96
	}
97

    
98
	protected List<TaxonNameDescription> getNextNameDescriptionPartition(int limit, int partitionCount, List<String> propertyPath) {
99
		List<OrderHint> orderHints = new ArrayList<>();
100
		orderHints.add(new OrderHint("id", OrderHint.SortOrder.ASCENDING ));
101
		Pager<TaxonNameDescription> l = getDescriptionService().getTaxonNameDescriptions(null, limit, partitionCount, propertyPath);
102
		List<TaxonNameDescription> list = l.getRecords();
103
		if (list.isEmpty()){
104
			return null;
105
		}
106

    
107
		Iterator<TaxonNameDescription> it = list.iterator();
108
		while (it.hasNext()){
109
			TaxonNameDescription nameDescription = it.next();
110
			if (! isPesiNameDescriptionTaxon(nameDescription)){
111
				it.remove();
112
			}
113
		}
114
		return list;
115
	}
116

    
117
	private boolean isPesiNameDescriptionTaxon(TaxonNameDescription nameDescription) {
118
		TaxonName name = nameDescription.getTaxonName();
119
		if (isPurePesiName(name)){
120
			return true;
121
		}else{
122
			Set<TaxonBase> taxa = name.getTaxonBases();
123
			for (TaxonBase<?> taxonBase : taxa){
124
				if (isPesiTaxon(taxonBase)){
125
					return true;
126
				}
127
			}
128
		}
129
		return false;
130
	}
131

    
132
	/**
133
	 * Returns the next list of pure names. If finished result will be null. If list is empty there may be result in further partitions.
134
	 */
135
	protected List<TaxonName> getNextPureNamePartition(Class<TaxonName> clazz,int limit, int partitionCount) {
136
		List<OrderHint> orderHints = new ArrayList<>();
137
		orderHints.add(new OrderHint("id", OrderHint.SortOrder.ASCENDING ));
138
//		List<String> propPath = Arrays.asList(new String[]{"taxonBases"});
139

    
140
		List<TaxonName> list = getNameService().list(clazz, limit, partitionCount * limit, orderHints, null);
141
		if (list.isEmpty()){
142
			return null;
143
		}
144
		Iterator<TaxonName> it = list.iterator();
145
		while (it.hasNext()){
146
		    TaxonName taxonName = HibernateProxyHelper.deproxy(it.next());
147
			if (! isPurePesiName(taxonName)){
148
				it.remove();
149
			}
150
		}
151
		return list;
152
	}
153

    
154
	protected <CLASS extends RelationshipBase> List<CLASS> getNextNameRelationshipPartition(
155
	                Class<CLASS> clazz, int pageSize, int partitionCount, List<String> propertyPaths) {
156

    
157
	    List<CLASS> result = new ArrayList<>();
158
		List<OrderHint> orderHints = null;
159
		List<CLASS> list;
160
		if (NameRelationship.class.isAssignableFrom(clazz)){
161
            list = (List<CLASS>)getNameService().listNameRelationships(null, pageSize, partitionCount, orderHints, propertyPaths);
162
        }else if (HybridRelationship.class.isAssignableFrom(clazz)){
163
            list = (List<CLASS>)getNameService().listHybridRelationships(null, pageSize, partitionCount, orderHints, propertyPaths);
164
        }else{
165
            throw new RuntimeException("Only NameRelationship or HybridRelationship allowed here");
166
        }
167
		if (list.isEmpty()){
168
			return null;
169
		}
170
		for (CLASS rel : list){
171
			if (isPesiNameRelationship(rel)){
172
				result.add(rel);
173
			}
174
		}
175
		return result;
176
	}
177

    
178
	protected <CLASS extends RelationshipBase> List<CLASS> getNextTaxonRelationshipPartition( int limit, int partitionCount, List<String> propertyPaths) {
179

    
180
	    List<CLASS> result = new ArrayList<>();
181

    
182
	    List<OrderHint> orderHints = null;
183
		@SuppressWarnings("unchecked")
184
        List<CLASS> list = (List<CLASS>)this.getTaxonService()
185
		        .listTaxonRelationships(null, limit, partitionCount, orderHints, propertyPaths);
186

    
187
		if (list.isEmpty()){
188
			return null;
189
		}
190

    
191
		for (CLASS rel : list){
192
			if (isPesiTaxonOrSynonymRelationship(rel)){
193
				result.add(rel);
194
			}
195
		}
196
		return result;
197
	}
198

    
199
    protected List<TaxonNode> getNextTaxonNodePartition( int limit, int partitionCount, List<String> propertyPaths) {
200

    
201
        List<TaxonNode> result = new ArrayList<>();
202

    
203
        List<OrderHint> orderHints = null;
204
        List<TaxonNode> list = this.getTaxonNodeService()
205
            .list(TaxonNode.class, limit, limit * partitionCount, orderHints, propertyPaths);
206

    
207
        if (list.isEmpty()){
208
            return null;
209
        }
210

    
211
        for (TaxonNode tn : list){
212
            if (isPesiTaxonNode(tn)){
213
                result.add(tn);
214
            }
215
        }
216
        return result;
217
    }
218

    
219
    protected boolean isPesiTaxonNode(TaxonNode tn){
220
        TaxonBase<?> fromTaxon;
221
        Taxon toTaxon;
222

    
223
        fromTaxon = tn.getTaxon();
224
        toTaxon = tn.getParent()== null? null: tn.getParent().getTaxon();
225

    
226
        return (isPesiTaxon(fromTaxon, true) && isPesiTaxon(toTaxon, true));
227
    }
228

    
229
	protected boolean isPesiNameRelationship(RelationshipBase<?,?,?> rel){
230
		TaxonName name1;
231
		TaxonName name2;
232
		if (rel.isInstanceOf(HybridRelationship.class)){
233
			HybridRelationship hybridRel = CdmBase.deproxy(rel, HybridRelationship.class);
234
			name1 = hybridRel.getParentName();
235
			name2 = hybridRel.getHybridName();
236
		}else if (rel.isInstanceOf(NameRelationship.class)){
237
			NameRelationship nameRel = CdmBase.deproxy(rel, NameRelationship.class);
238
			name1 = nameRel.getFromName();
239
			name2 = nameRel.getToName();
240
		}else{
241
			logger.warn ("Only hybrid- and name-relationships alowed here");
242
			return false;
243
		}
244
		return (isPesiName(name1) && isPesiName(name2));
245
	}
246

    
247
	private boolean isPesiName(TaxonName name) {
248
		return hasPesiTaxon(name) || isPurePesiName(name);
249
	}
250

    
251
	protected boolean isPesiTaxonOrSynonymRelationship(RelationshipBase rel){
252
		TaxonBase<?> fromTaxon;
253
		Taxon toTaxon;
254
		// TODO:fix!!!
255
//		if (rel.isInstanceOf(SynonymRelationship.class)){
256
//			SynonymRelationship synRel = CdmBase.deproxy(rel, SynonymRelationship.class);
257
//			fromTaxon = synRel.getSynonym();
258
//			toTaxon = synRel.getAcceptedTaxon();
259
//			synRel = null;
260
//		}else
261
		if (rel.isInstanceOf(TaxonRelationship.class)){
262
			TaxonRelationship taxRel = CdmBase.deproxy(rel, TaxonRelationship.class);
263
			fromTaxon = taxRel.getFromTaxon();
264
			toTaxon = taxRel.getToTaxon();
265
			taxRel = null;
266
		}else{
267
			logger.warn ("Only synonym - and taxon-relationships allowed here");
268
			return false;
269
		}
270
		return (isPesiTaxon(fromTaxon, false) && isPesiTaxon(toTaxon, true));
271
	}
272

    
273
	/**
274
	 * Decides if a name is not used as the name part of a PESI taxon (and therefore is
275
	 * exported to PESI as taxon already) but is related to a name used as a PESI taxon
276
	 * (e.g. as basionym, orthographic variant, etc.) and therefore should be exported
277
	 * to PESI as part of the name relationship.
278
	 * @param taxonName
279
	 * @return
280
	 */
281
	protected boolean isPurePesiName(TaxonName taxonName){
282
		if (hasPesiTaxon(taxonName)){
283
			return false;
284
		}
285

    
286
		//from names
287
		for (NameRelationship rel :taxonName.getRelationsFromThisName()){
288
			TaxonName relatedName = rel.getToName();
289
			if (hasPesiTaxon(relatedName)){
290
				return true;
291
			}
292
		}
293

    
294
		//excluded relationships on to-side
295
		initExcludedRelTypes();
296

    
297
		//to names
298
		for (NameRelationship rel :taxonName.getRelationsToThisName()){
299
			//exclude certain types
300
			if (excludedRelTypes.contains(rel.getType())){
301
				continue;
302
			}
303
			TaxonName relatedName = rel.getFromName();
304
			if (hasPesiTaxon(relatedName)){
305
				return true;
306
			}
307
		}
308

    
309
		//include hybrid parents, but no childs
310

    
311
		for (HybridRelationship rel : taxonName.getHybridParentRelations()){
312
			INonViralName child = rel.getHybridName();
313
			if (hasPesiTaxon(child)){
314
				return true;
315
			}
316
		}
317

    
318
		return false;
319
	}
320

    
321

    
322
	private void initExcludedRelTypes() {
323
		if (excludedRelTypes.isEmpty()){
324
			excludedRelTypes.add(NameRelationshipType.BASIONYM());
325
			excludedRelTypes.add(NameRelationshipType.REPLACED_SYNONYM());
326
			excludedRelTypes.add(NameRelationshipType.ORTHOGRAPHIC_VARIANT());
327
		}
328
	}
329

    
330

    
331
	/**
332
	 * Decides if a given name has "PESI taxa" attached.
333
	 *
334
	 * @see #getPesiTaxa(TaxonNameBase)
335
	 * @see #isPesiTaxon(TaxonBase)
336
	 * @param taxonName
337
	 * @return
338
	 */
339
	protected boolean hasPesiTaxon(INonViralName taxonName) {
340
		for (TaxonBase<?> taxon : taxonName.getTaxonBases()){
341
			if (isPesiTaxon(taxon)){
342
				return true;
343
			}
344
		}
345
		return false;
346
	}
347

    
348
	/**
349
	 * Returns those concepts (taxon bases) for the given name that
350
	 * are pesi taxa.
351
	 *
352
	 *  @see #isPesiTaxon(TaxonBase)
353
	 * @param name
354
	 * @return
355
	 */
356
	protected Set<TaxonBase<?>> getPesiTaxa(TaxonName name){
357
		Set<TaxonBase<?>> result = new HashSet<>();
358
		for (TaxonBase<?> taxonBase : name.getTaxonBases()){
359
			if (isPesiTaxon(taxonBase)){
360
				result.add(taxonBase);
361
			}
362
		}
363
		return result;
364
	}
365

    
366
	/**
367
	 * @see #isPesiTaxon(TaxonBase, boolean)
368
	 * @return
369
	 */
370
	protected static boolean isPesiTaxon(TaxonBase taxonBase) {
371
		return isPesiTaxon(taxonBase, false);
372
	}
373

    
374
	/**
375
	 * Checks if this taxon base is a taxon that is to be exported to PESI. This is generally the case
376
	 * but not for taxa that are marked as "unpublish". Synonyms and misapplied names are exported if they are
377
	 * related at least to one accepted taxon that is also exported, except for those misapplied names
378
	 * marked as misapplied names created by Euro+Med common names ({@linkplain http://dev.e-taxonomy.eu/trac/ticket/2786} ).
379
	 * The list of conditions may change in future.
380
	 * @param taxonBase
381
	 * @return
382
	 */
383
	protected static boolean isPesiTaxon(TaxonBase<?> taxonBase, boolean excludeMisappliedNames) {
384
		if (taxonBase == null){
385
		    return false;
386
		}
387
	    //handle accepted taxa
388
		if (taxonBase.isInstanceOf(Taxon.class)){
389
			Taxon taxon = CdmBase.deproxy(taxonBase, Taxon.class);
390
			return isPesiAcceptedTaxon(excludeMisappliedNames, taxon);
391
		//handle synonyms
392
		}else if (taxonBase.isInstanceOf(Synonym.class)){
393
			Synonym synonym = CdmBase.deproxy(taxonBase, Synonym.class);
394
			return isPesiSynonym(synonym);
395
		}else {
396
			throw new RuntimeException("Unknown taxon base type: " + taxonBase.getClass());
397
		}
398
	}
399

    
400
    private static boolean isPesiSynonym(Synonym synonym) {
401
        boolean hasAcceptedPesiTaxon = false;
402

    
403
        hasAcceptedPesiTaxon = isPesiTaxon(synonym.getAcceptedTaxon());
404
        if (!hasAcceptedPesiTaxon) {if (logger.isDebugEnabled()){logger.debug("Synonym has no accepted PESI taxon: " +  synonym.getUuid() + ", (" +  synonym.getTitleCache() + ")");}}
405

    
406
        return hasAcceptedPesiTaxon && synonym.isPublish();
407
    }
408

    
409
    private static boolean isPesiAcceptedTaxon(boolean excludeMisappliedNames, Taxon taxon) {
410
        if (! taxon.isPublish()){
411
        	return false;
412
        }
413
        for (Marker marker : taxon.getMarkers()){
414
        	//probably not needed anymore after #1780 was fixed, also #4046 interesting
415
        	if (marker.getValue() == false && marker.getMarkerType().equals(MarkerType.PUBLISH())){
416
        		return false;
417
        	//probably not needed any more after #2786 was fixed
418
        	}else if (marker.getValue() == true && marker.getMarkerType().getUuid().equals(BerlinModelTransformer.uuidMisappliedCommonName)){
419
        		logger.warn("Misapplied common name still exists");
420
        		return false;
421
        	}
422
        }
423

    
424
        //handle PESI accepted taxa
425
        if (! taxon.isMisapplication()){
426
        	for (Marker marker : taxon.getMarkers()){
427
        		if (marker.getValue() == false && marker.getMarkerType().equals(MarkerType.PUBLISH())){
428
        			return false;
429
        		}
430
        	}
431
        	return true;
432
        //handle misapplied names
433
        }else{
434
        	if (excludeMisappliedNames){
435
        		return false;
436
        	}
437
        	for (Marker marker : taxon.getMarkers()){
438
        		//probably not needed any more after #2786 was fixed
439
        		if (marker.getValue() == true && marker.getMarkerType().getUuid().equals(BerlinModelTransformer.uuidMisappliedCommonName)){
440
        			logger.warn("Misapplied common name still exists");
441
        			return false;
442
        		}
443
        	}
444
        	for (TaxonRelationship taxRel : taxon.getRelationsFromThisTaxon()){
445
        		if (taxRel.getType().isAnyMisappliedName()){
446
//						logger.warn(taxRel.getUuid() + "; " + taxRel.getToTaxon().getUuid() + " + " + taxRel.getToTaxon().getTitleCache());
447
        			if (isPesiTaxon(taxRel.getToTaxon(), true)){
448
        				return true;
449
        			}
450
        		}
451
        	}
452
        	if (logger.isDebugEnabled()){ logger.debug("Misapplied name has no accepted PESI taxon: " +  taxon.getUuid() + ", (" +  taxon.getTitleCache() + ")");}
453
        	return false;
454
        }
455
    }
456

    
457
	@Override
458
    protected Object getDbIdCdmWithExceptions(CdmBase cdmBase, PesiExportState state) {
459
		if (cdmBase.isInstanceOf(TaxonName.class)){
460
		    TaxonName name = CdmBase.deproxy(cdmBase, TaxonName.class);
461
		    if (name.getTaxonBases().size()>1){
462
		        logger.warn("Name has multiple taxa. Can't define correct ID. Use first one." + name.getUuid());
463
		    }
464
		    if (!name.getTaxonBases().isEmpty()){
465
		        TaxonBase<?> tb = name.getTaxonBases().iterator().next();
466
		        return this.getDbId(tb, state);
467
            }else{
468
                return ( cdmBase.getId() + state.getConfig().getNameIdStart() );
469
            }
470
		}else if (isAdditionalSource(cdmBase) ){
471
			return ( cdmBase.getId() + 2 * state.getConfig().getNameIdStart() );  //make it a separate variable if conflicts occur.
472
		}else{
473
			return super.getDbIdCdmWithExceptions(cdmBase, state);
474
		}
475
	}
476

    
477
	private boolean isAdditionalSource(CdmBase cdmBase) {
478
		if (cdmBase.isInstanceOf(TextData.class)){
479
			TextData textData = CdmBase.deproxy(cdmBase, TextData.class);
480
			if (textData.getFeature().equals(Feature.ADDITIONAL_PUBLICATION()) ||
481
					textData.getFeature().equals(Feature.CITATION())){
482
				return true;
483
			}
484
		}
485
		return false;
486
	}
487

    
488
	protected MarkerType getUuidMarkerType(UUID uuid, PesiExportState state){
489
		if (uuid == null){
490
			uuid = UUID.randomUUID();
491
		}
492

    
493
		MarkerType markerType = state.getMarkerType(uuid);
494
		if (markerType == null){
495
			if (uuid.equals(PesiTransformer.uuidMarkerGuidIsMissing)){
496
				markerType = MarkerType.NewInstance("Uuid is Missing", "Uuid is missing", null);
497
				markerType.setUuid(uuid);
498
			} else if (uuid.equals(PesiTransformer.uuidMarkerTypeHasNoLastAction)){
499
				markerType = MarkerType.NewInstance("Has no last Action", "Has no last action", null);
500
				markerType.setUuid(uuid);
501
			}
502
		}
503

    
504
		state.putMarkerType(markerType);
505
		return markerType;
506
	}
507

    
508
	protected static TaxonNameDefaultCacheStrategy getCacheStrategy(TaxonName taxonName) {
509
	    TaxonNameDefaultCacheStrategy cacheStrategy;
510
		if (taxonName.isZoological()){
511
			cacheStrategy = zooNameStrategy;
512
		}else if (taxonName.isBotanical()) {
513
			cacheStrategy = botanicalNameStrategy;
514
		}else{
515
			logger.error("Unhandled taxon name type. Can't define strategy class");
516
			cacheStrategy = botanicalNameStrategy;
517
		}
518
		return cacheStrategy;
519
	}
520

    
521
	/**
522
	 * Checks whether a given taxon is a misapplied name.
523
	 * @param taxon The {@link TaxonBase Taxon}.
524
	 * @return Whether the given TaxonName is a misapplied name or not.
525
	 */
526
	protected static boolean isMisappliedName(TaxonBase<?> taxon) {
527
		return getAcceptedTaxonForMisappliedName(taxon) != null;
528
	}
529

    
530
	/**
531
	 * Returns the first accepted taxon for this misapplied name.
532
	 * If this misapplied name is not a misapplied name, <code>null</code> is returned.
533
	 * @param taxon The {@link TaxonBase Taxon}.
534
	 */
535
	private static Taxon getAcceptedTaxonForMisappliedName(TaxonBase<?> taxon) {
536
		if (! taxon.isInstanceOf(Taxon.class)){
537
			return null;
538
		}
539
		Set<TaxonRelationship> taxonRelations = CdmBase.deproxy(taxon, Taxon.class).getRelationsFromThisTaxon();
540
		for (TaxonRelationship taxonRelationship : taxonRelations) {
541
			TaxonRelationshipType taxonRelationshipType = taxonRelationship.getType();
542
			if (taxonRelationshipType.equals(TaxonRelationshipType.MISAPPLIED_NAME_FOR())) {
543
				return taxonRelationship.getToTaxon();
544
			}
545
		}
546
		return null;
547
	}
548

    
549
    protected List<AnnotationType> getLastActionAnnotationTypes() {
550
        Set<UUID> uuidSet = new HashSet<>();
551
        uuidSet.add(DbLastActionMapper.uuidAnnotationTypeLastActionDate);
552
        uuidSet.add(DbLastActionMapper.uuidAnnotationTypeLastAction);
553
        uuidSet.add(ErmsTransformer.uuidAnnSpeciesExpertName);
554
        @SuppressWarnings({"unchecked","rawtypes"})
555
        List<AnnotationType> result = (List)getTermService().find(uuidSet);
556
        return result;
557
    }
558

    
559
    protected enum PesiSource{
560
        EM,
561
        FE,
562
        ERMS,
563
        IF;
564

    
565
        private PesiSource(){
566

    
567
        }
568
    }
569

    
570
    /**
571
     * Returns the source (E+M, Fauna Europaea, Index Fungorum, ERMS) of a given
572
     * Identifiable Entity as an {@link EnumSet enum set}
573
     */
574
    protected static EnumSet<PesiSource> getSources(IdentifiableEntity<?> entity){
575
        EnumSet<PesiSource> result = EnumSet.noneOf(PesiSource.class);
576

    
577
        Set<IdentifiableSource> sources = getPesiSources(entity);
578
        for (IdentifiableSource source : sources) {
579
            Reference ref = source.getCitation();
580
            UUID refUuid = ref.getUuid();
581
            if (refUuid.equals(PesiTransformer.uuidSourceRefEuroMed)){
582
                result.add(PesiSource.EM);
583
            }else if (refUuid.equals(PesiTransformer.uuidSourceRefFaunaEuropaea)){
584
                result.add(PesiSource.FE);
585
            }else if (refUuid.equals(PesiTransformer.uuidSourceRefErms)){
586
                result.add(PesiSource.ERMS);
587
            }else if (refUuid.equals(PesiTransformer.uuidSourceRefIndexFungorum)){
588
                result.add(PesiSource.IF);
589
            }else{
590
                if (logger.isDebugEnabled()){logger.debug("Not a PESI source");};
591
            }
592
        }
593
        return result;
594
    }
595

    
596
    /**
597
     * Returns the Sources for a given TaxonName only.
598
     * @param identifiableEntity
599
     * @return The Sources.
600
     */
601
    protected static Set<IdentifiableSource> getPesiSources(IdentifiableEntity<?> identifiableEntity) {
602
        Set<IdentifiableSource> sources = new HashSet<>();
603

    
604
        //Taxon Names
605
        if (identifiableEntity.isInstanceOf(TaxonName.class)){
606
            // Sources from TaxonName
607
            TaxonName taxonName = CdmBase.deproxy(identifiableEntity, TaxonName.class);
608
            Set<IdentifiableSource> testSources = identifiableEntity.getSources();
609
            sources = filterPesiSources(testSources);
610

    
611
            if (sources.size() == 0 && testSources.size()>0){
612
                IdentifiableSource source = testSources.iterator().next();
613
                logger.warn("There are sources, but they are no pesi sources!!!" + source.getIdInSource() + " - " + source.getIdNamespace() + " - " + source.getCitation().getTitleCache());
614
            }
615
            if (sources.size() > 1) {
616
                logger.warn("This TaxonName has more than one Source: " + identifiableEntity.getUuid() + " (" + identifiableEntity.getTitleCache() + ")");
617
            }
618

    
619
            // name has no PESI source, take sources from TaxonBase
620
            if (sources == null || sources.isEmpty()) {
621
                Set<TaxonBase> taxa = taxonName.getTaxonBases();
622
                for (TaxonBase<?> taxonBase: taxa){
623
                    sources.addAll(filterPesiSources(taxonBase.getSources()));
624
                }
625
            }
626

    
627
        //for TaxonBases
628
        }else if (identifiableEntity.isInstanceOf(TaxonBase.class)){
629
            sources = filterPesiSources(identifiableEntity.getSources());
630
        } else {
631
            sources = filterPesiSources(identifiableEntity.getSources());
632
        }
633

    
634
        return sources;
635
    }
636

    
637
    // return all sources with a PESI reference
638
    protected static Set<IdentifiableSource> filterPesiSources(Set<? extends IdentifiableSource> sources) {
639
        Set<IdentifiableSource> result = new HashSet<>();
640
        for (IdentifiableSource source : sources){
641
            Reference ref = source.getCitation();
642
            if (ref != null){
643
                UUID refUuid = ref.getUuid();
644
                if (refUuid.equals(PesiTransformer.uuidSourceRefEuroMed) ||
645
                        refUuid.equals(PesiTransformer.uuidSourceRefFaunaEuropaea)||
646
                        refUuid.equals(PesiTransformer.uuidSourceRefErms)||
647
                        refUuid.equals(PesiTransformer.uuidSourceRefIndexFungorum) ||
648
                        refUuid.equals(PesiTransformer.uuidSourceRefAuct)){
649
                    result.add(source);
650
                }
651
            }
652
        }
653
        return result;
654
    }
655

    
656
}
(6-6/14)