Project

General

Profile

Download (26.3 KB) Statistics
| Branch: | Revision:
1
/**
2
* Copyright (C) 2007 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

    
10
package eu.etaxonomy.cdm.io.berlinModel.in;
11

    
12
import java.net.URI;
13
import java.sql.ResultSet;
14
import java.sql.SQLException;
15
import java.util.ArrayList;
16
import java.util.HashMap;
17
import java.util.HashSet;
18
import java.util.List;
19
import java.util.Map;
20
import java.util.Set;
21
import java.util.UUID;
22

    
23
import org.apache.commons.lang.StringUtils;
24
import org.apache.log4j.Logger;
25
import org.springframework.stereotype.Component;
26
import org.springframework.transaction.TransactionStatus;
27

    
28
import eu.etaxonomy.cdm.common.CdmUtils;
29
import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
30
import eu.etaxonomy.cdm.io.berlinModel.BerlinModelTransformer;
31
import eu.etaxonomy.cdm.io.berlinModel.in.validation.BerlinModelOccurrenceImportValidator;
32
import eu.etaxonomy.cdm.io.common.CdmImportBase;
33
import eu.etaxonomy.cdm.io.common.IOValidator;
34
import eu.etaxonomy.cdm.io.common.ResultSetPartitioner;
35
import eu.etaxonomy.cdm.io.common.Source;
36
import eu.etaxonomy.cdm.io.common.TdwgAreaProvider;
37
import eu.etaxonomy.cdm.model.common.Annotation;
38
import eu.etaxonomy.cdm.model.common.AnnotationType;
39
import eu.etaxonomy.cdm.model.common.CdmBase;
40
import eu.etaxonomy.cdm.model.common.ExtensionType;
41
import eu.etaxonomy.cdm.model.common.Language;
42
import eu.etaxonomy.cdm.model.common.Marker;
43
import eu.etaxonomy.cdm.model.common.MarkerType;
44
import eu.etaxonomy.cdm.model.common.OriginalSourceType;
45
import eu.etaxonomy.cdm.model.common.TermType;
46
import eu.etaxonomy.cdm.model.common.TermVocabulary;
47
import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
48
import eu.etaxonomy.cdm.model.description.Distribution;
49
import eu.etaxonomy.cdm.model.description.PresenceAbsenceTerm;
50
import eu.etaxonomy.cdm.model.description.TaxonDescription;
51
import eu.etaxonomy.cdm.model.location.NamedArea;
52
import eu.etaxonomy.cdm.model.location.NamedAreaLevel;
53
import eu.etaxonomy.cdm.model.location.NamedAreaType;
54
import eu.etaxonomy.cdm.model.reference.Reference;
55
import eu.etaxonomy.cdm.model.taxon.Taxon;
56
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
57
import eu.etaxonomy.cdm.strategy.exceptions.UnknownCdmTypeException;
58

    
59

    
60
/**
61
 * @author a.mueller
62
 * @created 20.03.2008
63
 */
