Project

General

Profile

Download (17.3 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.taxon.Synonym;
37
import eu.etaxonomy.cdm.model.taxon.Taxon;
38
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
39
import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;
40
import eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType;
41
import eu.etaxonomy.cdm.persistence.query.OrderHint;
42
import eu.etaxonomy.cdm.strategy.cache.name.NonViralNameDefaultCacheStrategy;
43
import eu.etaxonomy.cdm.strategy.cache.name.ZooNameNoMarkerCacheStrategy;
44

    
45
/**
46
 * @author e.-m.lee
47
 * @date 12.02.2010
48
 *
49
 */
50
public abstract class PesiExportBase extends DbExportBase<PesiExportConfigurator, PesiExportState, PesiTransformer> {
51
	private static final Logger logger = Logger.getLogger(PesiExportBase.class);
52

    
53
	protected static final boolean IS_CACHE = true;
54

    
55
	private static Set<NameRelationshipType> excludedRelTypes = new HashSet<NameRelationshipType>();
56

    
57
	private static NonViralNameDefaultCacheStrategy<?> zooNameStrategy = ZooNameNoMarkerCacheStrategy.NewInstance();
58
	private static NonViralNameDefaultCacheStrategy<?> botanicalNameStrategy = BotanicNameDefaultCacheStrategy.NewInstance();
59

    
60
	public PesiExportBase() {
61
		super();
62
	}
63

    
64

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

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

    
71

    
72

    
73
		if (list.isEmpty()){
74
			return null;
75
		}
76

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

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

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

    
108

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

    
121
		}
122
		return false;
123
	}
124

    
125

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

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

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

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

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

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

    
205
	}
206

    
207
	private boolean isPesiName(TaxonNameBase<?,?> name) {
208
		return hasPesiTaxon(name) || isPurePesiName(name);
209
	}
210

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

    
232
	}
233

    
234

    
235

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

    
249
		//from names
250
		for (NameRelationship rel :taxonName.getRelationsFromThisName()){
251
			TaxonNameBase<?,?> relatedName = rel.getToName();
252
			if (hasPesiTaxon(relatedName)){
253
				return true;
254
			}
255
		}
256

    
257
		//excluded relationships on to-side
258
		initExcludedRelTypes();
259

    
260
		//to names
261
		for (NameRelationship rel :taxonName.getRelationsToThisName()){
262
			//exclude certain types
263
			if (excludedRelTypes.contains(rel.getType())){
264
				continue;
265
			}
266
			TaxonNameBase<?,?> relatedName = rel.getFromName();
267
			if (hasPesiTaxon(relatedName)){
268
				return true;
269
			}
270
		}
271

    
272
		//include hybrid parents, but no childs
273
		NonViralName nvn = CdmBase.deproxy(taxonName, NonViralName.class);
274
		for (HybridRelationship rel : (Set<HybridRelationship>)nvn.getHybridParentRelations()){
275
			INonViralName child = rel.getHybridName();
276
			if (hasPesiTaxon(child)){
277
				return true;
278
			}
279
		}
280

    
281
		return false;
282
	}
283

    
284

    
285
	private void initExcludedRelTypes() {
286
		if (excludedRelTypes.isEmpty()){
287
			excludedRelTypes.add(NameRelationshipType.BASIONYM());
288
			excludedRelTypes.add(NameRelationshipType.REPLACED_SYNONYM());
289
			excludedRelTypes.add(NameRelationshipType.ORTHOGRAPHIC_VARIANT());
290
		}
291
	}
292

    
293

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

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

    
329

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

    
339

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

    
372
			}
373

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

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

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

    
435

    
436

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

    
448

    
449
	protected MarkerType getUuidMarkerType(UUID uuid, PesiExportState state){
450
		if (uuid == null){
451
			uuid = UUID.randomUUID();
452
		}
453

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

    
465
			state.putMarkerType(markerType);
466
			return markerType;
467
		}
468

    
469

    
470

    
471
	protected static NonViralNameDefaultCacheStrategy getCacheStrategy(TaxonNameBase<?, ?> taxonName) {
472
		NonViralNameDefaultCacheStrategy cacheStrategy;
473
		if (taxonName.isInstanceOf(ZoologicalName.class)){
474
			cacheStrategy = zooNameStrategy;
475
		}else if (taxonName.isInstanceOf(BotanicalName.class)) {
476
			cacheStrategy = botanicalNameStrategy;
477
		}else{
478
			logger.error("Unhandled taxon name type. Can't define strategy class");
479
			cacheStrategy = botanicalNameStrategy;
480
		}
481
		return cacheStrategy;
482
	}
483

    
484

    
485

    
486

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

    
495
	}
496

    
497

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

    
517

    
518

    
519

    
520

    
521

    
522

    
523

    
524

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

    
538
}
(4-4/12)