Project

General

Profile

Download (17.2 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.Arrays;
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.model.common.CdmBase;
26
import eu.etaxonomy.cdm.model.common.Marker;
27
import eu.etaxonomy.cdm.model.common.MarkerType;
28
import eu.etaxonomy.cdm.model.common.RelationshipBase;
29
import eu.etaxonomy.cdm.model.description.Feature;
30
import eu.etaxonomy.cdm.model.description.TaxonNameDescription;
31
import eu.etaxonomy.cdm.model.description.TextData;
32
import eu.etaxonomy.cdm.model.name.HybridRelationship;
33
import eu.etaxonomy.cdm.model.name.INonViralName;
34
import eu.etaxonomy.cdm.model.name.NameRelationship;
35
import eu.etaxonomy.cdm.model.name.NameRelationshipType;
36
import eu.etaxonomy.cdm.model.name.TaxonName;
37
import eu.etaxonomy.cdm.model.taxon.Synonym;
38
import eu.etaxonomy.cdm.model.taxon.Taxon;
39
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
40
import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;
41
import eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType;
42
import eu.etaxonomy.cdm.persistence.query.OrderHint;
43
import eu.etaxonomy.cdm.strategy.cache.name.TaxonNameDefaultCacheStrategy;
44
import eu.etaxonomy.cdm.strategy.cache.name.ZooNameNoMarkerCacheStrategy;
45

    
46
/**
47
 * @author e.-m.lee
48
 * @since 12.02.2010
49
 *
50
 */
51
public abstract class PesiExportBase extends DbExportBase<PesiExportConfigurator, PesiExportState, PesiTransformer> {
52

    
53
    private static final long serialVersionUID = 6226747017958138156L;
54
    private static final Logger logger = Logger.getLogger(PesiExportBase.class);
55

    
56
	protected static final boolean IS_CACHE = true;
57

    
58
	private static Set<NameRelationshipType> excludedRelTypes = new HashSet<>();
59

    
60
	private static TaxonNameDefaultCacheStrategy zooNameStrategy = ZooNameNoMarkerCacheStrategy.NewInstance();
61
	private static TaxonNameDefaultCacheStrategy botanicalNameStrategy = TaxonNameDefaultCacheStrategy.NewInstance();
62

    
63
	public PesiExportBase() {
64
		super();
65
	}
66

    
67

    
68
	protected <CLASS extends TaxonBase> List<CLASS> getNextTaxonPartition(Class<CLASS> clazz, int limit, int partitionCount, List<String> propertyPath) {
69
		List<OrderHint> orderHints = new ArrayList<OrderHint>();
70
		orderHints.add(new OrderHint("id", OrderHint.SortOrder.ASCENDING ));
71

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

    
74

    
75

    
76
		if (list.isEmpty()){
77
			return null;
78
		}
79

    
80
		Iterator<CLASS> it = list.iterator();
81
		while (it.hasNext()){
82
			TaxonBase<?> taxonBase = it.next();
83
			if (! isPesiTaxon(taxonBase)){
84
				it.remove();
85
			}
86
			taxonBase = null;
87
		}
88
		it = null;
89
		return list;
90
	}
91

    
92
	protected List<TaxonNameDescription> getNextNameDescriptionPartition(int limit, int partitionCount, List<String> propertyPath) {
93
		List<OrderHint> orderHints = new ArrayList<OrderHint>();
94
		orderHints.add(new OrderHint("id", OrderHint.SortOrder.ASCENDING ));
95
		Pager<TaxonNameDescription> l = getDescriptionService().getTaxonNameDescriptions(null, limit, partitionCount, propertyPath);
96
		List<TaxonNameDescription> list = l.getRecords();
97
		if (list.isEmpty()){
98
			return null;
99
		}
100

    
101
		Iterator<TaxonNameDescription> it = list.iterator();
102
		while (it.hasNext()){
103
			TaxonNameDescription nameDescription = it.next();
104
			if (! isPesiNameDescriptionTaxon(nameDescription)){
105
				it.remove();
106
			}
107
		}
108
		return list;
109
	}
110

    
111

    
112
	private boolean isPesiNameDescriptionTaxon(TaxonNameDescription nameDescription) {
113
		TaxonName name = nameDescription.getTaxonName();
114
		if (isPurePesiName(name)){
115
			return true;
116
		}else{
117
			Set<TaxonBase> taxa = name.getTaxonBases();
118
			for (TaxonBase<?> taxonBase : taxa){
119
				if (isPesiTaxon(taxonBase)){
120
					return true;
121
				}
122
			}
123

    
124
		}
125
		return false;
126
	}
127

    
128

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

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

    
155
	protected <CLASS extends RelationshipBase> List<CLASS> getNextNameRelationshipPartition(Class<CLASS> clazz, int limit, int partitionCount, List<String> propertyPath) {
156
		List<CLASS> result = new ArrayList<CLASS>();
157
		String[] propertyPaths = null;
158
		String orderHints = null;
159
		List<CLASS> list = (List<CLASS>)getNameService().getAllRelationships(limit, partitionCount * limit);
160
		if (list.isEmpty()){
161
			return null;
162
		}
163
		for (CLASS rel : list){
164
			if (isPesiNameRelationship(rel)){
165
				result.add(rel);
166
			}
167
		}
168
		return result;
169
	}
170

    
171
	protected <CLASS extends RelationshipBase> List<CLASS> getNextTaxonRelationshipPartition( int limit, int partitionCount, List<String> propertyPath) {
172
		List<CLASS> result = new ArrayList<CLASS>();
173
		String[] propertyPaths = null;
174
		String orderHints = null;
175
		//TODO: fix!!!!
176

    
177
//		List<CLASS> list = (List<CLASS>)getTaxonService().getAllRelationships(limit, partitionCount * limit);
178
//
179
//		if (list.isEmpty()){
180
//			return null;
181
//		}
182
//
183
//		for (CLASS rel : list){
184
//			if (isPesiTaxonOrSynonymRelationship(rel)){
185
//				result.add(rel);
186
//			}
187
//		}
188
		return result;
189
	}
190

    
191
	protected boolean isPesiNameRelationship(RelationshipBase rel){
192
		TaxonName name1;
193
		TaxonName name2;
194
		if (rel.isInstanceOf(HybridRelationship.class)){
195
			HybridRelationship hybridRel = CdmBase.deproxy(rel, HybridRelationship.class);
196
			name1 = hybridRel.getParentName();
197
			name2 = hybridRel.getHybridName();
198
		}else if (rel.isInstanceOf(NameRelationship.class)){
199
			NameRelationship nameRel = CdmBase.deproxy(rel, NameRelationship.class);
200
			name1 = nameRel.getFromName();
201
			name2 = nameRel.getToName();
202
		}else{
203
			logger.warn ("Only hybrid- and name-relationships alowed here");
204
			return false;
205
		}
206
		return (isPesiName(name1) && isPesiName(name2));
207

    
208
	}
209

    
210
	private boolean isPesiName(TaxonName name) {
211
		return hasPesiTaxon(name) || isPurePesiName(name);
212
	}
213

    
214
	protected boolean isPesiTaxonOrSynonymRelationship(RelationshipBase rel){
215
		TaxonBase<?> fromTaxon;
216
		Taxon toTaxon;
217
		// TODO:fix!!!
218
//		if (rel.isInstanceOf(SynonymRelationship.class)){
219
//			SynonymRelationship synRel = CdmBase.deproxy(rel, SynonymRelationship.class);
220
//			fromTaxon = synRel.getSynonym();
221
//			toTaxon = synRel.getAcceptedTaxon();
222
//			synRel = null;
223
//		}else
224
		    if (rel.isInstanceOf(TaxonRelationship.class)){
225
			TaxonRelationship taxRel = CdmBase.deproxy(rel, TaxonRelationship.class);
226
			fromTaxon = taxRel.getFromTaxon();
227
			toTaxon = taxRel.getToTaxon();
228
			taxRel = null;
229
		}else{
230
			logger.warn ("Only synonym - and taxon-relationships allowed here");
231
			return false;
232
		}
233
		return (isPesiTaxon(fromTaxon, false) && isPesiTaxon(toTaxon, true));
234

    
235
	}
236

    
237

    
238

    
239
	/**
240
	 * Decides if a name is not used as the name part of a PESI taxon (and therefore is
241
	 * exported to PESI as taxon already) but is related to a name used as a PESI taxon
242
	 * (e.g. as basionym, orthographic variant, etc.) and therefore should be exported
243
	 * to PESI as part of the name relationship.
244
	 * @param taxonName
245
	 * @return
246
	 */
247
	protected boolean isPurePesiName(TaxonName taxonName){
248
		if (hasPesiTaxon(taxonName)){
249
			return false;
250
		}
251

    
252
		//from names
253
		for (NameRelationship rel :taxonName.getRelationsFromThisName()){
254
			TaxonName relatedName = rel.getToName();
255
			if (hasPesiTaxon(relatedName)){
256
				return true;
257
			}
258
		}
259

    
260
		//excluded relationships on to-side
261
		initExcludedRelTypes();
262

    
263
		//to names
264
		for (NameRelationship rel :taxonName.getRelationsToThisName()){
265
			//exclude certain types
266
			if (excludedRelTypes.contains(rel.getType())){
267
				continue;
268
			}
269
			TaxonName relatedName = rel.getFromName();
270
			if (hasPesiTaxon(relatedName)){
271
				return true;
272
			}
273
		}
274

    
275
		//include hybrid parents, but no childs
276

    
277
		for (HybridRelationship rel : taxonName.getHybridParentRelations()){
278
			INonViralName child = rel.getHybridName();
279
			if (hasPesiTaxon(child)){
280
				return true;
281
			}
282
		}
283

    
284
		return false;
285
	}
286

    
287

    
288
	private void initExcludedRelTypes() {
289
		if (excludedRelTypes.isEmpty()){
290
			excludedRelTypes.add(NameRelationshipType.BASIONYM());
291
			excludedRelTypes.add(NameRelationshipType.REPLACED_SYNONYM());
292
			excludedRelTypes.add(NameRelationshipType.ORTHOGRAPHIC_VARIANT());
293
		}
294
	}
295

    
296

    
297
	/**
298
	 * Decides if a given name has "PESI taxa" attached.
299
	 *
300
	 * @see #getPesiTaxa(TaxonNameBase)
301
	 * @see #isPesiTaxon(TaxonBase)
302
	 * @param taxonName
303
	 * @return
304
	 */
305
	protected boolean hasPesiTaxon(INonViralName taxonName) {
306
		for (TaxonBase<?> taxon : taxonName.getTaxonBases()){
307
			if (isPesiTaxon(taxon)){
308
				return true;
309
			}
310
		}
311
		return false;
312
	}
313

    
314
	/**
315
	 * Returns those concepts (taxon bases) for the given name that
316
	 * are pesi taxa.
317
	 *
318
	 *  @see #isPesiTaxon(TaxonBase)
319
	 * @param name
320
	 * @return
321
	 */
322
	protected Set<TaxonBase<?>> getPesiTaxa(TaxonName name){
323
		Set<TaxonBase<?>> result = new HashSet<>();
324
		for (TaxonBase<?> taxonBase : name.getTaxonBases()){
325
			if (isPesiTaxon(taxonBase)){
326
				result.add(taxonBase);
327
			}
328
		}
329
		return result;
330
	}
331

    
332

    
333
	/**
334
	 * @see #isPesiTaxon(TaxonBase, boolean)
335
	 * @param taxonBase
336
	 * @return
337
	 */
338
	protected static boolean isPesiTaxon(TaxonBase taxonBase) {
339
		return isPesiTaxon(taxonBase, false);
340
	}
341

    
342

    
343
	/**
344
	 * Checks if this taxon base is a taxon that is to be exported to PESI. This is generally the case
345
	 * but not for taxa that are marked as "unpublish". Synonyms and misapplied names are exported if they are
346
	 * related at least to one accepted taxon that is also exported, except for those misapplied names
347
	 * marked as misapplied names created by Euro+Med common names ({@linkplain http://dev.e-taxonomy.eu/trac/ticket/2786} ).
348
	 * The list of conditions may change in future.
349
	 * @param taxonBase
350
	 * @return
351
	 */
352
	protected static boolean isPesiTaxon(TaxonBase taxonBase, boolean excludeMisappliedNames) {
353
		if (taxonBase == null){
354
		    return false;
355
		}
356
	    //handle accepted taxa
357
		if (taxonBase.isInstanceOf(Taxon.class)){
358
			Taxon taxon = CdmBase.deproxy(taxonBase, Taxon.class);
359
			if (! taxon.isPublish()){
360
				taxon = null;
361
				return false;
362
			}
363
			for (Marker marker : taxon.getMarkers()){
364
				//probably not needed anymore after #1780 was fixed, also #4046 interesting
365
				if (marker.getValue() == false && marker.getMarkerType().equals(MarkerType.PUBLISH())){
366
					taxon = null;
367
					return false;
368
				//probably not needed any more after #2786 was fixed
369
				}else if (marker.getValue() == true && marker.getMarkerType().getUuid().equals(BerlinModelTransformer.uuidMisappliedCommonName)){
370
					logger.warn("Misapplied common name still exists");
371
					taxon = null;
372
					return false;
373
				}
374

    
375
			}
376

    
377
			//handle PESI accepted taxa
378
			if (! taxon.isMisapplication()){
379
				for (Marker marker : taxon.getMarkers()){
380
					if (marker.getValue() == false && marker.getMarkerType().equals(MarkerType.PUBLISH())){
381
						taxon = null;
382
						return false;
383
					}
384
				}
385
				return true;
386
			//handle misapplied names
387
			}else{
388
				if (excludeMisappliedNames){
389
					taxon = null;
390
					return false;
391
				}
392
				for (Marker marker : taxon.getMarkers()){
393
					//probably not needed any more after #2786 was fixed
394
					if (marker.getValue() == true && marker.getMarkerType().getUuid().equals(BerlinModelTransformer.uuidMisappliedCommonName)){
395
						logger.warn("Misapplied common name still exists");
396
						taxon = null;
397
						return false;
398
					}
399
				}
400
				for (TaxonRelationship taxRel : taxon.getRelationsFromThisTaxon()){
401
					if (taxRel.getType().equals(TaxonRelationshipType.MISAPPLIED_NAME_FOR())){
402
//						logger.warn(taxRel.getUuid() + "; " + taxRel.getToTaxon().getUuid() + " + " + taxRel.getToTaxon().getTitleCache());
403
						if (isPesiTaxon(taxRel.getToTaxon(), true)){
404
							taxon = null;
405
							return true;
406
						}
407
					}
408
				}
409
				if (logger.isDebugEnabled()){ logger.debug("Misapplied name has no accepted PESI taxon: " +  taxon.getUuid() + ", (" +  taxon.getTitleCache() + ")");}
410
				taxon = null;
411
				return false;
412
			}
413
		//handle synonyms
414
		}else if (taxonBase.isInstanceOf(Synonym.class)){
415
			Synonym synonym = CdmBase.deproxy(taxonBase, Synonym.class);
416
			boolean hasAcceptedPesiTaxon = false;
417
			hasAcceptedPesiTaxon = isPesiTaxon(synonym.getAcceptedTaxon());
418

    
419
			if (!hasAcceptedPesiTaxon) {if (logger.isDebugEnabled()){logger.debug("Synonym has no accepted PESI taxon: " +  synonym.getUuid() + ", (" +  synonym.getTitleCache() + ")");}}
420
			synonym = null;
421
			return hasAcceptedPesiTaxon;
422
		}else {
423
			throw new RuntimeException("Unknown taxon base type: " + taxonBase.getClass());
424
		}
425
	}
426

    
427
	@Override
428
    protected Object getDbIdCdmWithExceptions(CdmBase cdmBase, PesiExportState state) {
429
		if (cdmBase.isInstanceOf(TaxonName.class)){
430
			return ( cdmBase.getId() + state.getConfig().getNameIdStart() );
431
		}if (isAdditionalSource(cdmBase) ){
432
			return ( cdmBase.getId() + 2 * state.getConfig().getNameIdStart() );  //make it a separate variable if conflicts occur.
433
		}else{
434
			return super.getDbIdCdmWithExceptions(cdmBase, state);
435
		}
436
	}
437

    
438

    
439

    
440
	private boolean isAdditionalSource(CdmBase cdmBase) {
441
		if (cdmBase.isInstanceOf(TextData.class)){
442
			TextData textData = CdmBase.deproxy(cdmBase, TextData.class);
443
			if (textData.getFeature().equals(Feature.ADDITIONAL_PUBLICATION()) ||
444
					textData.getFeature().equals(Feature.CITATION())){
445
				return true;
446
			}
447
		}
448
		return false;
449
	}
450

    
451

    
452
	protected MarkerType getUuidMarkerType(UUID uuid, PesiExportState state){
453
		if (uuid == null){
454
			uuid = UUID.randomUUID();
455
		}
456

    
457
		MarkerType markerType = state.getMarkerType(uuid);
458
			if (markerType == null){
459
				if (uuid.equals(PesiTransformer.uuidMarkerGuidIsMissing)){
460
					markerType = MarkerType.NewInstance("Uuid is Missing", "Uuid is missing", null);
461
					markerType.setUuid(uuid);
462
				} else if (uuid.equals(PesiTransformer.uuidMarkerTypeHasNoLastAction)){
463
					markerType = MarkerType.NewInstance("Has no last Action", "Has no last action", null);
464
					markerType.setUuid(uuid);
465
				}
466
			}
467

    
468
			state.putMarkerType(markerType);
469
			return markerType;
470
		}
471

    
472

    
473

    
474
	protected static TaxonNameDefaultCacheStrategy getCacheStrategy(TaxonName taxonName) {
475
	    TaxonNameDefaultCacheStrategy cacheStrategy;
476
		if (taxonName.isZoological()){
477
			cacheStrategy = zooNameStrategy;
478
		}else if (taxonName.isBotanical()) {
479
			cacheStrategy = botanicalNameStrategy;
480
		}else{
481
			logger.error("Unhandled taxon name type. Can't define strategy class");
482
			cacheStrategy = botanicalNameStrategy;
483
		}
484
		return cacheStrategy;
485
	}
486

    
487

    
488

    
489

    
490
	/**
491
	 * Checks whether a given taxon is a misapplied name.
492
	 * @param taxon The {@link TaxonBase Taxon}.
493
	 * @return Whether the given TaxonName is a misapplied name or not.
494
	 */
495
	protected static boolean isMisappliedName(TaxonBase<?> taxon) {
496
		return getAcceptedTaxonForMisappliedName(taxon) != null;
497

    
498
	}
499

    
500

    
501
	/**
502
	 * Returns the first accepted taxon for this misapplied name.
503
	 * If this misapplied name is not a misapplied name, <code>null</code> is returned.
504
	 * @param taxon The {@link TaxonBase Taxon}.
505
	 */
506
	private static Taxon getAcceptedTaxonForMisappliedName(TaxonBase<?> taxon) {
507
		if (! taxon.isInstanceOf(Taxon.class)){
508
			return null;
509
		}
510
		Set<TaxonRelationship> taxonRelations = CdmBase.deproxy(taxon, Taxon.class).getRelationsFromThisTaxon();
511
		for (TaxonRelationship taxonRelationship : taxonRelations) {
512
			TaxonRelationshipType taxonRelationshipType = taxonRelationship.getType();
513
			if (taxonRelationshipType.equals(TaxonRelationshipType.MISAPPLIED_NAME_FOR())) {
514
				return taxonRelationship.getToTaxon();
515
			}
516
		}
517
		return null;
518
	}
519

    
520

    
521

    
522

    
523

    
524

    
525

    
526

    
527

    
528
//	protected List<TaxonBase> getNextDescriptionPartition(Class<? extends DescriptionElementBase> clazz,int limit, int partitionCount) {
529
//		List<DescriptionElementBase> list = getDescriptionService().listDescriptionElements(null, null, pageSize, pageNumber, propPath);
530
//
531
//		Iterator<TaxonBase> it = list.iterator();
532
//		while (it.hasNext()){
533
//			TaxonBase<?> taxonBase = it.next();
534
//			if (! isPesiTaxon(taxonBase)){
535
//				it.remove();
536
//			}
537
//		}
538
//		return list;
539
//	}
540

    
541
}
(4-4/12)