64
@Component
65
public class BerlinModelOccurrenceImport  extends BerlinModelImportBase {
66
	private static final Logger logger = Logger.getLogger(BerlinModelOccurrenceImport.class);
67

    
68
	public static final String NAMESPACE = "Occurrence";
69
	private static final String EM_AREA_NAMESPACE = "emArea";
70

    
71
	private static int modCount = 5000;
72
	private static final String pluralString = "occurrences";
73
	private static final String dbTableName = "emOccurrence";  //??
74

    
75
	public BerlinModelOccurrenceImport(){
76
		super(dbTableName, pluralString);
77
	}
78

    
79
	@Override
80
	protected String getIdQuery(BerlinModelImportState state) {
81
		String result = " SELECT occurrenceId FROM " + getTableName();
82
		if (StringUtils.isNotBlank(state.getConfig().getOccurrenceFilter())){
83
			result += " WHERE " +  state.getConfig().getOccurrenceFilter();
84
		}
85
		return result;
86
	}
87

    
88
	@Override
89
	protected String getRecordQuery(BerlinModelImportConfigurator config) {
90
			String emCode = config.isIncludesAreaEmCode()? ", emArea.EMCode" : "";
91
			String strQuery =   //DISTINCT because otherwise emOccurrenceSource creates multiple records for a single distribution
92
            " SELECT DISTINCT PTaxon.RIdentifier AS taxonId, emOccurrence.OccurrenceId, emOccurrence.Native, emOccurrence.Introduced, " +
93
            		" emOccurrence.Cultivated, emOccurrence.Notes occNotes, " +
94
            		" emOccurSumCat.emOccurSumCatId, emOccurSumCat.Short, emOccurSumCat.Description, " +
95
                	" emOccurSumCat.OutputCode, emArea.AreaId, emArea.TDWGCode " + emCode +
96
                " FROM emOccurrence INNER JOIN " +
97
                	" emArea ON emOccurrence.AreaFk = emArea.AreaId INNER JOIN " +
98
                	" PTaxon ON emOccurrence.PTNameFk = PTaxon.PTNameFk AND emOccurrence.PTRefFk = PTaxon.PTRefFk LEFT OUTER JOIN " +
99
                	" emOccurSumCat ON emOccurrence.SummaryStatus = emOccurSumCat.emOccurSumCatId LEFT OUTER JOIN " +
100
                	" emOccurrenceSource ON emOccurrence.OccurrenceId = emOccurrenceSource.OccurrenceFk " +
101
            " WHERE (emOccurrence.OccurrenceId IN (" + ID_LIST_TOKEN + ")  )" +
102
                " ORDER BY PTaxon.RIdentifier";
103
		return strQuery;
104
	}
105

    
106
	private Map<Integer, NamedArea> euroMedAreas = new HashMap<Integer, NamedArea>();
107

    
108

    
109
	@Override
110
	public void doInvoke(BerlinModelImportState state) {
111
		if (state.getConfig().isUseEmAreaVocabulary()){
112
			try {
113
				createEuroMedAreas(state);
114
			} catch (Exception e) {
115
				logger.error("Exception occurred when trying to create euroMed Areas");
116
				e.printStackTrace();
117
				state.setSuccess(false);
118
			}
119
		}
120
		super.doInvoke(state);
121
		//reset
122
		euroMedAreas = new HashMap<Integer, NamedArea>();
123
	}
124

    
125
	private TermVocabulary<NamedArea> createEuroMedAreas(BerlinModelImportState state) throws SQLException {
126
		logger.warn("Start creating E+M areas");
127
		Source source = state.getConfig().getSource();
128
		Reference<?> sourceReference = state.getConfig().getSourceReference();
129

    
130
		TransactionStatus txStatus = this.startTransaction();
131

    
132
		sourceReference = getSourceReference(sourceReference);
133

    
134
		TermVocabulary<NamedArea> euroMedAreas = makeEmptyEuroMedVocabulary();
135

    
136
		MarkerType eurMarkerType = getMarkerType(state, BerlinModelTransformer.uuidEurArea, "eur", "eur Area", "eur");
137
		MarkerType euroMedAreaMarkerType = getMarkerType(state, BerlinModelTransformer.uuidEurMedArea, "EuroMedArea", "EuroMedArea", "EuroMedArea");
138
		ExtensionType isoCodeExtType = getExtensionType(state, BerlinModelTransformer.uuidIsoCode, "IsoCode", "IsoCode", "iso");
139
		ExtensionType tdwgCodeExtType = getExtensionType(state, BerlinModelTransformer.uuidTdwgAreaCode, "TDWG code", "TDWG Area code", "tdwg");
140
		ExtensionType mclCodeExtType = getExtensionType(state, BerlinModelTransformer.uuidMclCode, "MCL code", "MedCheckList code", "mcl");
141
		NamedAreaLevel areaLevelTop = getNamedAreaLevel(state, BerlinModelTransformer.uuidEuroMedAreaLevelTop, "Euro+Med top area level", "Euro+Med top area level. This level is only to be used for the area representing the complete Euro+Med area", "e+m top", null);
142
		NamedAreaLevel areaLevelEm1 = getNamedAreaLevel(state, BerlinModelTransformer.uuidEuroMedAreaLevelFirst, "Euro+Med 1. area level", "Euro+Med 1. area level", "e+m 1.", null);
143
		NamedAreaLevel areaLevelEm2 = getNamedAreaLevel(state, BerlinModelTransformer.uuidEuroMedAreaLevelSecond, "Euro+Med 2. area level", "Euro+Med 2. area level", "Euro+Med 1. area level", null);
144

    
145

    
146
		String sql = "SELECT * , CASE WHEN EMCode = 'EM' THEN 'a' ELSE 'b' END as isEM " +
147
				" FROM emArea " +
148
				" ORDER BY isEM, EMCode";
149
		ResultSet rs = source.getResultSet(sql);
150

    
151
		NamedArea euroMedArea = null;
152
		NamedArea lastLevel1Area = null;
153

    
154
		//euroMedArea (EMCode = 'EM')
155
		rs.next();
156
		euroMedArea = makeSingleEuroMedArea(rs, eurMarkerType, euroMedAreaMarkerType, isoCodeExtType, tdwgCodeExtType, mclCodeExtType,
157
				areaLevelTop, areaLevelEm1 , areaLevelEm2, sourceReference, euroMedArea, lastLevel1Area);
158
		euroMedAreas.addTerm(euroMedArea);
159

    
160
		//all other areas
161
		while (rs.next()){
162
			NamedArea newArea = makeSingleEuroMedArea(rs, eurMarkerType, euroMedAreaMarkerType,
163
					isoCodeExtType, tdwgCodeExtType, mclCodeExtType,
164
					areaLevelTop, areaLevelEm1 , areaLevelEm2, sourceReference, euroMedArea, lastLevel1Area);
165
			if (newArea != null){
166
    			euroMedAreas.addTerm(newArea);
167
    			if (newArea.getPartOf().equals(euroMedArea)){
168
    				lastLevel1Area = newArea;
169
    			}
170
			}
171
		}
172
		emAreaFinetuning(euroMedAreas, areaLevelEm2);
173

    
174
		markAreasAsHidden(state, euroMedAreas);
175

    
176
	    getVocabularyService().saveOrUpdate(euroMedAreas);
177

    
178
		try {
179
            commitTransaction(txStatus);
180
        } catch (Exception e) {
181
             e.printStackTrace();
182
             logger.error("An exception occurred when trying to commit E+M Areas");
183
        }
184
		logger.warn("Created E+M areas");
185

    
186
		return euroMedAreas;
187
	}
188

    
189
	/**
190
     * @param areaLevelEm2
191
	 * @param euroMedAreas2
192
     */
193
    private void emAreaFinetuning(TermVocabulary<NamedArea> euroMedAreas, NamedAreaLevel areaLevelEm2) {
194
        //CZ
195
        NamedArea oldArea = euroMedAreas.getTermByIdInvocabulary("Cz");
196
        makeSubterm(oldArea, euroMedAreas.getTermByIdInvocabulary("Cs"), areaLevelEm2);
197
        makeSubterm(oldArea, euroMedAreas.getTermByIdInvocabulary("Sk"), areaLevelEm2);
198

    
199
        //Ju
200
        oldArea = euroMedAreas.getTermByIdInvocabulary("Ju");
201
        makeSubterm(oldArea, euroMedAreas.getTermByIdInvocabulary("BH"), areaLevelEm2);
202
        makeSubterm(oldArea, euroMedAreas.getTermByIdInvocabulary("Cg"), areaLevelEm2);
203
        makeSubterm(oldArea, euroMedAreas.getTermByIdInvocabulary("Ct"), areaLevelEm2);
204
        makeSubterm(oldArea, euroMedAreas.getTermByIdInvocabulary("Mk"), areaLevelEm2);
205
        makeSubterm(oldArea, euroMedAreas.getTermByIdInvocabulary("Sl"), areaLevelEm2);
206
        makeSubterm(oldArea, euroMedAreas.getTermByIdInvocabulary("Sr"), areaLevelEm2);
207

    
208
        //IJ
209
        oldArea = euroMedAreas.getTermByIdInvocabulary("IJ");
210
        makeSubterm(oldArea, euroMedAreas.getTermByIdInvocabulary("Ir"), areaLevelEm2);
211
        makeSubterm(oldArea, euroMedAreas.getTermByIdInvocabulary("Jo"), areaLevelEm2);
212

    
213
        //LS
214
        oldArea = euroMedAreas.getTermByIdInvocabulary("LS");
215
        makeSubterm(oldArea, euroMedAreas.getTermByIdInvocabulary("Le"), areaLevelEm2);
216
        makeSubterm(oldArea, euroMedAreas.getTermByIdInvocabulary("Sy"), areaLevelEm2);
217

    
218
    }
219

    
220
    //5.Mark areas to be hidden #3979 .5
221
    private void markAreasAsHidden(BerlinModelImportState state, TermVocabulary<NamedArea> euroMedAreasVoc) {
222

    
223
        try {
224

    
225
            @SuppressWarnings("unchecked")
226
            TermVocabulary<MarkerType> vocUserDefinedMarkerTypes = getVocabularyService().find(CdmImportBase.uuidUserDefinedMarkerTypeVocabulary);
227
            if (vocUserDefinedMarkerTypes == null){
228
                String message = "Marker type vocabulary could not be found. Hidden areas not added.";
229
                logger.error(message);
230
                System.out.println(message);
231
            }
232
            MarkerType hiddenAreaMarkerType = getMarkerType(state, BerlinModelTransformer.uuidHiddenArea, "Hidden Area","Used to hide distributions for the named areas in publications", null, vocUserDefinedMarkerTypes);
233

    
234
            //Add hidden area marker to Rs(C) and Rs(N)
235
            hideArea(euroMedAreasVoc, hiddenAreaMarkerType, BerlinModelTransformer.uuidRs);
236
            hideArea(euroMedAreasVoc, hiddenAreaMarkerType, BerlinModelTransformer.uuidRs_B);
237
            hideArea(euroMedAreasVoc, hiddenAreaMarkerType, BerlinModelTransformer.uuidRs_C);
238
            hideArea(euroMedAreasVoc, hiddenAreaMarkerType, BerlinModelTransformer.uuidRs_E);
239
            hideArea(euroMedAreasVoc, hiddenAreaMarkerType, BerlinModelTransformer.uuidRs_N);
240
            hideArea(euroMedAreasVoc, hiddenAreaMarkerType, BerlinModelTransformer.uuidRs_K);
241
            hideArea(euroMedAreasVoc, hiddenAreaMarkerType, BerlinModelTransformer.uuidRs_W);
242
        } catch (Exception e) {
243
            e.printStackTrace();
244
            logger.error("Exception in markAreasAsHidden: " + e.getMessage());
245
        }
246

    
247
    }
248

    
249
    private void hideArea(TermVocabulary<NamedArea> euroMedAreasVoc, MarkerType hiddenAreaMarkerType, UUID areaUuid) {
250
        for (NamedArea namedArea : euroMedAreasVoc){
251
            if (namedArea.getUuid().equals(areaUuid)){
252
                namedArea.addMarker(Marker.NewInstance(hiddenAreaMarkerType, true));
253
                return;
254
            }
255
        }
256
    }
257

    
258
    /**
259
     * @param oldArea
260
     * @param namedArea
261
     * @param areaLevelEm2
262
     */
263
    private void makeSubterm(NamedArea oldArea, NamedArea namedArea, NamedAreaLevel areaLevelEm2) {
264
        namedArea.setLevel(areaLevelEm2);
265
        namedArea.setPartOf(oldArea);
266
    }
267

    
268
    /**
269
	 * @param sourceReference
270
	 * @return
271
	 */
272
	private Reference<?> getSourceReference(Reference<?> sourceReference) {
273
		Reference<?> persistentSourceReference = getReferenceService().find(sourceReference.getUuid());  //just to be sure
274
		if (persistentSourceReference != null){
275
			sourceReference = persistentSourceReference;
276
		}
277
		return sourceReference;
278
	}
279

    
280
	/**
281
	 * @param eurMarkerType
282
	 * @param euroMedAreaMarkerType
283
	 * @param isoCodeExtType
284
	 * @param tdwgCodeExtType
285
	 * @param mclCodeExtType
286
	 * @param rs
287
	 * @param areaLevelEm2
288
	 * @param areaLevelEm1
289
	 * @param areaLevelTop
290
	 * @throws SQLException
291
	 */
292
	private NamedArea makeSingleEuroMedArea(ResultSet rs, MarkerType eurMarkerType,
293
			MarkerType euroMedAreaMarkerType, ExtensionType isoCodeExtType,
294
			ExtensionType tdwgCodeExtType, ExtensionType mclCodeExtType,
295
			NamedAreaLevel areaLevelTop, NamedAreaLevel areaLevelEm1, NamedAreaLevel areaLevelEm2,
296
			Reference<?> sourceReference, NamedArea euroMedArea, NamedArea level1Area) throws SQLException {
297
		Integer areaId = rs.getInt("AreaId");
298
		String emCode = nullSafeTrim(rs.getString("EMCode"));
299
		String isoCode = nullSafeTrim(rs.getString("ISOCode"));
300
		String tdwgCode = nullSafeTrim(rs.getString("TDWGCode"));
301
		String unit = nullSafeTrim(rs.getString("Unit"));
302
//				      ,[Status]
303
//				      ,[OutputOrder]
304
		boolean eurMarker = rs.getBoolean("eur");
305
		boolean euroMedAreaMarker = rs.getBoolean("EuroMedArea");
306
		String notes = nullSafeTrim(rs.getString("Notes"));
307
		String mclCode = nullSafeTrim(rs.getString("MCLCode"));
308
		String geoSearch = nullSafeTrim(rs.getString("NameForGeoSearch"));
309

    
310

    
311

    
312
		if (isBlank(emCode)){
313
			emCode = unit;
314
		}
315

    
316
		//uuid
317
		UUID uuid = BerlinModelTransformer.getEMAreaUuid(emCode);
318
		NamedArea area = (NamedArea)getTermService().find(uuid);
319
		if (area == null){
320
			//label
321
			area = NamedArea.NewInstance(geoSearch, unit, emCode);
322
			if (uuid != null){
323
				area.setUuid(uuid);
324
			}else{
325
			    if (areaId == 211 || areaId == 213){  //Additional Azores and Canary Is. area are merged into primary area, see also area.addSource part below
326
			        return null;
327
			    }
328
				logger.warn("Uuid for emCode could not be defined: " + emCode);
329
			}
330
		}
331

    
332

    
333
		//code
334
		area.setIdInVocabulary(emCode);
335
		//notes
336
		if (StringUtils.isNotEmpty(notes)){
337
			area.addAnnotation(Annotation.NewInstance(notes, AnnotationType.EDITORIAL(), Language.DEFAULT()));
338
		}
339
		//markers
340
		area.addMarker(Marker.NewInstance(eurMarkerType, eurMarker));
341
		area.addMarker(Marker.NewInstance(euroMedAreaMarkerType, euroMedAreaMarker));
342

    
343
		//extensions
344
		if (isNotBlank(isoCode)){
345
			area.addExtension(isoCode, isoCodeExtType);
346
		}
347
		if (isNotBlank(tdwgCode)){
348
			area.addExtension(tdwgCode, tdwgCodeExtType);
349
		}
350
		if (isNotBlank(mclCode)){
351
			area.addExtension(mclCode, mclCodeExtType);
352
		}
353

    
354
		//type
355
		area.setType(NamedAreaType.ADMINISTRATION_AREA());
356

    
357
		//source
358
		area.addSource(OriginalSourceType.Import, String.valueOf(areaId), EM_AREA_NAMESPACE, sourceReference, null);
359
		//add duplicate area ids for canary
360
		if (areaId == 624){ //Canary Is.
361
		    area.addSource(OriginalSourceType.Import, String.valueOf(213), EM_AREA_NAMESPACE, sourceReference, null);
362
		}
363
		if (areaId == 210){//Azores
364
            area.addSource(OriginalSourceType.Import, String.valueOf(211), EM_AREA_NAMESPACE, sourceReference, null);
365
        }
366

    
367
		//parent
368
		if (euroMedArea != null){
369
			if (emCode.contains("(")){
370
				area.setPartOf(level1Area);
371
				area.setLevel(areaLevelEm2);
372
			}else{
373
				area.setPartOf(euroMedArea);
374
				area.setLevel(areaLevelEm1);
375
			}
376
		}else{
377
			area.setLevel(areaLevelTop);
378
		}
379
		this.euroMedAreas.put(areaId, area);
380

    
381
		//save
382
		getTermService().saveOrUpdate(area);
383

    
384
		return area;
385
	}
386

    
387
	private String nullSafeTrim(String string) {
388
		if (string == null){
389
			return null;
390
		}else{
391
			return string.trim();
392
		}
393
	}
394

    
395
	/**
396
	 *
397
	 */
398
	private TermVocabulary<NamedArea> makeEmptyEuroMedVocabulary() {
399
		TermType type = TermType.NamedArea;
400
		String description = "Euro+Med area vocabulary";
401
		String label = "E+M areas";
402
		String abbrev = null;
403
		URI termSourceUri = null;
404
		TermVocabulary<NamedArea> result = TermVocabulary.NewInstance(type, description, label, abbrev, termSourceUri);
405

    
406
		result.setUuid(BerlinModelTransformer.uuidVocEuroMedAreas);
407
		getVocabularyService().save(result);
408
		return result;
409
	}
410

    
411
	@Override
412
	public boolean doPartition(ResultSetPartitioner partitioner, BerlinModelImportState state) {
413
		boolean success = true;
414
		Set<TaxonBase> taxaToSave = new HashSet<TaxonBase>();
415

    
416
		Map<String, TaxonBase<?>> taxonMap = partitioner.getObjectMap(BerlinModelTaxonImport.NAMESPACE);
417

    
418
		ResultSet rs = partitioner.getResultSet();
419

    
420
		try {
421
			//map to store the mapping of duplicate berlin model occurrences to their real distributions
422
			//duplicated may occur due to area mappings from BM areas to TDWG areas
423
			Map<Integer, String> duplicateMap = new HashMap<Integer, String>();
424
			int oldTaxonId = -1;
425
			TaxonDescription oldDescription = null;
426
			int i = 0;
427
			int countDescriptions = 0;
428
			int countDistributions = 0;
429
			int countDuplicates = 0;
430
			//for each reference
431
            while (rs.next()){
432

    
433
            	if ((i++ % modCount) == 0 && i!= 1 ){ logger.info("Facts handled: " + (i-1));}
434

    
435
                int occurrenceId = rs.getInt("OccurrenceId");
436
                int newTaxonId = rs.getInt("taxonId");
437
                String notes = nullSafeTrim(rs.getString("occNotes"));
438

    
439
                Integer emStatusId = nullSafeInt(rs, "emOccurSumCatId");
440

    
441
                try {
442
                	//status
443
                	PresenceAbsenceTerm status = null;
444
                	String alternativeStatusString = null;
445
					if (emStatusId != null){
446
						status = BerlinModelTransformer.occStatus2PresenceAbsence(emStatusId);
447
					}else{
448
						String[] stringArray = new String[]{rs.getString("Native"), rs.getString("Introduced"), rs.getString("Cultivated")};
449
						alternativeStatusString = CdmUtils.concat(",", stringArray);
450
					}
451

    
452
					Reference<?> sourceRef = state.getTransactionalSourceReference();
453

    
454
					List<NamedArea> areas = makeAreaList(state, rs,	occurrenceId);
455

    
456
                    //create description(elements)
457
                    TaxonDescription taxonDescription = getTaxonDescription(newTaxonId, oldTaxonId, oldDescription, taxonMap, occurrenceId, sourceRef);
458
                    for (NamedArea area : areas){
459
                    	Distribution distribution = Distribution.NewInstance(area, status);
460
                        if (status == null){
461
                        	AnnotationType annotationType = AnnotationType.EDITORIAL();
462
                        	Annotation annotation = Annotation.NewInstance(alternativeStatusString, annotationType, null);
463
                        	distribution.addAnnotation(annotation);
464
                        	distribution.addMarker(Marker.NewInstance(MarkerType.PUBLISH(), false));
465
                        }
466
//                      distribution.setCitation(sourceRef);
467
                        if (taxonDescription != null) {
468
                        	Distribution duplicate = checkIsNoDuplicate(taxonDescription, distribution, duplicateMap , occurrenceId);
469
                            if (duplicate == null){
470
                            	taxonDescription.addElement(distribution);
471
	                            distribution.addImportSource(String.valueOf(occurrenceId), NAMESPACE, state.getTransactionalSourceReference(), null);
472
	                        	countDistributions++;
473
	                            if (taxonDescription != oldDescription){
474
	                            	taxaToSave.add(taxonDescription.getTaxon());
475
	                                oldDescription = taxonDescription;
476
	                                countDescriptions++;
477
	                            }
478
                            }else{
479
                            	countDuplicates++;
480
                            	duplicate.addImportSource(String.valueOf(occurrenceId), NAMESPACE, state.getTransactionalSourceReference(), null);
481
                            	logger.info("Distribution is duplicate");	                           }
482
                        } else {
483
                        	logger.warn("Distribution " + area.getLabel() + " ignored. OccurrenceId = " + occurrenceId);
484
	                       	success = false;
485
	                    }
486
                        //notes
487
                        if (isNotBlank(notes)){
488
                        	Annotation annotation = Annotation.NewInstance(notes, Language.DEFAULT());
489
                        	distribution.addAnnotation(annotation);
490
                        }
491
                    }
492
                } catch (UnknownCdmTypeException e) {
493
                     logger.error("Unknown presenceAbsence status id: " + emStatusId);
494
                	e.printStackTrace();
495
                     success = false;
496
                }
497
            }
498

    
499
            logger.info("Distributions: " + countDistributions + ", Descriptions: " + countDescriptions );
500
			logger.info("Duplicate occurrences: "  + (countDuplicates));
501

    
502
			logger.info("Taxa to save: " + taxaToSave.size());
503
			getTaxonService().save(taxaToSave);
504

    
505
			return success;
506
		} catch (SQLException e) {
507
			logger.error("SQLException:" +  e);
508
			return false;
509
		}
510
	}
511

    
512
	/**
513
	 * @param state
514
	 * @param rs
515
	 * @param occurrenceId
516
	 * @param tdwgCodeString
517
	 * @param emCodeString
518
	 * @return
519
	 * @throws SQLException
520
	 */
521
	//Create area list
522
	private List<NamedArea> makeAreaList(BerlinModelImportState state, ResultSet rs, int occurrenceId) throws SQLException {
523
		List<NamedArea> areas = new ArrayList<NamedArea>();
524

    
525
		if (state.getConfig().isUseEmAreaVocabulary()){
526
			Integer areaId = rs.getInt("AreaId");
527
	        NamedArea area = this.euroMedAreas.get(areaId);
528
			areas.add(area);
529
		}else{
530
	        String tdwgCodeString = rs.getString("TDWGCode");
531
	        String emCodeString = state.getConfig().isIncludesAreaEmCode() ? rs.getString("EMCode") : null;
532

    
533
			if (tdwgCodeString != null){
534

    
535
				String[] tdwgCodes = new String[]{tdwgCodeString};
536
				if (state.getConfig().isSplitTdwgCodes()){
537
					tdwgCodes = tdwgCodeString.split(";");
538
				}
539

    
540
				for (String tdwgCode : tdwgCodes){
541
					NamedArea area = TdwgAreaProvider.getAreaByTdwgAbbreviation(tdwgCode.trim());
542
			    	if (area == null){
543
			    		area = getOtherAreas(state, emCodeString, tdwgCodeString);
544
			    	}
545
			    	if (area != null){
546
			    		areas.add(area);
547
			    	}
548
				}
549
			 }
550

    
551
			 if (areas.size()== 0){
552
				 NamedArea area = getOtherAreas(state, emCodeString, tdwgCodeString);
553
				 if (area != null){
554
			         areas.add(area);
555
			   }
556
			 }
557
			 if (areas.size() == 0){
558
				 String areaId = rs.getString("AreaId");
559
				 logger.warn("No areas defined for occurrence " + occurrenceId + ". EMCode: " + CdmUtils.Nz(emCodeString).trim() + ". AreaId: " + areaId );
560
			 }
561
		}
562
		return areas;
563
	}
564

    
565
	@Override
566
	public Map<Object, Map<String, ? extends CdmBase>> getRelatedObjectsForPartition(ResultSet rs, BerlinModelImportState state) {
567
		String nameSpace;
568
		Class<?> cdmClass;
569
		Set<String> idSet;
570
		Map<Object, Map<String, ? extends CdmBase>> result = new HashMap<Object, Map<String, ? extends CdmBase>>();
571

    
572
		try{
573
			Set<String> taxonIdSet = new HashSet<String>();
574
			while (rs.next()){
575
				handleForeignKey(rs, taxonIdSet, "taxonId");
576
			}
577

    
578
			//taxon map
579
			nameSpace = BerlinModelTaxonImport.NAMESPACE;
580
			cdmClass = TaxonBase.class;
581
			idSet = taxonIdSet;
582
			Map<String, TaxonBase> objectMap = (Map<String, TaxonBase>)getCommonService().getSourcedObjectsByIdInSource(cdmClass, idSet, nameSpace);
583
			result.put(nameSpace, objectMap);
584

    
585
		} catch (SQLException e) {
586
			throw new RuntimeException(e);
587
		}
588
		return result;
589
	}
590

    
591

    
592

    
593
	/**
594
     * Tests if a distribution with the same tdwgArea and the same status already exists in the description.
595
     * If so the old distribution is returned
596
     * @param description
597
     * @param tdwgArea
598
     * @return false, if dupplicate exists. True otherwise.
599
     */
600
    private Distribution checkIsNoDuplicate(TaxonDescription description, Distribution distribution, Map<Integer, String> duplicateMap, Integer bmDistributionId){
601
    	for (DescriptionElementBase descElBase : description.getElements()){
602
    		if (descElBase.isInstanceOf(Distribution.class)){
603
    			Distribution oldDistr = HibernateProxyHelper.deproxy(descElBase, Distribution.class);
604
    			NamedArea oldArea = oldDistr.getArea();
605
    			if (oldArea != null && oldArea.equals(distribution.getArea())){
606
    				PresenceAbsenceTerm oldStatus = oldDistr.getStatus();
607
    				if (oldStatus != null && oldStatus.equals(distribution.getStatus())){
608
    					duplicateMap.put(bmDistributionId, oldDistr.getSources().iterator().next().getIdInSource());
609
    					return oldDistr;
610
    				}
611
    			}
612
    		}
613
    	}
614
    	return null;
615
    }
616

    
617
	/**
618
	 * Use same TaxonDescription if two records belong to the same taxon
619
	 * @param newTaxonId
620
	 * @param oldTaxonId
621
	 * @param oldDescription
622
	 * @param taxonMap
623
	 * @return
624
	 */
625
	private TaxonDescription getTaxonDescription(int newTaxonId, int oldTaxonId, TaxonDescription oldDescription, Map<String, TaxonBase<?>> taxonMap, int occurrenceId, Reference<?> sourceSec){
626
		TaxonDescription result = null;
627
		if (oldDescription == null || newTaxonId != oldTaxonId){
628
			TaxonBase<?> taxonBase = taxonMap.get(String.valueOf(newTaxonId));
629
			//TODO for testing
630
			//TaxonBase taxonBase = Taxon.NewInstance(BotanicalName.NewInstance(Rank.SPECIES()), null);
631
			Taxon taxon;
632
			if ( taxonBase instanceof Taxon ) {
633
				taxon = (Taxon) taxonBase;
634
			} else if (taxonBase != null) {
635
				logger.warn("TaxonBase for Occurrence " + occurrenceId + " was not of type Taxon but: " + taxonBase.getClass().getSimpleName());
636
				return null;
637
			} else {
638
				logger.warn("TaxonBase for Occurrence " + occurrenceId + " is null.");
639
				return null;
640
			}
641
			Set<TaxonDescription> descriptionSet= taxon.getDescriptions();
642
			if (descriptionSet.size() > 0) {
643
				result = descriptionSet.iterator().next();
644
			}else{
645
				result = TaxonDescription.NewInstance();
646
				result.setTitleCache(sourceSec.getTitleCache(), true);
647
				taxon.addDescription(result);
648
			}
649
		}else{
650
			result = oldDescription;
651
		}
652
		return result;
653
	}
654

    
655
	@Override
656
	protected boolean doCheck(BerlinModelImportState state){
657
		IOValidator<BerlinModelImportState> validator = new BerlinModelOccurrenceImportValidator();
658
		return validator.validate(state);
659
	}
660

    
661

    
662
	@Override
663
	protected boolean isIgnore(BerlinModelImportState state){
664
		if (! state.getConfig().isDoOccurrence()){
665
			return true;
666
		}else{
667
			if (!this.checkSqlServerColumnExists(state.getConfig().getSource(), "emOccurrence", "OccurrenceId")){
668
				logger.error("emOccurrence table or emOccurrenceId does not exist. Must ignore occurrence import");
669
				return true;
670
			}else{
671
				return false;
672
			}
673
		}
674
	}
675

    
676
}
(10-10/21)