Project

General

Profile

Download (26.4 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.OrderedTermVocabulary;
45
import eu.etaxonomy.cdm.model.common.OriginalSourceType;
46
import eu.etaxonomy.cdm.model.common.TermType;
47
import eu.etaxonomy.cdm.model.common.TermVocabulary;
48
import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
49
import eu.etaxonomy.cdm.model.description.Distribution;
50
import eu.etaxonomy.cdm.model.description.PresenceAbsenceTerm;
51
import eu.etaxonomy.cdm.model.description.TaxonDescription;
52
import eu.etaxonomy.cdm.model.location.NamedArea;
53
import eu.etaxonomy.cdm.model.location.NamedAreaLevel;
54
import eu.etaxonomy.cdm.model.location.NamedAreaType;
55
import eu.etaxonomy.cdm.model.reference.Reference;
56
import eu.etaxonomy.cdm.model.taxon.Taxon;
57
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
58
import eu.etaxonomy.cdm.strategy.exceptions.UnknownCdmTypeException;
59

    
60

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

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

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

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

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

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

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

    
109

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

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

    
131
		TransactionStatus txStatus = this.startTransaction();
132

    
133
		sourceReference = getSourceReference(sourceReference);
134

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

    
137
		MarkerType eurMarkerType = getMarkerType(state, BerlinModelTransformer.uuidEurArea, "eur", "eur Area", "eur", getEuroMedMarkerTypeVoc());
138
		MarkerType euroMedAreaMarkerType = getMarkerType(state, BerlinModelTransformer.uuidEurMedArea, "EuroMedArea", "EuroMedArea", "EuroMedArea", getEuroMedMarkerTypeVoc());
139
		ExtensionType isoCodeExtType = getExtensionType(state, BerlinModelTransformer.uuidIsoCode, "IsoCode", "IsoCode", "iso");
140
		ExtensionType tdwgCodeExtType = getExtensionType(state, BerlinModelTransformer.uuidTdwgAreaCode, "TDWG code", "TDWG Area code", "tdwg");
141
		ExtensionType mclCodeExtType = getExtensionType(state, BerlinModelTransformer.uuidMclCode, "MCL code", "MedCheckList code", "mcl");
142
		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);
143
		NamedAreaLevel areaLevelEm1 = getNamedAreaLevel(state, BerlinModelTransformer.uuidEuroMedAreaLevelFirst, "Euro+Med 1. area level", "Euro+Med 1. area level", "e+m 1.", null);
144
		NamedAreaLevel areaLevelEm2 = getNamedAreaLevel(state, BerlinModelTransformer.uuidEuroMedAreaLevelSecond, "Euro+Med 2. area level", "Euro+Med 2. area level", "Euro+Med 1. area level", null);
145

    
146

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

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

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

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

    
175
		markAreasAsHidden(state, euroMedAreas);
176

    
177
	    getVocabularyService().saveOrUpdate(euroMedAreas);
178

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

    
187
		return euroMedAreas;
188
	}
189

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

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

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

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

    
219
    }
220

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

    
224
        try {
225

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

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

    
249
    }
250

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

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

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

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

    
312

    
313

    
314
		if (isBlank(emCode)){
315
			emCode = unit;
316
		}
317

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

    
334

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

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

    
356
		//type
357
		area.setType(NamedAreaType.ADMINISTRATION_AREA());
358

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

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

    
383
		//save
384
		getTermService().saveOrUpdate(area);
385

    
386
		return area;
387
	}
388

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

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

    
408
		result.setUuid(BerlinModelTransformer.uuidVocEuroMedAreas);
409
		getVocabularyService().save(result);
410
		return result;
411
	}
412

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

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

    
420
		ResultSet rs = partitioner.getResultSet();
421

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

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

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

    
441
                Integer emStatusId = nullSafeInt(rs, "emOccurSumCatId");
442

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

    
454
					Reference sourceRef = state.getTransactionalSourceReference();
455

    
456
					List<NamedArea> areas = makeAreaList(state, rs,	occurrenceId);
457

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

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

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

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

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

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

    
535
			if (tdwgCodeString != null){
536

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

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

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

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

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

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

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

    
593

    
594

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

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

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

    
663

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

    
678
}
(10-10/21)